אקסס למתחילים: יצירת מערכת לניהול תורמים
-
פרק כ: הפקת קבלות: חלק א: אפיון, קשר של יחיד ליחיד ועוד קצת VBA
אני רוצה להוסיף למערכת שלנו יכולת הפקה של קבלות לתורמים.
אני מעוניין באפיון הבא:- לכל תרומה תהיה רק קבלה אחת ויחידה.
- לקבלות יהיה מספר רץ ייחודי.
- לקבלה יהיה תאריך הנפקה.
- אפשרות להוספת הודעת טקסט אישית על הקבלה.
לכאורה, הפתרון הפשוט הוא להוסיף עוד כמה שדות לטבלת התרומות:
ReceiptNumber
ReceiptDate
ReceiptMessage
ולמלא אותם בכל פעם שיוצרים קבלה.
למה לטבלת התרומות?
כי כל קבלה שייכת רק לתרומה אחת בלבד.אבל אם נחשוב על כך, לפתרון זה ישנם שני חסרונות גדולים:
- אני צריך לנהל בעצמי את המספר הרץ. וזה לא כל כך טריוויאלי. בכל הנפקת קבלה חדשה אצטרך לסרוק את כל טבלת התרומות, למצוא את הערך המקסימלי, להוסיף 1 ולהקצות אותו לקבלה החדשה. זה מסורבל.
במקרה שיש כמה משתמשים במערכת, זה אפילו מסוכן, כי יתכן ושניהם ינפיקו בו זמנית את אותו המספר לשתי קבלות שונות... - גם ניהול תאריך הנפקת הקבלה יהיה רק באחריותי, ולא על ידי המערכת, כי לא אוכל להקצות ערך ברירת מחדל לשדה, שהרי אם כן, הוא ייקבע ברגע שאצור תרומה חדשה, ומסתמא תאריך הנפקת הקבלה לא תמיד זהה לתאריך התשלום. בנוסף אני עלול לשכוח למלא את הנתון, מה שיגרום לי סיבוך מיותר עם מס הכנסה...
אבל אל דאגה, יש פתרון יעיל בהרבה.
נכון שלכאורה פרטי הקבלה שייכים באופן הגיוני לתרומה, אך בעצם, תרומות וקבלות הן שתי ישויות נפרדות, וראויות להיות נפרדות גם בנתונים.
אנחנו נפריד בין נתוני התרומות לבין נתוני הקבלות, וניצור ביניהן יחס של אחד לאחד.
יחס של אחד לאחד קובע כי לכל רשומה בטבלה א תיתכן אך ורק רשומה אחת קשורה בטבלה ב.
ניתן להמשיל זאת לפריסת הטבלה על ידי סכין לשתי טבלאות נפרדות: אחת לתרומות ואחת לקבלות.
באופן עקרוני תכנון טוב של בסיס נתונים רלציונאלי מושתת על הפרדה של ישויות בנתונים. להפרדת ישויות על ידי יחס אחד לאחד יש כמה יתרונות:
- צמצום בנעילת רשומות
כאשר משתמש עובד על רשומה מסויימת, אותה רשומה ננעלת עבור שאר המשתמשים. בהפרדת הנתונים לשתי טבלאות אנו מאפשרים עבודה על שתי הטבלאות במקביל ללא חשש. - חיסכון בשטח אחסון
לעתים אנו לא מעוניינים בשמירת כל הנתונים עבור כל הרשומות, אלא רק עבור חלקן.
הפרדת הנתונים תאפשר לנו לשמור את הנתונים רק עבור הרשומות שבחרנו.
במקרה שלנו זה לא רצוי, כי אנחנו כן רוצים ליצור קבלה עבור כל תרומה (יש כאן מישהו ממס הכנסה?) אבל ייתכנו מקרים אחרים שבהם זה שייך. - הקטנה בצריכת משאבים
הרבה מבסיסי הנתונים משתמשים במנגנון מטמון Cache עבור אחסון זמני של נתונים. גם בבחירת חלק מהעמודות (למשל על ידי שאילתת בחירה), לרוב ה-DB מייבא את כל השורה למטמון. הפרדת נתונים תקטין את המשאבים הנדרשים עבור כך.
במקרה שלנו זה ממש לא קריטי, אבל תארו לעצמכם טבלה עם 200 או 300 עמודות (וכן, יש דברים כאלו), מסתמא המערכת נדרשת רק לחלק מהעמודות ברוב הקריאות ל-DB. - יצירת טריגרים מבוססי טבלה מדוייקים יותר (מחוץ לתחום הדרכה זו)
חשוב לציין כי להפרדת נתונים על ידי יחס אחד לאחד יש גם חסרונות, בעיקר אם תמיד נצטרך לייבא את שתי הטבלאות על ידי JOIN. במקרה כזה עדיף למקם את כל הנתונים בטבלה אחת.
אז בואו נראה כיצד עושים זאת:
ניצור טבלה חדשה עבור הקבלות, עם השדות הבאים:
DonationID – מפתח ראשי, מסוג מספר שלם ארוך. ערך ברירת מחדל Null
ReceiptNumber – מספור אוטומטי
ReceiptDate – תאריך\שעה. ערך ברירת מחדל =Now()
ReceiptMessage – מסוג טקסט קצר.
נשמור את הטבלה בשם Receipt.שימו לב כי בשיטת עיצוב זו פתרנו בקלילות את שתי הבעיות שהעלנו לעיל: ניהול מספר רץ עבור הקבלה, וניהול תאריך ההנפקה, והעברנו את האחריות על כך למערכת בלבד. בכך חסכנו לעצמנו כאב ראש ושגיאות.
הגדרת יחסי הגומלין
נפתח את עורך יחסי הגומלין, ונייבא את טבלת הקבלות.
כעת נגרור את שדה ID מטבלת Donation אל השדה DonationID בטבלת הקבלות, ונבחר בחלון עריכת קשרי הגומלין: "אכוף שלמות הקשרים בין הטבלאות".
שימו לב שאקסס יצרה יחס של אחד לאחד בין הטבלאות:
מהיכן היא יודעת לעשות זאת?
אקסס מזהה כי יצרנו קשר גומלין בין שני שדות מפתח. מציאות זו תיתכן רק בקשר של אחד לאחד.
סיגרו את החלון ושימרו את השינויים.יצירת טופס להקלדת נתוני קבלה
כעת ניצור את הטופס עבור הקבלות, שוב באופן אוטומטי: נבחר את טבלת התרומות, ומהתפריט למעלה: יצירה > טופס. נעבור לתצוגת עיצוב ונערוך בטופס זה כמה שינויים: נסיר את שדה המפתח, ונשנה את גודל הכותרת, תיבות הטקסט ונקטין גם את הטופס:
כעת נבחר את תיבת הטקסט של ההודעה לתורם, ובמאפיינים תחת הלשונית "אחר" נשנה את המאפיין "התנהגות מקש Enter" ל: שורה חדשה בשדה:
ברירת המחדל של מקש Enter בטופס היא מעבר לשדה הבא, אולם בהודעה האישית לתורם, ייתכן ונרצה להכניס ירידות שורה. הגדרה זו קובעת כי אם נרצה להוסיף ירידת שורה בהודעה האישית, נוכל לעשות זאת על ידי מקש אנטר, ואקסס תכניס תו ירידת שורה בשדה, במקום לעבור לשדה הבא.
נסגור ונשמור את הטופס בשם: frmReceipt.
כעת נוסיף את הטופס כטופס משנה לטופס כרטיס התרומה: frmDonationCard, על ידי פתיחת הטופס של כרטיס התרומה וגרירת הטופס החדש לשם:
במאפיינים של פקד טופס המשנה, נעבור ללשונית "נתונים", ונשים לב כי אקסס קבעה את הקשר בין הטפסים לפי הקשר שיצרנו:
נעבור ללשונית "תבנית", ונגדיר את המאפיין עוגן אופקי ל-ימין, כדי שטופס המשנה יוצג בצד הנכון של טופס האב:
נסגור את טופס האב ונשמור את השינויים. לאחר מכן נפתח אותו שוב, ונכניס את ההודעה אישית עבור התרומה הראשונה:
שימו לב שאקסס הקצתה את מספר הקבלה ואת תאריך ההנפקה באופן אוטומטי:
סגרו את הטופס ופתחו את טבלת הקבלות, שימו לב שאקסס גם קבעה נכון את שדה המפתח, כך שיתאים לתרומה:
בדק בית
המערכת עובדת די טוב, אך יש עוד כמה שיפורים לבצע:-
אין אפשרות ליצור קבלה מבלי להכניס ערך כלשהו. ומה אם איננו מעוניינים להוסיף טקסט אישי לקבלה?
את בעיה זו נשאיר לכם לפתור בשיעורי הבית. -
בטופס המשנה, לא אמורה להיות יותר מקבלה אחת עבור כל תרומה, ולכן לחצני הניווט שם מיותרים. אם ננסה להכניס יותר מקבלה אחת עבור תרומה מסויימת, נקבל שגיאה.
בואו נראה:
פתחו שוב את טופס כרטיס התרומה, ובטופס המשנה של הקבלה, לחצו על לחצן הרשומה החדשה, והכניסו טקסט כלשהו בהודעה:
נסו לסגור את הטופס. אקסס לא תאפשר לשמור את הרשומה, ותציג הודעת שגיאה:
לחצו על אישור.
אקסס תציג את השאלה הבאה:
בחרו כן.
כתוצאה מהמהלך הזה, הנתונים שהכנסתם יאבדו. גם המספר הרץ של הקבלות יקפוץ על המספר 2, והקבלה הבאה תקבל את המספר 3, כי המספר 2 כבר "שרוף" במחיקת הרשומה השגויה.
פתרון לבעיה
כדי להימנע מלהיכנס בכלל למצב שכזה, נבצע כמה שינויים.
אנו מעוניינים לחסום אפשרות להוספת קבלה לתרומה שיש לה קבלה קיימת. לשם כך נשתמש במאפיין "אפשר תוספות" או באנגלית "AllowAdditions" של הטופס. כאשר מאפיין זה מכיל ערך True, ניתן להוסיף רשומות. וכאשר הוא מכיל את הערך False, אין אפשרות להוסיף רשומות.כיון שהרשות להוספת קבלה לתרומה נקבעת על ידי התרומה הנוכחית (אנו רוצים לאפשר זאת רק אם אין לה כבר קבלה), נשתמש בפונקציית VBA שנצמיד לארוע של התרומה הנוכחית בטופס האב.
פתחו את טופס האב frmDonationCard בתצוגת עיצוב, וצרו פונקציה עבור הארוע "בנוכחי":
הקלידו את הקוד הבא:Private Sub Form_Current() If Me.frmReceipt.Form.Recordset.RecordCount = 0 Then Me.frmReceipt.Form.AllowAdditions = True Else Me.frmReceipt.Form.AllowAdditions = False End If End Sub
הקוד הנ"ל בודק את מספר הרשומות בקבוצת הרשומות של טופס המשנה (שורה 2), ואם הוא שווה 0 (=אין קבלה), אז קובע את ערך המאפיין AllowAdditions בטופס המשנה ל-True, וכך מאפשר הוספת רשומה חדשה (שורה 3), אחרת, הוא קובע את המאפיין ל False, ובכך חוסם את האפשרות (שורה 5).
סגרו ושמרו.עדיין יש כאן פתח לשגיאות, כי כאשר ניצור תרומה חדשה, המאפיין AllowEditions בטופס המשנה יהיה על True, ונוכל להכניס עוד תרומה. עלינו לדאוג להעבירו למצב False לאחר ההוספה. לשם כך נשתמש בפונקציה נוספת שנצמיד כמובן לארוע "לאחר הוספה" של טופס המשנה.
פתחו את טופס המשנה frmReceipt בתצוגת עיצוב, וצרו פונקציה עבור הארוע "לאחר הוספה":
הקלידו את הקוד הבא:
Private Sub Form_AfterInsert() Me.AllowAdditions = False End Sub
חיזרו לטופס על ידי הקשה על Alt+F11, עיברו ללשונית תבנית, והסירו את לחצני הניווט מהטופס, הם מיותרים כעת:
תוספת: הכינוי Me
כדי לגשת לטופס הפתוח אנו משתמשים במילה השמורה Me. המילה Me היא כינוי למופע של מחלקת הטופס שהפעיל את האירוע.מה הפשט?
הטופס הוא בעצם סוג של תבנית. הוא דוגמא שממנה אנו יכולים ליצור כמה מופעים של אותו הטופס, בדיוק כמו תבנית צורה של עוגיה, שממנה ניתן ליצור כמה עוגיות זהות.
לדוגמא, במערכת ההפעלה ניתן לפתוח במקביל כמה מסמכים של וורד, בכל פתיחה של מסמך חדש, מערכת ההפעלה יוצרת מופע חדש של תוכנת וורד.
בשפת תכנות, לתבנית קוראים בשם מחלקה (או מודל). ולצורות שיוצרים ממנה קוראים מופעים.
כל מופע מכיל את כל הפונקציונאליות והמאפיינים של המחלקה שממנה נוצר.
אם נחשוב על כך, כל טופס יכול באופן עקרוני להיות פתוח בו זמנית כמה וכמה פעמים.
נתאר לעצמנו מצב דמיוני שבו הטופס פתוח ב-10 מופעים. כאשר נסגור מופע אחד, אותו מופע יפעיל את הארוע "סגירת טופס", אפילו שתשעת המופעים האחרים פתוחים. כיצד נדע מתוך הקוד, איזה מופע של הטופס נסגר?לשם כך שפת VBA מספקת לנו את המאפיין Me ככינוי שבאמצעותו ניגשים ישירות למופע הפעיל של הטופס שהריץ את הקוד.
או אם תרצו: אם אין אני לי – Me לי.שיעורי בית:
כדי להתחמק מן הבעיה הראשונה שהזכרנו לעיל, נכריח את המשתמש להכניס נתון כלשהו בקבלה: אמצעי השליחה.-
צרו טבלה חדשה בשם DeliveryMethod שתכיל שדה מזהה ID ושדה נוסף בשם Description.
טבלה זו תכיל את אפשרויות השליחה של הקבלה, כאשר 1 מציין שהקבלה תישלח בדואר רגיל, ו-2 מציין כי הקבלה תישלח בדואר אלקטרוני. -
הוסיפו שדה נוסף לטבלת הקבלות בשם DeliveryMethodID מטיפוס מספר ארוך. הערכים לשדה זה יילקחו מהטבלה בסעיף א, על ידי תיבה משולבת. קבעו את ערך ברירת המחדל של השדה ל-Null.
-
בטבלת הקבלות, הפכו את כל השדות לנדרשים, למעט השדה של ההודעה האישית.
-
הוסיפו פקד תיבה משולבת עבור השדה הנ"ל בטופס הקבלה.
-
פרק כא: הפקת קבלות: חלק ב: עיקרון ה-DRY, מחולל הדוחות
כדי שנוכל להדפיס את הקבלות שיצרנו, אנו צריכים ליצור דוח.
באופן עקרוני, דוח באקסס מאוד דומה לטופס:- הוא יכול להיות מאוגד לטבלה, או לא מאוגד
- הוא יכול להכיל את רוב הפקדים שיכולים להימצא בטופס
- יש לו מגוון של ארועים שניתן להצמיד אליהם קוד VBA
- הוא יכול להכיל דוחות משנה
היתרון הגדול ביצירת דוח הוא היכולת להציג נתונים בצורה נוחה להדפסה.
אז בואו וניצור את הדוח הראשון שלנו: דוח עבור קבלות לתורמים.
נחשוב:
אילו נתונים צריכים להופיע על הקבלה?
מסתמא נרצה את כל הנתונים שבטבלת הקבלות, אך חסרים שם הרבה פרטים, כמו סכום ותאריך התרומה, ושם התורם והכתובת שלו.למעשה, אין לנו שדה כתובת בטבלת התורמים עדיין, אז בואו ניצור אחד כזה:
כדי להציג את כל פרטי הקבלה, ניצור שאילתת צירוף.שלב א: יצירת שאילתת צירוף להצגת פרטי הקבלה
ניצור שאילתה חדשה, ונוסיף את שלושת הטבלאות: קבלות, תרומות, ותורמים, למשטח העבודה, אקסס תזהה את הצירוף בין הטבלאות לפי מה שהגדרנו ביחסי הגומלין:
נבחר להציג את השדות הבאים:
הממ... עדיין חסר לי את שדה שם התורם.
אני יכול להציג את שם המשפחה ואת השם הפרטי בנפרד, אבל אני רוצה כמובן להציג את שם התורם המלא.
לא בעיה!
אני יכול ליצור שדה מחושב FullName שמחבר את השם הפרטי ושם המשפחה של התורם.אבל רגע, זה נשמע לי מוכר...
יש לי כבר שאילתה שעושה זאת: qryDonor_FullName.במקום ליצור שוב שדה מחושב, בואו ונשתמש בה.
למה?עיקרון ה-DRY
לפני כעשרים שנה, פירסמו שני מתכנתים אמריקאים את העיקרון הבא בתכנון מערכות:
Don't Repeat Yourself (אל תחזור על עצמך) או בקיצור DRY. הנוסח הרשמי לעיקרון זה הוא:
לכל פיסת ידע צריך להיות ייצוג יחיד, חד משמעי וסמכותי במערכת.
במילים פשוטות, זה אומר שלא נשכפל שום חלק במערכת אלא אם כן הדבר הכרחי.עקרון זה נועד כדי להפחית כפילויות מיוצרות במערכת, ועל ידי כך ליצור מערכת קלה לתחזוקה, כי שינוי של גורם יחיד במערכת לא יאלץ שינויים נוספים בגורמים אחרים שאינם קשורים אליו לוגית.
ניקח לדוגמא את המקרה שלנו:
כרגע, שם התורם המלא מוצג לפי הסדר הבא: שם משפחה + רווח + שם התורם. נניח שבעוד שנה ירצה בעל הבית להציג את שמות התורמים המלאים בסדר הפוך, דהיינו במקום כהן אברהם – אברהם כהן וכו'.
אם הרכבת השם המלא של התורם מבוצעת רק במקום יחיד במערכת, דהיינו בשאילתה הנ"ל, כל שעלינו לעשות הוא לשנות את הגדרת השדה המחושב שם – והשינוי ישתקף בכל מקום במערכת.
אבל, אם בכל פעם יצרנו שוב את השדה המחושב מחדש – זה הופך לעבודת נמלים מייגעת...אז יופי, בואו ונוסיף גם את השאילתה למשטח העבודה, והופ – נראה שהפעם אקסס לא הייתה כל כך מבריקה, והחליטה לצרף את השדה ID מטבלת התרומות לשדה ID בשאילתה, כפי שמוצג בדרמטיות בתמונה הבאה:
מדוע זה קרה?
אקסס זיהתה את שם השדה ID הזהה בשתי מקורות הנתונים, והחליטה "לעזור לנו" על ידי יצירת הצירוף עבורנו. אבל זה כמובן לא נכון!אם היינו קוראים לשדה המפתח בכל טבלה בשם מלא, כפי שנהגנו במפתח הזר, למשל DonationID במקום ID בטבלת התרומות, או DonorID במקום ID בטבלת התורמים וכו', המנגנון של אקסס אכן היה עוזר לנו.
זו אכן סכמה נפוצה, ובאמת בתחילת דרכי כך נהגתי, אבל היא פחות מקובלת, ובקוד היא נעשית מסורבלת עוד יותר, כי ניגשים לשדה המזהה כך: Donor.DonorID במקום כך: Donor.ID.
לכן אני מעדיף לוותר על העזרה של אקסס כאן, וליצור ידנית את הצירוף, תמורת הרווח של קוד ושאילתות יותר קריאים.בואו נתקן את הצירוף:
נבחר את החץ ונמחק אותו על ידי הקשה על מקש Delete, ובמקום, נגרור את שדה ID מטבלת התורמים לשדה ID בשאילתת השם המלא, כך:
כעת נוסיף גם את השדה FullName לחגיגה:
נעבור לתצוגת גליון נתונים כדי לראות שהכל תקין. על הדרך, בואו נוסיף עוד הודעות אישיות לתרומות של כהן אברהם:
נשמור את השאילתה בשם: qryReceipt_Details (=פרטי קבלה)
כעת ניתן סוף סוף לעבור לשלב יצירת הדוח.שלב ב: יצירת דוח עבור הקבלה
בחרו מתפריט היצירה > עיצוב דוח:
אקסס תייצר עבורנו דוח ריק. שימו לב שהדוח מחולק לשלושה אזורים:
- כותרת עליונה בעמוד: חלק זה יודפס בראש כל עמוד חדש.
- פירוט: החלק העיקרי של הדוח.
- כותרת תחתונה בעמוד: חלק זה יודפס כמובן בתחתית כל עמוד.
ישנם עוד חלקים נוספים שאפשר לערוך בדוח, כפי שנראה אי"ה בהמשך.
כדי שהטופס יציג לנו את נתוני הקבלות, צריך לאגד אותו לשאילתה שיצרנו. לשם כך נבחר בפקד הדוח, על ידי לחיצה על הפינה השמאלית העליונה (בדומה לפקד טופס, זהו הפקד שנבחר אוטומטית בתצוגת עיצוב):
כעת נלחץ על מקש F4 כדי להציג את חלונית המאפיינים, ניגש לכרטיסית הנתונים, ובמאפיין מקור רשומה נבחר את שאילתת פרטי הקבלות qryReceipt_Details:
נבחר מהתפריט למעלה את האפשרות: הוסף שדות קיימים כדי להציג את השדות שנמצאים בטבלה:
נבחר את כל השדות ונגרור אותם לתוך חלק הפירוט של הטופס:
נעצב את הדוח כיד הדמיון הטובה עלינו:
כשסיימנו, נבחר מתפריט העיצוב את התצוגה: הצג לפני הדפסה:
כדי לראות את התוצאה:
שימו לב כי בתצוגה זו מוצגת בכל עמוד קבלה אחת בלבד. כדי לעבור לעמוד הבא, נשתמש בסרגל הניווט למטה:
נשמור את הדוח בשם: rptReciept_Details.
זהו לבינתיים, מקווה שנהנתם!
בפרק הבא אי"ה נלמד על טפסים רציפים.
אני משאיר כמה שיעורי בית, בעיקר בעיצוב (מהקל למאתגר):
- הסירו את המסגרות מסביב לתיבות הטקסט בדוח.
- הוסיפו בכותרת התחתונה של העמוד את הכיתוב: "הודפס על ידי מערכת לניהול תורמים גירסא 0.01"
- הוסיפו את שעת ההדפסה המדוייקת בכותרת העליונה.
- הצמידו את ראשי התיבות נ"י לשם התורם כך שיופיעו מיד לאחריו בצורה יפה בלי רווח גדול.
- הסירו את השעה מתאריך החשבונית ומתאריך התרומה.
בהצלחה!
-
פרק כב: עושים סדר: חלק א: אפיון מדיוק של המערכת, טפסים רציפים
המערכת שלנו בינתיים מסוגלת לכמה דברים, אבל לא מאורגנת בכלל.
נו, אז הגיע הזמן לעשות קצת סדר.הזכרתי כבר שבמערכת אמיתית, שלב התכנון הוא הראשון, עוד בטרם ניגשים בכלל למחשב. פשוט לוקחים דף ועט ומציירים על הנייר. אין צורך לסרטט את הכל במחשב, לפחות לא בהתחלה. זה סתם מסרבל.
אז לאחר שישבתי וחשבתי, הגעתי לאפיון המופיע בסרטוט הבא:
המלבנים מייצגים טפסים והסנפירים למטה מייצגים את הפונקציונאליות שאני מבקש בטפסים אלו.
את הדף הזה אני אתלה מול עיני בזמן הפיתוח, כך תהיה לי דרך סלולה ללכת בה, והכי חשוב: אני אדע ברור מתי כבר סיימתי. מעתה נשתדל להיצמד במדריך לאפיון הנ"ל.אגב, את התרשים הנ"ל יצרתי בעזרת כלי נפלא בשם Draw.io. זהו כלי מדהים ליצירת תרשימי זרימה, סרטוטים ועוד, קל ונוח, עם אפשרות לעברית מלאה, וקיים בגרסא מקוונת או להורדה, והוא חינמי לחלוטין!
למי שעוקב אחרי ההדרכה, הנה הקובץ של הסרטוטתוכלו להכניס בו שינויים כרצונכם.
סדר הפיתוח הנכון
אני מאוד ממליץ להתחיל לבנות את המערכת מלמטה למעלה, כלומר קודם כל לבנות את הרבדים הנמוכים של המערכת, ומשם לטפס למעלה.נתחיל ברגל ימין עם צד ימין של המשפחות.
ציינתי שיש שם טופס שמציג את רשימת המשפחות.
מה אני רוצה שיראו בו?
כמובן את פרטי המשפחה, ולפי האפיון, גם את סיכום התרומות למשפחה.לשם כך ניצור שאילתת עזר, שתקבץ את הנתונים של התרומות לפי משפחה.
שלב א: יצירת שאילתת סיכום תרומות למשפחה
נפתח שאילתה חדשה, נהפוך לשאילתת קיבוץ, נייבא את טבלת התרומות, ונגדיר את השדות לתצוגה באופן הבא:
נשמור את השאילתה בשם qryFamily_DonationSummary
שלב ב: יצירת השאילתת הבסיס לרשימת המשפחות:
השאילתה הזו תושתת על צירוף של שתי השאילתות שיצרנו:
- שאילתה א: שמות המשפחה המלאים: qryFamily_FullName
- שאילתה ב: סיכום התרומות למשפחה: qryFamily_DonationSummary.
נתבונן ונשים לב, שעלינו לצרף אותן בצירוף חיצוני, כי למרות שכל המשפחות מופיעות בשאילתה א (שמות המשפחה המלאים), שהרי היא מבוססת על טבלת המשפחות, יתכן ויש משפחה שלא תופיע בשאילתה ב (סיכום התרומות למשפחה), מפני ששאילתה ב מבוססת על טבלת התרומות, ותכיל רק משפחות שכבר יועדו להן תרומות.
להלן מבנה השאילתה:
נשמור את השאילתה בשם: qryFamily_FullName_DonationSummary
כעת הכל מוכן ליצירת טופס רשימת המשפחות.תצוגת גליון נתונים .VS תצוגת טפסים רציפים
לאקסס יש שתי אפשרויות להציג רשומות מרובות בטופס יחיד:
- תצוגת גליון נתונים
- תצוגת טפסים רציפים
תצוגת גליון נתונים מציגה את הנתונים בטבלה פשוטה, בדומה לגליון אקסל. ולמרות שלעתים זה מספק, לרוב נרצה להשתמש בתצוגת טפסים רציפים, שמאפשרת גמישות רבה יותר.
בואו נראה:
נסמן את השאילתה שיצרנו, ונבחר מתפריט העיצוב: "טפסים נוספים" > "פריטים מרובים". אקסס תיצור טופס ותפתח אותו בתצוגת פריסה:
נעבור לתצוגת עיצוב, ונראה כי באמת הטופס מחולק לשלושה חלקים (בדומה לדוח בפרק שעבר):
- כותרת עליונה: משמשת בעיקר להצגת כותרות העמודות
- פירוט: מציג את הרשומה הנוכחית
- כותרת תחתונה: בה נשתמש להצגת סיכומי העמודות
הערה: למרות שחלק הפירוט מראה שורה אחת בלבד, כשנעבור לתצוגת טופס יוצגו בפירוט כל הרשומות. כל עיצוב שנבצע בחלק זה - ישפיע על כל שורה ושורה בתצוגת הטופס.
שלב ג: הוספת סיכום עמודות
בואו ונרחיב את החלק של הכותרת התחתונה של הטופס, על ידי גרירה מטה של הגבול:
כעת נוסיף שם שלוש תיבות טקסט לא מאוגדות, ותווית אחת עם הכיתוב "סיכום", כפי שמופיע בתמונה הבאה:
בכל אחת מתיבות טקסט אני רוצה שיופיע סיכום של כל העמודה שמעליה.
אבל לפני כן אנחנו חייבים לטפל בדבר חשוב.
מי אני ומה שמי?
לאקסס יש הרגל מגונה לתת לפקד מאוגד בטופס שם זהה לשם השדה בטבלה שאליו הוא מאוגד. למשל, תיבת הטקסט של שם המשפחה קיבלה את השם FullFamilyName, שזהה בדיוק לשם השדה FullFamilyName בטבלה שעליה מבוסס הטופס.
בכך אקסס גורמת לי חוסר ודאות כמפתח המערכת, האם FullFamilyName מתייחס לתיבת הטקסט או לשדה בטבלה? וחוסר ודאות - זה מתכון מצוין לבעיות....
לשם כך אני תמיד רגיל ביצירת טופס להפריד בין השניים, ולשנות את שם הפקד המאוגד לשם שונה משם השדה, על ידי הוספת קידומת מיוחדת לשם הפקד, לפי סוג הפקד.
לדוגמא:
- לתיבת טקסט אני אוסיף קידומת "txt"
- לתווית אני אוסיף קידומת "lbl"
- לתיבה משולבת אני אוסיף קידומת "cbo" וכו'
זוהי אמנם עבודה מעט מרגיזה, אבל כמו תמיד, היא משתלמת מאוד כשמתחילים להוסיף קוד בטופס.
לשם כך אני אשנה את שמות ארבע תיבות הטקסט המאוגדות בחלק הפירוט של הטופס, לפי הטבלה הבאה:
שם קודם שם חדש ID txtID FullFamilyName txtFullFamilyName TotalDonationCount txtTotalDonationCount TotalDonationAmount txtTotalDonationAmount על ידי כניסה למאפיינים של הפקד (בלשונית "אחר" או בלשונית "הכל") והוספת הקידומת "txt" לשם הפקד, לדוגמא:
הערה: יש הנוהגים להוסיף סיומת לשם הפקד (במקום קידומת) דהינו FullFamilyNameTextBox וכו', זה בהחלט אפשרי, אך לטעמי מסורבל יותר. והבוחר יבחר.
למעשה, היינו צריכים להנהיג הנהגה זו כבר מתחילת המדריך, מהטופס הראשון שעשינו, אך נמנעתי מלהזכיר זאת עד עתה, פן ינחם העם בראותם מלחמה...
על כל פנים, מעתה זו תהיה הנחת היסוד: מכאן והלאה לבצע את שינוי השם לכל שדה מאוגד בטופס.
את הטיפול בכל הטפסים הקודמים נשאיר לשיעורי הבית (מסכן @בערל...)סיימתם?
כעת נוכל לבנות את הנוסחא לסיכום העמודות, נתחיל עם עמודת שמות המשפחה, שם אנו רוצים להציג את מספר המשפחות בטופס. נבחר את תיבת הטקסט שבכותרת התחתונה של העמודה של שמות המשפחה:
במאפייני הפקד, בלשונית "נתונים" בחרו את המאפיין "מקור הפקד" ולחצו על שלושת הנקודות כדי לפתוח את בונה הביטויים:
הקלידו בבונה את הנוסחה הבאה:Count(ID)
עברו לתיבת הטקסט בתחתית העמודה השנייה, ושם תכניסו באותו אופן את הנוסחה:
Sum(TotalDonationCount)
ובתיבה האחרונה את הנוסחה:
Sum(TotalDonationAmount)
שנו גם את תבנית העיצוב של תיבה זו ל"מטבע":
שלב ד: קצת קוסמטיקה:
כבר הזכרתי שאני משתדל להימנע מלמרוח את הזמן על עיצובים, אך לפעמים זה פשוט נותן הרגשה טובה ונעימה יותר להמשיך בפיתוח, אז אני חורג מהרגלי פה ושם. עם זאת, אני משתדל לא להתפתות להתחיל לשנות את עיצוב כל הטפסים במערכת בשלב זה, כדי שלא להיתקע על קו עיצוב מסויים ולהיות משועבד לו מכאן ואילך, בפרט כשלרוב מחליטים לשנות אותו בהמשך...
בחרו את כל הפקדים בכותרת התחתונה, ושנו את סגנון הרקע לשקוף, ואת צבע הכתב לשחור, עם סגנון מודגש:
לחצו על הפס האפור שעליו כתוב "כותרת תחתונה בטופס", והגדירו את צבע הרקע לתכלת:
שנו גם הכותרת הראשית ואת תוויות הכותרת של העמודות לעברית.
כעת עברו לתצוגת טופס, ושימו לב כי מופיעים סיכומים של העמודות בתחתית הטופס:
שלב ה: הוספת לחצנים לפונקציונאליות של הטופס
כיוון שבא לידינו עיצוב טופס זה, נוסיף לו עוד שלושה לחצנים, אחד בכותרת העליונה להוספת משפחה למערכת, ושנים בחלק הפירוט: אחד לפתיחת כרטיס המשפחה ואחד למחיקת המשפחה מהמערכת (את הפונקציונאליות שלהם נממש בהמשך)
נחזור לתצוגת עיצוב.
בתפריט העיצוב, נבחר את לחצן הפקודה מסרגל הפקדים:
נקליק בכותרת העליונה של הטופס במקום שבו אנו רוצים ליצור את הלחצן:
אקסס תיצור לחצן עם השם "פקודהXX" ותפתח את אשף לחצני הפקודות, שאליו נסרב להתייחס ופשוט נסגור אותו בנימוס, על ידי לחיצה על "ביטול":
האשף הנ"ל מציע ליצור עבורנו פקודות מאקרו לבניית הפונקציונאליות של הלחצנים, אך אנו נכתוב זאת בעצמנו על ידי קוד VBA בהמשך.
נשנה את שם הלחצן ל cmdNewFamily ואת הכיתוב עליו ל"משפחה חדשה":
נוסיף עוד שני לחצנים בחלק הפירוט של הטופס, אחד מימין בראש השורה, בשם cmdOpenFamilyCard ועם הכיתוב "הצג", ואחד משמאל בסוף השורה בשם cmdDeleteFamily עם הכיתוב "מחק":
כעת אין צורך בבוררי הרשומות ולחצני הניווט של הטופס, אז בואו נסיר גם אותם (בחרו קודם בפקד הטופס, בפינה השמאלית העליונה, זוכרים?)
כשנסיים, נשמור את הטופס בשם frmFamilyList.
והנה הטופס המוכן, אחרי עוד כמה קנעטשים:
בפרק הבא ניצור גם את טופס כרטיס המשפחה, ונוסיף פונקציונאליות ללחצנים שיצרנו היום.
-
פרק כג: עושים סדר: חלק ב: שדרוגים שונים, פונקציונאליות לחצני רשומה, ורגע למחשבה.
תזכורת:
בפרק הבא ניצור גם את טופס כרטיס המשפחה, ונוסיף פונקציונאליות ללחצנים שיצרנו היום.
גילוי נאות: בפרק זה עדיין לא נוסיף פונקציונאליות ללחצנים הנ"ל, אלא ללחצנים אחרים שניצור.
שלב א: שדרוג כרטיס המשפחה
בואו ניזכר, כי בפרק יד יצרנו כבר טופס בשם frmFamily המציג את פרטי המשפחה, אם כי הוא לא מעורר תיאבון במיוחד:
שינוי השם
ראשית נשנה את שמו לשם חדש: frmFamilyCard (כרטיס משפחה), שמתאים יותר לתכנית שלנו מהפרק הקודם:
הצגת מידע על התרומות המשוייכות
מלבד תצוגה של כל פרטי המשפחה, אני רוצה להציג בטופס זה גם סיכום קצר על התרומות שמשוייכות למשפחה זו.
כבסיס, אפשר להשתמש בשאילתת סיכום התרומות למשפחה שיצרנו בעבר: qryFamily_DonationSummary, אבל היא לא מספיק מפורטת, כי היא מציגה רק את סכום כל התרומות למשפחה, מבלי להתייחס לסטטוס התרומות.לדוגמא, עבור משפחת אשרי, מופיע שקיימות 2 תרומות על סך כולל 300 ₪:
אבל אין שום מידע על סטטוס התרומות, מה בוצע ומה לא.
לצורך המחשת העניין, נפתח את טבלת התרומות ונשנה את הסטטוס של התרומה הראשונה ל-בוצעה:
כעת למשפחת אשרי יש 100 ₪ שבוצעו ו-200 ₪ שממתינים לביצוע, אך שאילתת הסיכום הנ"ל לא מציגה שום מידע על השינוי שעשינו כעת:
שלב ב: שדרוג שאילתת סיכום התרומות
בואו נשדרג את שאילתת הסיכום, כך שתציג עוד ארבע עמודות חדשות:- AwaitingDonationCount מספר התרומות הממתינות לביצוע (=המיועדות)
- AwaitingDonationSum סכום התרומות הממתינות לביצוע (=המיועדות)
- DoneDonationCount מספר התרומות שבוצעו בפועל
- DoneDonationSum סכום התרומות שבוצעו בפועל
נתחיל ע"י פתיחת השאילתה בתצוגת עיצוב, וניצור שדה חדש בשם AwaitingDonationCount:
אבל מה תהיה הנוסחה שבה נשתמש?
יש כאן קושי מסויים, כי לחישוב השדה הזה אי אפשר להשתמש בפונקצית Count רגילה, מפני שאז נקבל את מספר כל הרשומות, ואנו מעוניינים לקבל רק את מספר התרומות שמיועדות אך לא בוצעו עדיין, דהיינו עם סטטוס=2.הפתרון הוא ליצור שדה עם ביטוי מחושב. נפתח את הבונה:
ונרשום את הנוסחא הבאה:
AwaitingDonationCount: Sum(IIf([StatusID]=2,1,0))
הסבר: נוסחא זו מחשבת סכום לפי תנאי IIF: עבור כל רשומה, אם StatusID=2 (התרומה מיועדת), מוסיפים לסכום את הערך 1, אחרת – מוסיפים 0.
נסגור את הבונה, ונשנה את המאפיין "סך הכל" מ-"קבץ לפי" ל-"Expression", כדי להורות לשאילתה שכאן מדובר בביטוי מחושב ולא בשדה רגיל:
נעבור לתצוגת גליון נתונים ונראה כי הערך המופיע עבור משפחת אשרי הוא 1, דהיינו שיש לה תרומה אחת משוייכת:
יפה. כעת ניצור את השדה השני: סכום התרומות המשוייכות - בצורה דומה:
נוסיף שדה חדש בשם AwaitingDonationSum, אך הפעם במקום להוסיף לסכום המחושב את הערך 1, נוסיף את סכום התרומה הנוכחית ברשומה:AwaitingDonationSum: Sum(IIf([StatusID]=2,[Amount],0))
ושוב, נשנה את סוג השדה ל-Expression.
כעת מוצג גם הסכום של התרומות המיועדות:
באופן דומה נוסיף את שתי העמודות הנותרות, עם הנוסחאות הבאות:
מספר התרומות שבוצעו בפועל:DoneDonationCount: Sum(IIf([StatusID]=3,1,0))
סכום התרומות שבוצעו בפועל:DoneDonationSum: Sum(IIf([StatusID]=3,[Amount],0))
הערה: למרות שאפשרי (ואפילו יותר יעיל), לחשב את שתי השדות האחרונים בלי להשתמש בעוד פונקציית סכום, אלא פשוט על ידי ההפרש בין שתי השדות הקודמים, דהיינו:
DoneDonationCount: TotalDonationCount - AwaitingDonationCount
לא כדאי לנו לעשות כן, כי אם נחליט אי פעם להוסיף למערכת ערך סטטוס תרומה חדש, למשל: "בוטלה" (כשהתרומה הוקלדה בטעות, או שהבנק לא אישר את ההעברה), השדה המחושב יתעלם מסטטוס זה, ועלול להציג ערך שגוי.והנה התוצאה הסופית:
שלב ג: יצירת טופס משנה לתרומות
כעת ניצור טופס המציג את השדות, נתחיל כמו בעבר על ידי בחירת השאילתא ויצירת טופס אוטומטי:
ונבצע את השינויים הבאים:
בתיבות הטקסט: הוספת קידומת "txt", הסרת הגבול, הקטנת הרוחב ל-3 ס"מ.
בטופס: מחיקת תיבת הטקסט והתווית של משפחת היעד, הסרת בוררי הרשומות, הסרת לחצני הניווט, שינוי הכותרת, הקטנת הרוחב ל-8 ס"מ.התוצאה:
שמרו את הטופס בשם: frmFamily_DonationSummary.
נוסיף אותו כטופס משנה לכרטיס המשפחה, על ידי גרירה:
נעבור למאפייני פקד טופס המשנה, ונראה שאקסס לא ביצעה קישור בין נתוני טופס המשנה לטופס האב:
מדוע המאפיינים ריקים?
כשהטפסים מבוססים על טבלאות, ויש בין הטבלאות קשרי גומלין, אקסס מזהה את השדה המקשר ומגדירה את הקישור אוטומטית. אך כאן טופס המשנה מבוסס על שאילתה ולא על טבלה, ולכן לא זכינו לפינוק הזה.נו טוב, נעשה זאת בעצמנו, אבל אל דאגה, אקסס עוזרת לנו גם כאן, ומספקת מנגנון פשוט לקישור בין הטפסים.
נבחר את אחד המאפיינים קישור שדות אב או קישור שדות צאצא, ונלחץ על שלש הנקודות:
ייפתח החלון הבא:
הופה!
אקסס ניסתה לנחש את השדות המקושרים ו... הצליחה!
יתרה מכך, אקסס מתארת עבורנו את התוצאה שתתקבל מקישור זה:
נשמע טוב.
לנו נשארה המלאכה המפרכת ללחוץ על אישור... ואקסס תעדכן את המאפיינים:
נסיים את העבודה על הטופס הזה:
- נשנה את העוגן האופקי של פקד טופס המשנה ל: ימין, כך שיוצג בצמוד לפרטי המשפחה:
- נסיר את השדה המזהה ID.
- נעביר את תיבת הטקסט של CreatedOn לראש, ונשנה את המאפיין "נעול" ל-כן, והמאפיין "אפשר" ל-לא. כך נמנע מהמשתמש לבצע בה שינוי בטעות. אני גם אוהב להסיר לגמרי את הגבול מתיבות טקסט לקריאה בלבד, ולכן אעשה גם את זה.
- נשנה את הכיתוב בתוויות.
- נוסיף עוד שני לחצנים בכותרת, אחד בשם cmdNew לפתיחת כרטיס חדש, ואחד בשם cmdDelete למחיקת הכרטיס הנוכחי.
הנה התוצאה:
נעבור למשפחת אשרי ונוודא שטופס המשנה מתעדכן נכון כשעוברים ממשפחה למשפחה, ומציג את פרטי התרומות הנכונים:
נפלא!שלב ד: הוספת פונקציונאליות בלחצני כרטיס המשפחה
נבחר את לחצן יצירת כרטיס חדש cmdNew שיצרנו הרגע, ובמאפיינים בלשונית "אירוע", נבחר את האירוע: "בעת לחיצה", ונבחר את האפשרות "פרוצדורת אירוע":
נלחץ על שלושת הנקודות
…
אקסס תפתח את עורך הקוד, ותיצור שלד לפונקציית האירוע.שימו לב לשם הפונקציה: הוא מתחיל בשם הפקד cmdNew, ומסתיים בסיומת Click כסימן שהפונקציה משוייכת לארוע הלחיצה של הפקד.
נרשום את הקוד הבא:
Private Sub cmdNew_Click() DoCmd.GoToRecord , , acNewRec End Sub
הסבר הקוד:
בשפת VBA קיימים אובייקטים שונים.אובייקט הוא מושג בסיסי במדעי המחשב המתאר משתנה, פונקציה, מבנה נתונים או שילוב של הנ"ל.
אחד האובייקטים הנכבדים באקסס הוא DoCmd שמאגד בתוכו פונקציות רבות ומגוונות, כגון שליטה על חלונות וטפסים.
אחת מהפונקציות שהוא מכיל היא: GoToRecord שתפקידה, כמובן, לבצע מעבר בין רשומות.
ניתן לספק לה 4 פרמטרים, וכולם אופציונאליים.אנחנו דילגנו על שני הפרמטרים הראשונים על ידי ציון של פסיק, וסיפקנו רק את הפרמטר השלישי: acNewRec שפירושו "רשומה חדשה".
נחזור לאקסס על ידי Alt+F11, נעבור לתצוגת טופס, ונבדוק שלחיצה על הלחצן מעבירה אותנו לרשומה חדשה.
פשוט וקל!כעת ללחצן המחיקה
נחזור לתצוגת עיצוב, נבחר כעת את לחצן המחיקה, וניצור פונקציית אירוע גם עבור ארוע הלחיצה שלו:
הפעם נרשום את הקוד הבא:
Private Sub cmdDelete_Click() DoCmd.RunCommand acCmdDeleteRecord End Sub
הסבר: כאן אנו קוראים לפונקציה אחרת (באובייקט DoCmd) ששמה RunCommand, ומספקים לה פרמטר אחד: acCmdDeleteRecord, שפירושו: מחיקת הרשומה הנוכחית.
בואו נבדוק את הלחצן. נחזור לאקסס Alt+F11, נעבור לתצוגת טופס וננסה למחוק את משפחת ראובני...
אופס! אקסס תציג את הודעת השגיאה הבאה:
מה קרה? שימו לב ללשון ההודעה.
בעצם הכל תקין. אקסס לא מאפשרת לנו למחוק את הרשומה, ויש לכך סיבה טובה מאוד! אנו מנסים בעצם למחוק את הרשומה של משפחת ראובני מהטבלה Family, אך ניזכר כי הטבלה Family מקושרת בקשר גומלין לטבלת הזוגות Family_Donor, וזו מכילה רשומות השייכות למשפחת ראובני (כי ישנם תורמים המשוייכים למשפחה זו).
כיון שבהגדרת קשרי הגומלין, הגדרנו לאכוף את שלימות קשרי הגומלין בין הטבלאות, אם נמחק את משפחת ראובני רק מטבלת המשפחות, נהפוך את כל הרשומות של משפחת ראובני בטבלה Family_Donor לרשומות יתומות, כי אין להם שדה אב מתאים בטבלת Family. בסיס הנתונים יכיל נתונים לא שלמים.
אקסס דואגת שלא נגיע לידי כך, וזה דבר טוב.
אז מה עושים?
מחיקות הירארכיות
כדי לאפשר מחיקה של רשומה בטבלת המשפחות, אנו חייבים להורות בפירוש לאקסס למחוק גם את כל הרשומות הקשורות אליה בשאר הטבלאות, בהתאם להירארכיית הקשרים. לשם כך נערוך את קשרי הגומלין בין הטבלאות.נפתח את עורך קשרי הגומלין ונקליק פעמיים על החץ המקשר בין הטבלאות Family ו-Family_Donor:
ייפתח חלון עורך קשרי הגומלין, ונסמן ב-V את האפשרות: מחק רשומות קשורות זו לזו בהתאם להירארכיית הקשרים:
נלחץ על אישור.
זהו.
כעת ברגע שנמחק משפחה, אם יש לה תורמים משוייכים, אקסס פשוט תמחק אוטומטית את הרשומות המתאימות גם בטבלה Family_Donor.רגע, חושבים!
שימו לב כי הטבלה Family מקושרת בקשרי גומלין גם לטבלת התרומות Donation, וגם שם בחרנו לאכוף את שלמות הקשרים בין הטבלאות.
לכאורה זה אומר שפתרנו רק חצי בעיה, כי אם תהיה למשפחה גם תרומה משוייכת – לא נוכל למחוק אותה.מה הבעיה, אפשר להגדיר מחדש גם את קשר הגומלין הזה, וכאשר נמחק משפחה - לאפשר לאקסס למחוק את התרומות המשוייכות אליה, לא?
אז זהו, שממש לא.
חישבו, האם באמת כדאי לנו לאפשר מחיקה של נתוני תרומות? ומה אם נרצה להוציא דו"ח על כל התרומות שעברו בעמותה שלנו? ואם נצטרך להגיש דוח למס הכנסה?!לכן - לא ניגע בקשר הגומלין הזה. ואם יש למשפחה תרומה משוייכת - לא נאפשר מחיקה שלה בכלל.
מכאן עולה המסקנה הבאה:
שימוש במחיקות הירארכיות הוא מנגנון מסוכן, ומצריך מחשבה מקדימה. למעשה ישנם מתכנתים הנמנעים מלאפשר זאת על ידי קשרי הגומלין, ומעדיפים להשאיר את האחריות בידיים שלהם. כאשר הדבר נצרך, כגון הכא - הם מבצעים מחיקה של הרשומות בטבלאות הקשורות, על ידי קוד, ורק לאחר שבע בדיקות שאין כאן טעות.
ומדוע אפשרנו זאת במקרה של התורמים המשוייכים?
מפני שטבלת הזוגות Family_Donor בסך הכל מציינת קשר גומלין של רבים לרבים, ומחיקת רשומה ממנה אינה משפיעה על טבלת נתוני התורמים בשום צורה, ובוודאי שאינה מוחקת שום תורם, לכן היא בטוחה.המשך יבוא אי"ה...
-
פרק כד: עושים סדר: חלק ג: תפריטים ופקדי ניווט, פונקציונאליות ברשימת המשפחות
שלום לכולם! מקווה שנהנתם מהחופש הגדול...
היום הגענו לחלק די קל ומהנה (יחסית...) והוא בניית התפריטים.
אחד הדברים שחסרים מאוד במערכת שלנו הוא התפריט הראשי, (או הדשבורד), שדרכו ננווט את דרכנו בין הטפסים השונים, במקום לבחור בכל פעם את הטופס מהפנל מימין.
אני רוצה ליצור משהו כזה:
למרבה המזל, לאקסס יש מנגנון מובנה לניהול הניווט בין טפסים, בשם פקד הניווט.
אז בואו ניצור משהו כזה.שלב א: יצירת טופס תפריט המשפחות
נפתח טופס חדש ריק, על ידי יצירה > עיצוב טופס.
נבחר מתפריט העיצוב את פקד הניווט:
ואז פשוט נקליק בתוך הטופס קרוב לפינה הימנית העליונה:
אקסס תיצור עבורנו פקד ניווט:
לפקד הניווט שני חלקים:
- החלק העליון הוא פקד הניווט עצמו, זהו בעצם התפריט, שמכיל את הלחצנים לבחירת הטפסים לתצוגה.
- החלק התחתון הוא פקד טופס המשנה לניווט, ותפקידו להציג בתוכו את הטפסים שבחרנו מן התפריט.
הערה חשובה: כברירת מחדל, שם פקד טופס המשנה הוא "NavigationSubform". למרות שאפשר לשנות את שמו לכל שם שנרצה, לעת עתה נשאיר אותו עם שם זה. פרט זה יתגלה כחשוב בהמשך הדרך.
נוסיף לחצן לפקד הניווט על ידי לחיצה על המקום שמסומן [הוסף חדש], ונרשום בתוכו "רשימת משפחות". אקסס יצרה עבורנו לחצן חדש:
נגדיל את הלחצן כך שיציג את כל הכיתוב:
נוסיף עוד לחצן עם הכיתוב "כרטיס משפחה":
כעת נותר לנו להגדיר איזה טופס ייפתח על ידי כל לחצן.
ניכנס למאפיינים של הלחצן הראשון (רשימת המשפחות), ובלשונית הנתונים נבחר את המאפיין "שם יעד ניווט", ונבחר מתיבת הרשימה המשולבת את טופס רשימת המשפחות frmFamilyList:
באופן דומה, גם בלחצן השני, נבחר את שם יעד הניווט להיות טופס כרטיס המשפחה frmFamilyCard:
לסיום, נסיר מן הטופס את הפקדים המיותרים: בוררי הרשומות, לחצני ניווט ופסי הגלילה: (להלן: "שלשת המעצבנים")
ונצמצם את השוליים המיותרים מסביב לפקד הניווט (מסומנים בכתום):
נסגור את הטופס ונשמור אותו בשם navFamilies.
כעת פתחו את הטופס שיצרנו ובידקו את לחצני הניווט:
שלב ב: יצירת טופס התפריט הראשי
בדומה לשלב הקודם, נפתח טופס חדש ריק, על ידי יצירה > עיצוב טופס, ונוסיף אליו פקד ניווט, ונוסיף שלושה לחצנים כפי שמופיע בתמונה הבאה:
כעת נהפוך את הכיוון של התפריט לאנכי.
לשם כך נבחר את פקד הניווט כולו (זוכרים? החלק העליון) על ידי הקלקה במקום הריק (לא על לחצן):
שימו לב שכל פקד הניווט מסומן כעת.
מתוך המאפיינים בלשונית התבנית נגדיר את המאפיין "מרחב" ל-"אנכי". שימו לב לשינוי בפריסת הלחצנים, כעת הם מופיעים מלמעלה למטה:
אך עדיין פקד הניווט מופיע בצמוד לחלק העליון של טופס המשנה, ולא מצידו הימני כמו בתכנון.
אל דאגה, נשנה זאת מיד: נגרור את כל פקד הניווט, כך שיופיע בצמוד לדופן הימנית של טופס המשנה.
שימו לב לגרור אותו אל הדופן הימנית ממש, כך שיוצג קו בצבע ורוד חלש בצד ימין:
כעת נקטין את רוחב פקד הניווט לגודל יותר סביר:
נגדיר את שם יעד הניווט עבור לחצן המשפחות להיות טופס תפריט המשפחות שיצרנו היום: navFamilies. (בינתיים יש לנו רק את תפריט המשפחות, את שני התפריטים של התורמים והתרומות ניצור בהמשך.)
לסיום – גם כאן נסיר את הפקדים המיותרים בטופס (שלשת המעצבנים כדלעיל), ואת השוליים המיותרים מסביב לפקד הניווט.
נשמור את הטופס בשם navMain.להלן התוצאה:
נהדר, זה לא היה קשה, נכון?
קחו אויר, כי החלק הבא קצת יותר מורכב.
שלב ג: הוספת פונקציונאליות ללחצנים שבטפסים
נשאר לנו כעת לחבר את הלחצנים שבטפסי המשפחה (אלו שיצרנו בפרק כב). נתחיל עם טופס רשימת המשפחות.לחצן תצוגת המשפחה
פתחו את הטופס בתצוגת עיצוב, ובחרו את לחצן הצגת המשפחה. שנו את שמו ל: cmdViewFamilyCard:
כעת נגדיר פונקצית אירוע לחיצה:
בלשונית אירוע, בחרו את האירוע בעת לחיצה, ופתחו את בונה הקוד על ידי לחיצה על שלושת הנקודות…
ובחירה באפשרות בונה הקוד.
אקסס תיצור תבנית עבור פונקצית הארוע של הלחצן.
הוסיפו בגוף הפונקציה את השורה הבאה:DoCmd.BrowseTo acBrowseToForm, "frmFamilyCard", "navMain.NavigationSubform>navFamilies.NavigationSubform", "ID=" & Me.ID
הסבר הקוד:
אנו משתמשים כאן באובייקט DoCmd שראינו בעבר, המכיל פונקציות שונות באקסס. מתוכו אנו מפעילים את הפונקציה BrowseTo שתפקידה לנווט אל טופס מסויים. הפונקציה מקבלת כמה פרמטרים:
- הפרמטר הראשון acBrowseToForm מציין את סוג האובייקט לתצוגה. במקרה שלנו הוא טופס.
כדי להציג דוח במקום טופס, יש לציין acBrowseToReport במקום acBrowseToForm.
- הפרמטר השני
"frmFamilyCard"
מציין את שם הטופס לפתיחה הלא הוא כרטיס המשפחה. - הפרמטר השלישי
"navMain.NavigationSubform>navFamilies.NavigationSubform"
מציין את הנתיב שבו ייפתח הטופס.
כיוון שבנינו מערכת של תפריטי ניווט מקוננים (תפריט ראשי>תפריט המשפחות) אנו צריכים לציין במפורש את כל המסלול שדרכו נגיע ליעד המבוקש (טופס המשנה של תפריט המשפחות). התחביר הוא כך:
שם_טופס_הניווט.שם_פקד_טופס_המשנה (כברירת מחדל הוא NavigationSubform)
אם יש כמה טפסי ניווט אחד בתוך השני (כמו אצלנו), מפרידים ביניהם על ידי הסימן "גדול מ"<
.
כך מתקבלת התוצאה הנ"ל.
שימו לב שיש להוסיף גרשיים מסביב לנתיב, כי הוא צריך להיות מועבר לפונקציה כמחרוזת.
- הפרמטר הרביעי
"ID=" & Me.ID
מציין קריטריון לחיפוש רשומה מבוקשת לתצוגה.
פרמטר זה הוא אופציונאלי, וכאשר מציינים אותו, אקסס תחפש בטופס שנפתח את הרשומה המתאימה לקריטריון, ותקפוץ אליה בפתיחת הטופס.
לדוגמא, אם אנו רוצים להציג את המשפחה שהמזהה ID שלה הוא 7, עלינו להעביר לפונקציה את הקריטריון: "ID=7".
הואיל וברצוננו להציג את המשפחה המתאימה לשורה שבה לחצנו על הלחצן, ואנחנו לא יודעים מה יהיה המזהה שלה, נוכל לקבל את המזהה שלה על ידי האובייקט Me.ID וניצור את הקריטריון המתאים על ידי חיבור מחרוזות.
הערה: ההסבר לעיל עלול לבלבל מאוד מתכנתים בתחילת הדרך.
אם אתם כאלו, זה נורמלי לחלוטין, ואין צורך להיבהל. כתיבת והבנת קוד, כמו כל מיומנות, הולכת ומשתפרת עם תרגול.
כמובן שישנה גם האפשרות שההסבר שלי לא מספיק ברור...
בכל מקרה, אל תזיעו יותר מידי. אני מבטיח שהעסק נהיה יותר קל עם הזמן.שימרו את הטופס.
כעת פיתחו את טופס התפריט הראשי navMain, בחרו את תפריט המשפחות, וברשימת המשפחות בידקו שהלחצן "הצג" עובד כראוי.טעות בכתובת
הניווט של אקסס אינו מושלם.
נסו לפתוח ישירות את הטופס של רשימת המשפחות frmFamilyList, וללחוץ על הלחצן "הצג".
למרבה התסכול, במקום להציג את הטופס, אקסס תציג הודעת שגיאה:
מה קרה?
ההודעה הזו מוצגת מפני שאנו מנסים לגשת לנתיב שאינו קיים.
הרי בקוד צייננו שהנתיב המבוקש הוא"navMain.NavigationSubform>navFamilies.NavigationSubform"
. אבל הטפסים של הניווט navMain ו-navFamilies לא פתוחים כעת, ולכן הנתיב שגוי.ישנה אפשרות על ידי קוד לפתור את הבעיה הנ"ל, אך לעת עתה נניח לה במקומה, ולא נלחץ על הכפתור הצג אם התפריטים לא פתוחים.
לחצן יצירת משפחה חדשה
בואו ניצור גם את הלחצן של יצירת משפחה חדשה. נבחר את הלחצן, וניצור עבורו פונקצית אירוע בעת לחיצה:
לשמחתנו, הקוד הנדרש דומה לקוד הקודם (נוכל להעתיק ולהדביק, ולשנות כנדרש):
DoCmd.BrowseTo acBrowseToForm, "frmFamilyCard", "navMain.NavigationSubform>navFamilies.NavigationSubform", , , acFormAdd
הסבר הקוד:
השמטנו את הפרמטר הרביעי (כי אנו לא רוצים לקפוץ לרשומה מסויימת), וגם את הפרמטר החמישי (לא רלוונטי כעת).- הפרמטר השישי
acFormAdd
מורה לאקסס לפתוח את הטופס המבוקש במצב הוספת נתונים, ולהציג רשומה חדשה בטופס.
שימרו את הטופס, פתחו את התפריט הראשי ובידקו שלחצן יצירת משפחה חדשה עובד כראוי.
לחצן מחיקת המשפחה
מחיקת משפחה היא תהליך מורכב, הואיל ויש לכל משפחה קשרי גומלין שונים. בנוסף, אני לא בטוח שכדאי לאפשר מחיקת משפחה מתצוגת הרשימה. לכן אני אחזור בי ואסיר את לחצן המחיקה מרשימת המשפחות, כדי לאפשר מחיקת משפחה רק מכרטיס המשפחה:
את הקוד עבור לחצני כרטיס המשפחה (כולל מחיקת משפחה) נשאיר לפעם הבאה אי"ה.
-
-
-
-
-
-
-
-
-
-
-
-