【第3版emWin教程】第43章 emWin6.x視窗管理器例項(含自定義訊息)
教程不斷更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429
第43章 emWin6.x視窗管理器例項(含自定義訊息)
為了幫助大家更好的理解視窗管理器的回撥函式和訊息機制,本章教程專門做了兩個相關的例子,幫助大家更好的理解。
43.1初學者重要提示
43.2 使用者自定義訊息型別例項
43.3 桌面視窗回撥函式例項
43.4 總結
43.1 初學者重要提示
- 通過例項來學習emWin是最佳的學習捷徑。
- 本章節舉的兩個例子都用到了對話方塊,對於初學者來說,僅需知道這是對話方塊即可,重點是看對話方塊回撥函式的實現,後面章節會專門講解對話方塊。
- 視窗管理器這塊的API函式應該是emWin手冊所有章節中函式最多的,以後需要用到什麼功能了,查詢就行,或者看官方的例項,哪個函式不理解了也可以查手冊。下圖是中文版手冊裡面API函式位
下圖是英文版手冊裡面API函式的位置:
43.2 使用者自定義訊息型別例項
第42章為大家講解的都是emWin支援的訊息型別,這裡我們通過一個例項來實現自定義訊息,這個功能在大家以後的實際專案中都有機會用到,比較有實戰價值。
下面我們直接通過如下的程式碼來講解實現方法和用到的函式(可以直接將程式碼複製到模擬器或者開發板上面執行)。
#include "DIALOG.h" /* ********************************************************************************************************* * 變數 **********************************************************************************************************/ static GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW}; //--------------(1) static unsigned char ucBackColor; /* ********************************************************************************************************* * 巨集定義 **********************************************************************************************************/ #define ID_FRAMEWIN_0 (GUI_ID_USER + 0x00) #define ID_BUTTON_0 (GUI_ID_USER + 0x01) #define ID_SCROLLBAR_0 (GUI_ID_USER + 0x02) #define ID_SLIDER_0 (GUI_ID_USER + 0x03) #define WM_UPDATE (WM_USER + 0x00) /* 自定義訊息 */ // --------------(2) /* ********************************************************************************************************* * GUI_WIDGET_CREATE_INFO型別陣列 ********************************************************************************************************* */ static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = { { FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 480, 272, 0, 0x64, 0 }, { BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 130, 28, 147, 35, 0, 0x0, 0 }, { SCROLLBAR_CreateIndirect, "Scrollbar", ID_SCROLLBAR_0, 129, 74, 147, 28, 0, 0x0, 0 }, { SLIDER_CreateIndirect, "Slider", ID_SLIDER_0, 133, 118, 137, 25, 0, 0x0, 0 }, }; /* ********************************************************************************************************* * 函 數 名: _cbDialog * 功能說明: 對話方塊回撥函式 * 形 參: pMsg 回撥引數 * 返 回 值: 無 ********************************************************************************************************* */ static void _cbDialog(WM_MESSAGE * pMsg) { WM_HWIN hItem; int NCode; int Id; switch (pMsg->MsgId) { case WM_INIT_DIALOG: // // 初始化 'Framewin' // hItem = pMsg->hWin; FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII); FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER); FRAMEWIN_SetText(hItem, "armfly"); // // 初始化 'Button' // hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0); BUTTON_SetFont(hItem, GUI_FONT_24B_ASCII); BUTTON_SetText(hItem, "armfly"); /* 預設顏色取*/ ucBackColor = 0; break; case WM_PAINT: GUI_SetBkColor(_acColor[ucBackColor]); GUI_Clear(); break; case WM_UPDATE: //--------------(3) ucBackColor++; if (ucBackColor == 3) { ucBackColor = 0; } WM_InvalidateWindow(pMsg->hWin); break; case WM_KEY: switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) { case GUI_KEY_ESCAPE: GUI_EndDialog(pMsg->hWin, 1); break; case GUI_KEY_ENTER: GUI_EndDialog(pMsg->hWin, 0); break; } break; case WM_NOTIFY_PARENT: Id = WM_GetId(pMsg->hWinSrc); NCode = pMsg->Data.v; switch(Id) { case ID_BUTTON_0: switch(NCode) { case WM_NOTIFICATION_CLICKED: break; case WM_NOTIFICATION_RELEASED: break; } break; case ID_SCROLLBAR_0: switch(NCode) { case WM_NOTIFICATION_CLICKED: break; case WM_NOTIFICATION_RELEASED: break; case WM_NOTIFICATION_VALUE_CHANGED: break; } break; case ID_SLIDER_0: switch(NCode) { case WM_NOTIFICATION_CLICKED: break; case WM_NOTIFICATION_RELEASED: break; case WM_NOTIFICATION_VALUE_CHANGED: break; } break; } break; default: WM_DefaultProc(pMsg); break; } } /* ********************************************************************************************************* * 函 數 名: CreateFramewin * 功能說明: 建立對話方塊 * 形 參: 無 * 返 回 值: 返回對話方塊控制代碼 ********************************************************************************************************* */ WM_HWIN CreateFramewin(void) { WM_HWIN hWin; hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0); return hWin; } /* ********************************************************************************************************* * 函 數 名: MainTask * 功能說明: GUI主函式 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void MainTask(void) { WM_HWIN hDlg; /* 初始emWin */ GUI_Init(); /* 建立對話方塊 */ hDlg = CreateFramewin(); while(1) { /* 給對話方塊hDlg傳送自定義訊息WM_UPDATE */ WM_SendMessageNoPara(WM_GetClientWindow(hDlg), WM_UPDATE); // --------------(4) GUI_Delay(500); } }
實現自定義訊息的關鍵是函式WM_SendMessageNoPara的使用,學會了這個函式基本就學會了自定義訊息的實現:
- 定義一個數組,裡面有三種顏色,再定義一個變數,用於三種顏色的切換。
- 定義一個使用者訊息WM_UPDATE,一定要以WM_USER作為起始值,防止跟系統其他的數值衝突。如果還要實現其它自定義訊息,在這個數值的基礎上面定義即可。
- 在回撥函式中加入自定義訊息WM_UPDATE,在這個訊息裡面切換對話方塊的背景色變數,然後呼叫函式WM_InvalidateWindow將對話方塊進行無效化,從而會觸發視窗管理器去執行WM_PAINT訊息,這樣就實現了對話方塊背景色的變化。
- 通過函式WM_SendMessageNoPara()每隔500ms給對話方塊傳送WM_UPDATE訊息。函式原型如下:
void WM_SendMessageNoPara(WM_HWIN hWin, int MsgId)
此函式用於將不帶引數的訊息傳送到指定視窗,使用也比較簡單,第一個引數hWin是要接受訊息的視窗控制代碼,第二個引數MsgId是訊息型別。其中第一個引數要特別注意,如果是給對話方塊發訊息,且對話方塊的主體是框架視窗FrameWin或者直接給框架視窗FrameWin發訊息,第一個引數必須要使用函式WM_GetClientWindow獲得框架視窗的客戶區,這一點非常重要,經常有初學者在這個地方犯錯誤。如果對話方塊的主體是Windows或者直接給Windows視窗發訊息,無需使用函式WM_GetClientWindow,直接填控制代碼就可以了。
此時初學者還會有個疑問,能否使用函式WM_SendMessageNoPara可以傳送類似WM_PAINT的系統訊息?答案是可以的,不過跟發自定義訊息稍有區別:
/* 設定要用於繪製操作的活動視窗 */ WM_SelectWindow(WM_GetClientWindow(hDlg)); /* 給對話方塊hDlg傳送系統訊息WM_PAINT */ WM_SendMessageNoPara(WM_GetClientWindow(hDlg), WM_PAINT); /* 切換回預設的桌面視窗 */ WM_SelectWindow(WM_HBKWIN);
另外還有一個帶引數的訊息傳送函式WM_SendMessage,在第38章會有一個例子呼叫這個函式。最後,本程式的顯示效果如下(解析度480*272),每500ms更新一次對話方塊的客戶區背景色:
43.3 桌面視窗回撥函式例項
這個例子為大家講解如何給桌面視窗配置回撥函式。實現原始碼如下(可以直接將程式碼複製到模擬器或者開發板上面執行)。
#include "DIALOG.h" /* ********************************************************************************************************* * 巨集定義 ********************************************************************************************************* */ #define ID_FRAMEWIN_0 (GUI_ID_USER + 0x00) #define ID_BUTTON_0 (GUI_ID_USER + 0x01) #define ID_SCROLLBAR_0 (GUI_ID_USER + 0x02) #define ID_SLIDER_0 (GUI_ID_USER + 0x03) /* ********************************************************************************************************* * GUI_WIDGET_CREATE_INFO型別陣列 ********************************************************************************************************* */ static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = { //--------------(1) { FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 480, 272, FRAMEWIN_CF_MOVEABLE, 0x64, 0 }, { BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 130, 28, 147, 35, 0, 0x0, 0 }, { SCROLLBAR_CreateIndirect, "Scrollbar", ID_SCROLLBAR_0, 129, 74, 147, 28, 0, 0x0, 0 }, { SLIDER_CreateIndirect, "Slider", ID_SLIDER_0, 133, 118, 137, 25, 0, 0x0, 0 }, }; /* ********************************************************************************************************* * 函 數 名: _cbDialog * 功能說明: 對話方塊回撥函式 * 形 參: pMsg 回撥引數 * 返 回 值: 無 ********************************************************************************************************* */ static void _cbDialog(WM_MESSAGE * pMsg) { WM_HWIN hItem; int NCode; int Id; switch (pMsg->MsgId) { case WM_INIT_DIALOG: // // 初始化 'Framewin' // hItem = pMsg->hWin; FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII); FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER); FRAMEWIN_SetText(hItem, "armfly"); // // 初始化 'Button' // hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0); BUTTON_SetFont(hItem, GUI_FONT_24B_ASCII); BUTTON_SetText(hItem, "armfly"); break; case WM_PAINT: GUI_SetBkColor(GUI_RED); GUI_Clear(); break; case WM_KEY: switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) { case GUI_KEY_ESCAPE: GUI_EndDialog(pMsg->hWin, 1); break; case GUI_KEY_ENTER: GUI_EndDialog(pMsg->hWin, 0); break; } break; case WM_NOTIFY_PARENT: Id = WM_GetId(pMsg->hWinSrc); NCode = pMsg->Data.v; switch(Id) { case ID_BUTTON_0: switch(NCode) { case WM_NOTIFICATION_CLICKED: break; case WM_NOTIFICATION_RELEASED: break; } break; case ID_SCROLLBAR_0: switch(NCode) { case WM_NOTIFICATION_CLICKED: break; case WM_NOTIFICATION_RELEASED: break; case WM_NOTIFICATION_VALUE_CHANGED: break; } break; case ID_SLIDER_0: switch(NCode) { case WM_NOTIFICATION_CLICKED: break; case WM_NOTIFICATION_RELEASED: break; case WM_NOTIFICATION_VALUE_CHANGED: break; } break; } break; default: WM_DefaultProc(pMsg); break; } } /* ********************************************************************************************************* * 函 數 名: CreateFramewin * 功能說明: 建立對話方塊 * 形 參: 無 * 返 回 值: 返回對話方塊控制代碼 ********************************************************************************************************* */ WM_HWIN CreateFramewin(void) { WM_HWIN hWin; hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0); return hWin; } /* ********************************************************************************************************* * 函 數 名: _cbBkWindow * 功能說明: 桌面視窗回撥函式 * 形 參: 無 * 返 回 值: 返回對話方塊控制代碼 ********************************************************************************************************* */ static void _cbBkWindow(WM_MESSAGE * pMsg) //--------------(2) { WM_HWIN hWin = pMsg->hWin; switch (pMsg->MsgId) { case WM_PAINT: GUI_SetBkColor(GUI_BLUE); GUI_Clear(); break; default: WM_DefaultProc(pMsg); } } /* ********************************************************************************************************* * 函 數 名: MainTask * 功能說明: GUI主函式 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void MainTask(void) { WM_HWIN hDlg; /* 使能視窗使用記憶體裝置,這樣可以有效避免閃爍, 放在GUI_Init前面就包括桌面 視窗,如果放在後面就不包括桌面視窗。 */ WM_SetCreateFlags(WM_CF_MEMDEV); //--------------(3) /* 初始emWin */ GUI_Init(); /* 設定桌面視窗的回撥函式 */ WM_SetCallback(WM_HBKWIN, _cbBkWindow); //--------------(4) /* 建立對話方塊 */ hDlg = CreateFramewin(); while(1) { GUI_Delay(10); } }
- 對話方塊資源列表第一個選項FrameWin設定了一個引數FRAMEWIN_CF_MOVEABLE,這樣對話方塊就是可以移動的,方便檢視桌面視窗回撥函式的重新整理。關於對話方塊的使用會在後面章節為大家詳細講解,這裡有個感性的認識即可。
- 桌面視窗的回撥函式(桌面視窗是emWin最底層的視窗,是初始化後自動建立的),這裡僅實現了一個WM_PAINT訊息。
- 使用函式WM_SetCreateFlags(WM_CF_MEMDEV)分兩種情況,如果此函式是放在函式GUI_Init前面,那麼所有的視窗將自動使用記憶體裝置,使用記憶體裝置的好處是有效避免閃爍感。如果此函式是放在函式GUI_Init後面呼叫,那麼桌面視窗是沒有使用記憶體裝置的,這點要特別注意。
- 通過函式WM_SetCallback來設定桌面視窗的回撥函式,實現的功能比較簡單,僅設定重繪訊息。這裡的功能基本等同於呼叫函式WM_SetDesktopColor(GUI_BLUE)。實現的效果是一樣的,都是可以自動重繪桌面視窗。
另外,測試中還發現一點,如果使用者將函式WM_SetCreateFlags(WM_CF_MEMDEV)放在GUI_Init前面,桌面視窗也是可以自動重繪的,這樣就可以不需要使用WM_SetCallback來設定桌面視窗回撥函式或者使用函式WM_SetDesktopColor(GUI_BLUE),不過重繪的顏色固定為灰色。
----------------------------
這個程式的顯示效果如下(解析度480*272):
使用者可以拖動這個視窗,滑鼠點選到標題欄就可以拖動了,跟操作電腦端軟體是一樣的:
如果不設定桌面視窗回撥函式,且函式WM_SetCreateFlags(WM_CF_MEMDEV)沒有放在GUI_Init前面呼叫,那麼拖動視窗的話,顯示效果就是這個樣子的:
顯示成這個樣子是因為桌面視窗沒有執行重繪,導致拖動對話方塊的時候一直有上次顯示的殘影。
43.4 總結
本章節就跟大家講這麼多,希望通過本章教程讓大家對視窗管理器有更好的認識,不過還需要大家在模擬器或者開發板上面多做這方面的練習,將其它的視窗管理器API函式也呼叫測試下。
微信公眾號:armfly_com 安富萊論壇:www.armbbs.cn 安富萊淘寶:https://armfly.taobao.com