| ראשי | חיפוש | קוד לדוגמא | שו"ת FAQ | מאמרים | קישורים | לימוד VB | הפורום | צ'אט | | |
תוכן המאמר: מבוא מהן הודעות? הודעות ב-Visual Basic כיצד שולחים הודעות? דוגמאות עם הסברים פונקציות נוספות איך מוצאים את ההודעות מבוא מאמר זה בא להסביר בכלליות מהן "הודעות" של חלונות (Windows) וכיצד ומתי משתמשים בהודעות ובפונקציה SendMessage. המאמר אמנם מתמקד בשימוש בהודעות מתוך Visual Basic 6.0 אולם בעיקרון הדברים נכונים גם לגבי VB5 ולגבי VB.Net . מהן הודעות? הודעה (Message) היא בעצם פקודה של ביצוע פעולה מסויימת שניתן לשלוח לחלון או פקד מסויים שיבצע את הפעולה. הערה: בכל פעם שיש כאן במאמר התייחסות ל-"חלון", הכוונה היא גם לחלונות, וגם לפקדים שהם למעשה חלונות בתוך חלונות. ישנם שני סוגים של הודעות: הסוג הראשון הוא הודעה של ביצוע פקודה המשוייכת לאותו חלון, כמו פקודה של שינוי מאפיין או קבלת מידע על מאפיין של החלון (שינוי טקסט, צבע וכדומה), וגם פקודה של ביצוע פעולה על החלון (כמו לחיצה, שינוי גודל, הצגה או הסתר, ריענון וכד'). הסוג השני הוא הודעה של הפעלת אירועים (Notifications), כמו למשל אירוע של לחיצה עם העכבר. הודעות של אירועים הן למעשה גם הודעות שמתקבלות, בניגוד לסוג הראשון של ההודעות שהן הודעות שנשלחות בלבד. הודעות ב-Visual Basic כידוע, ויזואל בייסיק הינה מונחית אירועים, לכן ניתן לבצע בקלות רבה פעולות פשוטות כמו שינוי מאפיינים של פקדים או ביצוע פעולות שונות. בשפות שאינן מונחות אירועים לא ניתן לבצע פעולות כאלו באותה פשטות כפי שניתן לעשות בויזואל בייסיק, אלא יש להשתמש בשליחת הודעות על מנת לבצע פעולות בסיסיות אלו. לעומת זאת בויזואל בייסיק, העבודה הקשה של שליחת ההודעות לפקדים הושארה מאחורי הקלעים של מאפייני העצמים והאובייקטים שבשפה. למרות שהיתרון הזה די חוסך ממתכנתי VB את הצורך בשליחת הודעות, ישנן מספר פעולות שניתן לבצע רק באמצעות שליחת הודעות, כמו למשל שינוי מאפיינים שלא נתמכים ישירות ב-VB (למשל צבע הרקע של Progress Bar) וגם ביצוע פעולות על חלונות שלא שייכים לתוכנית. כיצד שולחים הודעות? את ההודעות ניתן לשלוח באמצעות מספר פונקציות API, שהנפוצה מתוכן היא SendMessage, ששולחת הודעה מסויימת לחלון מסויים (הסברים על API ניתן למצוא במאמר זה). התחביר של הפונקציה הוא:
הסבר: בארגומנט הראשון - hWnd - מעבירים את המזהה של החלון שאליו רוצים לשלוח את ההודעה (הסברים על hWnd ומציאת מזהים של חלונות ניתן למצוא במאמר של רוני חן שיפורסם בקרוב). בארגומנט השני - wMsg - מציינים איזו הודעה לשלוח. זהו ערך מספרי שמציין את ההודעה, שישנם קבועים מוכנים מראש המכילים את המספר של כל הודעה (למשל WM_CLOSE). שני הארגומנט הבאים הם פרמטרים הנלווים להודעה אשר מציינים מידע הקשור להודעה ששולחים, ותפקידם משתנה בכל הודעה. בדרך כלל המידע שמעבירים ב-wParam הוא מידע מספרי, והמידע שמעבירים ב-lParam הוא יכול להיות גם מידע מספרי, וגם מידע יותר גדול כמו מחרוזת, טיפוס, או משתנה שמקבל מחרוזת או טיפוס (חשוב לציין שיש גם הודעות של קבלת מידע ולא רק שליחת מידע). כאשר שולחים הודעה שלא זקוקה למידע נוסף מהפרמטרים האלו, אז פשוט מעבירים 0 בשניהם או באחד מהם, תלוי בהודעה. הערך שמוחזר ישירות מהפונקציה ותפקידו גם כן משתנים בכל הודעה. דוגמאות עם הסברים ראשית, לכל שימוש בפונקציה SendMessage נדרשת כמובן הצהרה על הפונקציה, כדלקמן:
בנוסף להכרזה נהוג גם לשים קבועים (Const) שמייצגים את מספרי ההודעות. דבר זה מומלץ מאוד למרות שהוא למעשה אינו חובה - אפשר לשים ישירות את מספר ההודעה בקריאה לפונקציה אך זה עלול לגרום לבלבול וחוסר הבנה, ולכן דרך זו אינה מומלצת. דוגמאות להכרזה על קבועים של הודעת:
הערה: הסבר על מציאת ההודעות מופיע בהמשך המאמר. דוגמאות לשימוש בפונקציה באופן מעשי: דוגמא 1: סגירת החלון
הסבר: קוד זה מדגים שליחת הודעה של סגירת חלון. בשתי השורות הראשונות יש את ההצהרה על הפונקציה ועל הקבוע של ההודעה. השגרה שבאה בשורה הבאה היא אירוע של לחיצה על הכפתור Command1. כאשר לוחצים על הכפתור הפונקציה שולחת את ההודעה WM_CLOSE שפעולתה היא סגירת חלון. הפונקציה מופעלת על המזהה של הטופס (Me.hWnd) ולכן הטופס הוא החלון שייסגר, ואם הפונקציה הייתה מופעל על מזהה של חלון אחר אז החלון ההוא היה נסגר. מאחר וההודעה WM_CLOSE אינה דורשת נתונים נוספים, אז ב-wParam וב-lParam במקרה הזה נציב 0. הערה חשובה: שימו לב שאחרי האפס שאנו מציבים ב-lParam יש סימן "&", והסיבה היא שמאחר והטיפוס של הארגומנט lParam הוא Any, הוא לא יכול לקבל מספרים או משתנים שהם Integer, אלא רק Long ומעלה, ולכן יש צורך בסימן הזה, שהוא בעצם תו מגדיר של Long, כמו שהסימן "$" הוא תו מגדיר של String. דוגמא 2: קבלת תוכן של תיבת טקסט
הסבר: קוד זה מדגים שליחת הודעה של קבלת הטקסט של החלון, פעולה שנעשית באמצעות שתי הודעות: WM_GETTEXTLENGTH ו-WM_GETTEXT. כאשר יש לחיצה על הכפתור אז התוכנית מקבלת את הטקסט של תיבת הטקסט באופן הבא: ראשית יש לקבל את אורך הטקסט, דבר זה נעשה על-ידי שליחה של ההודעה WM_GETTEXTLENGTH, שמחזירה דרך SendMessage את אורך הטקסט. בשלב השני יש ליצור מקום במשתנה MyStr לפי אורך הטקסט, עבור קבלת תוכן הטקסט לתוך המשתנה. בשלב השלישי יש לשלוח את ההודעה WM_GETTEXT שפעולתה היא לקבל את תוכן הטקסט. להודעה יש שני פרמטרים: ב-wParam מציינים את אורך הטקסט שיוחזר, שמקרה שלנו אנו רוצים שזה יהיה גם אורך הטקסט שבתיבה. ב-lParam מציינים משתנה שבו ההודעה תציב את המידע המוחזר (בדוגמה זו זה יהיה הוא הטקסט שמופיע בתיבה). חשוב לציין שיש לא מעט פעמים שמשתמשים בדרך הזו של יצירת מקום במשתנה והשתלת המידע המוחזר במשתנה, זה די נפוץ ב-API כאשר המידע המוחזר הוא מחרוזת או טיפוס נתונים. דוגמא 3: פתיחת תיבת קומבו ע"י שימוש בקוד
הסבר: קוד זה מדגים שליחת הודעה של פתיחה ידנית של תיבת Combo, שאינה אפשרית בקוד המובנה של VB6. כשיש לחיצה על הכפתור אז התוכנית שולחת את ההודעה CB_SHOWDROPDOWN שנועדה לפתוח ולסגור תיבות קומבו. הפרמטר היחיד של ההודעה הוא wParam, בו מציינים האם לפתוח או לסגור את התיבה (True כדי לפתוח, False כדי לסגור). אין צורך ב-lParam ולכן מעבירים שם 0. פונקציות נוספות בנוסף ל-SendMessage יש עוד פונקציות API לעבודה עם הודעות, לחלקן יש מבנה דומה לזה של SendMessage. הנה חלק מהפונקציות ותפקידן: PostMessage - פונקציה זו שולחת הודעה בדומה ל-SendMessage, אך בניגוד לפונקציה ההיא, PostMessage אינה ממתינה עד שביצוע ההודעה יסתיים. SendMessageTimeout - פונקציה זו שולחת הודעה בדומה ל-SendMessage, וההמתנה לסיום ביצוע ההודעה מתבצעת בהתאם למה שצויין בשני הארגומנטים הנוספים: fuFlags ו-uTimeout. בארגומנט הנוסף השלישי (lpdwResult) מעבירים משתנה שמקבל את המידע המוחזר מהפונקציה. PostQuitMessage - פונקציה זו שולחת את ההודעה WM_QUIT לחלון שמציינים ב-hWnd. הפרמטר היחיד שלה הוא wParam כיוון שלהודעה WM_QUIT יש רק פרמטר אחד. יש גם מספר פונקציות שתפקידן הוא לטפל בהודעות שמגיעות ולא בשליחת הודעות, כגון GetMessage , PeekMessage או WaitMessage, עליהן לא נדון כאן. איך מוצאים את ההודעות? ישנן עשרות הודעות שמבצעות פעולות שונות, ובדומה לפונקציות API, אפשר למצוא תיעוד מלא על כל ההודעות שיש ב-MSDN Library, ששם ניתן למצוא פירוט מה עושה כל הודעה, ולמה משמשים ה-wParam וה-lParam של ההודעה הספציפית. ההודעות שם מופיעות לפי שמות הקבועים שמכילים את מספרי ההודעה (דוגמאות: TVM_SETBKCOLOR , EM_SCROLL , WM_GETICON וכדומה). את הקבועים של ההודעות אפשר למצוא במקומות שמכילים רשימות של קבועים, כמו ApiViewer 2004 או VB6 Api Viewer של ויזואל בייסיק, או כל מקום אחר שמכיל רשימת קבועים של API. בדרך כלל (לא תמיד) לקבועים יש שם שבנוי בצורה הזאת: [שם או פעולת ההודעה]_[קידומת של ראשי התיבות של הפקד+M] ניקח לדוגמה את ההודעה EM_SCROLL, לפי הקידומת EM היא מיועדת לתיבות טקסט, כיוון שאות הראשונה E מסמלת "Edit", כלומר תיבת טקסט. לפי מה שרשום אחרי הקידומת, לומדים שפעולת ההודעה היא גלילה, כך שזו הודעה שמבצעת גלילה של תיבות טקסט. חשוב לציין שהאות M שבקידומות באה מהמילה Message, כלומר הודעה. למשל, הודעות של לחצנים (כגון כפתורי פקודה) באות עם הקידומת BM (האות B מסמלת Button, כלומר לחצן), כמו למשל BM_CLICK, ומכאן למדים שההודעה הזו היא הודעה של לחיצה על כפתורים (חשוב לציין ש-CheckBox ו-OptionBox גם נחשבים ל-Button). דוגמאות נוספות של קידומות של הודעות: WM - הודעות כלליות שמשותפות לרוב סוגי החלונות (Window Message) TVM - הודעות הנוגעות לפקדי תצוגת עץ (TreeView Message) PBM - הודעות של פקדי תצוגת התקדמות (ProgressBar Message) LVM=פקדי ListView SBM=פסי גלילה (ScrollBar Message) TCM=פקדי טאבים (TabControl Message) UDM=פקדי UpDown. לחלק מהפקדים יש הודעות שהקידומת שלהן היא בלי האות M בסוף, לדוגמא: CB=הודעות של פקדי ComboBox (למשל CB_ADDSTRING) LB=פקדי ListBox SB=פקדי StatusBar TB=פקדי ToolBar עבור כל הודעה יש דף בנפרד באתר MSDN עם כל הפרטים אודות ההודעה. אני מקווה שמאמר זה יהיה מובן ושימושי, ובכל אופן בהצלחה. למקרה שמשהו אינו מובן ניתן לפנות אלי באמצעות ואשמח לעזור! לחצו כאן להורדת קוד לדוגמה, המדגים מספר אפשרויות לשימוש בהודעות. |