第34章 窗口管理器实例(一)
为了帮助大家更好的理解窗口管理器的回调和消息机制,本期教程专门做了三个相关的例子,帮助大家更好的理解。
34. 1 用户自定义消息类型实例
34. 2 桌面窗口回调函数实例
34. 3 官方WM_Redraw.c实例
34. 4 总结
34.1 用户自定义消息类型实例
这里用上期教程所介绍的自定义消息类型做一个实例。代码跟上期教程的三个实例类似。实现源码如下(可以直接将代码复制到模拟器或者开发板上面运行)。
- #include <stddef.h>
- #include "GUI.h"
- #include "DIALOG.h"
-
- #include "WM.h"
- #include "BUTTON.h"
- #include "CHECKBOX.h"
- #include "DROPDOWN.h"
- #include "EDIT.h"
- #include "FRAMEWIN.h"
- #include "LISTBOX.h"
- #include "MULTIEDIT.h"
- #include "RADIO.h"
- #include "SLIDER.h"
- #include "TEXT.h"
- #include "PROGBAR.h"
- #include "SCROLLBAR.h"
- #include "LISTVIEW.h"
-
-
- #define WM_UPDATE WM_USER + 1(1)
- /*********************************************************************
- *
- * static data
- *
- **********************************************************************
- */
- GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW};
- static char ucBackColor;
-
-
-
- /*********************************************************************
- *
- * Dialog resource
- *
- * This table conatins the info required to create the dialog.
- * It has been created by ucGUIbuilder.
- */
-
- static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
- { FRAMEWIN_CreateIndirect, "armfly", 0, 0, 0, 800,480,FRAMEWIN_CF_MOVEABLE,0},
- { BUTTON_CreateIndirect, "BUTTON0", GUI_ID_BUTTON0, 82, 122,162,37, 0,0},
- { BUTTON_CreateIndirect, "BUTTON1", GUI_ID_BUTTON1, 357,123,152,35, 0,0}
- };
-
- /*****************************************************************
- ** FunctionName:void PaintDialog(WM_MESSAGE * pMsg)
- ** Function: to initialize the Dialog items
- **
- ** call this function in _cbCallback --> WM_PAINT
- *****************************************************************/
-
- void PaintDialog(WM_MESSAGE * pMsg)
- {
- WM_HWIN hWin = pMsg->hWin;
- GUI_SetBkColor(_acColor[ucBackColor]);
- GUI_Clear();
- }
-
- /*****************************************************************
- ** FunctionName:void InitDialog(WM_MESSAGE * pMsg)
- ** Function: to initialize the Dialog items
- **
- ** call this function in _cbCallback --> WM_INIT_DIALOG
- *****************************************************************/
-
- void InitDialog(WM_MESSAGE * pMsg)
- {
- WM_HWIN hWin = pMsg->hWin;
- //
- //FRAMEWIN
- //
- FRAMEWIN_SetFont(hWin,&GUI_Font24B_ASCII);
- FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER);
- FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0);
- FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1);
- FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2);
- FRAMEWIN_SetTitleHeight(hWin,30);
-
- /* 默认颜色取*/
- ucBackColor = 0;
- }
-
- /*********************************************************************
- *
- * Dialog callback routine
- */
- static void _cbCallback(WM_MESSAGE * pMsg)
- {
- int NCode, Id;
- WM_HWIN hWin = pMsg->hWin;
- switch (pMsg->MsgId)
- {
-
- case WM_UPDATE: (2)
- ucBackColor++;
- if (ucBackColor == 3)
- {
- ucBackColor = 0;
- }
- WM_InvalidateWindow(hWin);
- break;
- case WM_MOUSEOVER:
- break;
- case WM_PAINT:
- PaintDialog(pMsg);
- break;
- case WM_INIT_DIALOG:
- InitDialog(pMsg);
- break;
- case WM_KEY:
- switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key)
- {
- case GUI_KEY_ESCAPE:
- GUI_EndDialog(hWin, 1);
- break;
- case GUI_KEY_ENTER:
- GUI_EndDialog(hWin, 0);
- break;
- }
- break;
- case WM_NOTIFY_PARENT:
- Id = WM_GetId(pMsg->hWinSrc);
- NCode = pMsg->Data.v;
- switch (Id)
- {
- case GUI_ID_OK:
- if(NCode==WM_NOTIFICATION_RELEASED)
- GUI_EndDialog(hWin, 0);
- break;
- case GUI_ID_CANCEL:
- if(NCode==WM_NOTIFICATION_RELEASED)
- GUI_EndDialog(hWin, 0);
- break;
- case GUI_ID_BUTTON0:
- switch(NCode)
- {
- case WM_NOTIFICATION_CLICKED:
- ucBackColor++;
- if (ucBackColor == 3)
- {
- ucBackColor = 0;
- }
- WM_InvalidateWindow(hWin);
- break;
- case WM_NOTIFICATION_RELEASED:
-
- break;
- case WM_NOTIFICATION_MOVED_OUT:
-
- break;
- }
- break;
- case GUI_ID_BUTTON1:
- switch(NCode)
- {
- case WM_NOTIFICATION_CLICKED:
- ucBackColor--;
- if (ucBackColor < 0)
- {
- ucBackColor = 2;
- }
- WM_InvalidateWindow(hWin);
- break;
- case WM_NOTIFICATION_RELEASED:
-
- break;
- case WM_NOTIFICATION_MOVED_OUT:
-
- break;
- }
- break;
-
- }
- break;
- default:
- WM_DefaultProc(pMsg);
- }
- }
-
-
- /*********************************************************************
- *
- * MainTask
- *
- **********************************************************************
- */
- void MainTask(void)
- {
- WM_HWIN hDlg;
-
- GUI_Init();
- WM_SetDesktopColor(GUI_BLUE); /* Automacally update desktop window */
- WM_SetCreateFlags(WM_CF_MEMDEV); /* Use memory devices on all windows to avoid flicker */
- PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
- FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX);
- PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
- BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX);
- CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX);
- DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX);
- SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX);
- SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX);
- HEADER_SetDefaultSkin(HEADER_SKIN_FLEX);
- RADIO_SetDefaultSkin(RADIO_SKIN_FLEX);
- /* 创建一个对话框 */
- hDlg = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0);
- while (1)
- {
- WM_SendMessageNoPara(WM_GetClientWindow(hDlg), WM_UPDATE); (3)
- GUI_Delay(500);
- }
-
- }
1. 定义一个用户消息WM_UPDATE。一定要以WM_USER作为起始值,防止跟系统其他的数值冲突。
2. 在回调函数中加入咱们定义的消息WM_UPDATE,实现对话框中背景的更新功能。
3. 通过函数WM_SendMessageNoPara()每隔500ms给对话框发送消息。这里要特别的注意一点,这个函数是给窗口发送消息的,而咱们前面创建的是对话框,所以这里必须得通过函数WM_GetClientWindow得到窗口的句柄。
这个程序的显示效果如下:
34.2 桌面窗口回调函数实例
这里用上期教程所介绍的自定义消息类型做一个实例。代码跟上期教程的三个实例类似。实现源码如下(可以直接将代码复制到模拟器或者开发板上面运行)。
- #include <stddef.h>
- #include "GUI.h"
- #include "DIALOG.h"
-
- #include "WM.h"
- #include "BUTTON.h"
- #include "CHECKBOX.h"
- #include "DROPDOWN.h"
- #include "EDIT.h"
- #include "FRAMEWIN.h"
- #include "LISTBOX.h"
- #include "MULTIEDIT.h"
- #include "RADIO.h"
- #include "SLIDER.h"
- #include "TEXT.h"
- #include "PROGBAR.h"
- #include "SCROLLBAR.h"
- #include "LISTVIEW.h"
-
-
- #define WM_UPDATE WM_USER + 1
- /*********************************************************************
- *
- * static data
- *
- **********************************************************************
- */
- GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW};
- static char ucBackColor;
-
-
-
- /*********************************************************************
- *
- * Dialog resource
- *
- * This table conatins the info required to create the dialog.
- * It has been created by ucGUIbuilder.
- */
-
- static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
- { FRAMEWIN_CreateIndirect, "armfly", 0, 0, 0, 800,480,FRAMEWIN_CF_MOVEABLE,0},
- { BUTTON_CreateIndirect, "BUTTON0", GUI_ID_BUTTON0, 82, 122,162,37, 0,0},
- { BUTTON_CreateIndirect, "BUTTON1", GUI_ID_BUTTON1, 357,123,152,35, 0,0}
- };
-
- /*****************************************************************
- ** FunctionName:void PaintDialog(WM_MESSAGE * pMsg)
- ** Function: to initialize the Dialog items
- **
- ** call this function in _cbCallback --> WM_PAINT
- *****************************************************************/
-
- void PaintDialog(WM_MESSAGE * pMsg)
- {
- WM_HWIN hWin = pMsg->hWin;
- // GUI_SetBkColor(_acColor[ucBackColor]);
- // GUI_Clear();
- }
-
- /*****************************************************************
- ** FunctionName:void InitDialog(WM_MESSAGE * pMsg)
- ** Function: to initialize the Dialog items
- **
- ** call this function in _cbCallback --> WM_INIT_DIALOG
- *****************************************************************/
-
- void InitDialog(WM_MESSAGE * pMsg)
- {
- WM_HWIN hWin = pMsg->hWin;
- //
- //FRAMEWIN
- //
- FRAMEWIN_SetFont(hWin,&GUI_Font24B_ASCII);
- FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER);
- FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0);
- FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1);
- FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2);
- FRAMEWIN_SetTitleHeight(hWin,30);
-
- /* 默认颜色取*/
- ucBackColor = 0;
- }
-
- /*********************************************************************
- *
- * Dialog callback routine
- */
- static void _cbCallback(WM_MESSAGE * pMsg)
- {
- int NCode, Id;
- WM_HWIN hWin = pMsg->hWin;
- switch (pMsg->MsgId)
- {
- case WM_PAINT:
- PaintDialog(pMsg);
- break;
- case WM_INIT_DIALOG:
- InitDialog(pMsg);
- break;
- case WM_KEY:
- switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key)
- {
- case GUI_KEY_ESCAPE:
- GUI_EndDialog(hWin, 1);
- break;
- case GUI_KEY_ENTER:
- GUI_EndDialog(hWin, 0);
- break;
- }
- break;
- case WM_NOTIFY_PARENT:
- Id = WM_GetId(pMsg->hWinSrc);
- NCode = pMsg->Data.v;
- switch (Id)
- {
- case GUI_ID_OK:
- if(NCode==WM_NOTIFICATION_RELEASED)
- GUI_EndDialog(hWin, 0);
- break;
- case GUI_ID_CANCEL:
- if(NCode==WM_NOTIFICATION_RELEASED)
- GUI_EndDialog(hWin, 0);
- break;
- case GUI_ID_BUTTON0:
- switch(NCode)
- {
- case WM_NOTIFICATION_CLICKED:
- break;
- case WM_NOTIFICATION_RELEASED:
-
- break;
- case WM_NOTIFICATION_MOVED_OUT:
-
- break;
- }
- break;
- case GUI_ID_BUTTON1:
- switch(NCode)
- {
- case WM_NOTIFICATION_CLICKED:
-
- break;
- case WM_NOTIFICATION_RELEASED:
-
- break;
- case WM_NOTIFICATION_MOVED_OUT:
-
- break;
- }
- break;
-
- }
- break;
- default:
- WM_DefaultProc(pMsg);
- }
- }
-
- /*********************************************************************
- *
- * Dialog callback routine
- */
- static void _cbBkWindow(WM_MESSAGE * pMsg) (1)
- {
- WM_HWIN hWin = pMsg->hWin;
-
- switch (pMsg->MsgId)
- {
- case WM_PAINT: (2)
- GUI_SetBkColor(_acColor[ucBackColor]);
- GUI_Clear();
- break;
- case WM_UPDATE:(3)
- ucBackColor++;
- if (ucBackColor == 3)
- {
- ucBackColor = 0;
- }
- WM_InvalidateWindow(hWin);
- break;
- default:
- WM_DefaultProc(pMsg);
- }
- }
-
- /*********************************************************************
- *
- * MainTask
- *
- **********************************************************************
- */
- void MainTask(void)
- {
- WM_HWIN hDlg;
- /*
- 使能窗口使用内存设备,这样可以有效避免闪烁 放在GUI_Init前面就包括桌面
- 窗口,如果放在后面就不包括桌面窗口。
- */
- WM_SetCreateFlags(WM_CF_MEMDEV); (4)
- GUI_Init();
- /* 设置桌面窗口回调函数 */
- WM_SetCallback(WM_HBKWIN, _cbBkWindow);(5)
- //WM_SetDesktopColor(GUI_BLUE); /* Automacally update desktop window */ (6)
- PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
- FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX);
- PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
- BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX);
- CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX);
- DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX);
- SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX);
- SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX);
- HEADER_SetDefaultSkin(HEADER_SKIN_FLEX);
- RADIO_SetDefaultSkin(RADIO_SKIN_FLEX);
- /* 创建一个对话框 */
- hDlg = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0);
- while (1)
- {
- WM_SendMessageNoPara(WM_HBKWIN, WM_UPDATE); (7)
- GUI_Delay(500);
- }
-
- }
1. 桌面窗口的回调函数(桌面窗口是emWin最底层的窗口,是初始化后自动创建的)。
2. 重绘消息,用于实现桌面颜色的重绘。
3. 这个是自定义消息,功能和上面34.1小节讲的一样。
4. 使能窗口使用内存设备,这样可以有效的避免闪烁。
5. 通过函数WM_SetCallback来设置桌面窗口的回调函数。
6. 函数WM_SetDesktopColor可以实现桌面窗口颜色的自动重绘。
7. 这里要尤其的注意,系统消息由GUI库发送。请勿从用户应用程序向窗口或小工具发送系统定义的消息。要不会出现异常的。也就是说我们不能发WM_PAINT消息,但是可以发自定义消息,进而来触发重绘。
这个DEMO的功能就是每隔500ms改变一次桌面窗口的颜色,实际显示效果如下:
34.3 官方WM_Redraw.c实例
这个DEMO在模拟器中的位置:
下面我们将这个代码分析一下:
- #include "GUI.h"
- #include "WM.h"
-
- /*******************************************************************
- *
- * static code
- *
- ********************************************************************
- */
- /*******************************************************************
- *
- * _cbBkWindow
- */
- static void _cbBkWindow(WM_MESSAGE* pMsg) {(1)
- switch (pMsg->MsgId) {
- case WM_PAINT:
- GUI_ClearRect(0, 50, 319, 239);(2)
- default:
- WM_DefaultProc(pMsg);
- }
- }
-
- /*******************************************************************
- *
- * _cbWindow
- */
- static void _cbWindow(WM_MESSAGE* pMsg) {(3)
- GUI_RECT Rect;
-
- switch (pMsg->MsgId) {
- case WM_PAINT:
- WM_GetInsideRect(&Rect);(4)
- GUI_SetBkColor(GUI_RED);
- GUI_SetColor(GUI_YELLOW);
- GUI_ClearRectEx(&Rect);(5)
- GUI_DrawRectEx(&Rect);
- GUI_SetColor(GUI_BLACK);
- GUI_SetFont(&GUI_Font8x16);
- GUI_DispStringHCenterAt("Foreground window", 75, 40);
- break;
- default:
- WM_DefaultProc(pMsg);
- }
- }
-
- /*******************************************************************
- *
- * _MoveWindow
- */
- static void _MoveWindow(const char* pText) {
- WM_HWIN hWnd;
- int i;
-
- //
- // Create foreground window
- //
- hWnd = WM_CreateWindow(10, 50, 150, 100, WM_CF_SHOW, _cbWindow, 0);(6)
- GUI_Delay(500);
- //
- // Move foreground window
- //
- for (i = 0; i < 40; i++) {
- WM_MoveWindow(hWnd, 2, 2);(7)
- GUI_Delay(10);
- }
- //
- // Show text before deleting window if we have one
- //
- if (pText) {
- GUI_DispStringAt(pText, 5, 50);
- GUI_Delay(2500);
- }
- //
- // Delete foreground window
- //
- WM_DeleteWindow(hWnd);(8)
- WM_Invalidate(WM_HBKWIN);(9)
- GUI_Exec();
- }
-
- /*******************************************************************
- *
- * _DemoRedraw
- */
- static void _DemoRedraw(void) {
- WM_CALLBACK * _cbOldBk;
-
- GUI_SetBkColor(GUI_BLACK);
- GUI_Clear();
- GUI_SetColor(GUI_WHITE);
- GUI_SetFont(&GUI_Font24_ASCII);
- GUI_DispStringHCenterAt("WM_Redraw - Sample", 160, 5);
- GUI_SetFont(&GUI_Font8x16);
- while(1) {
- //
- // Move a window over background
- //
- _MoveWindow("Background has not been redrawn");(10)
- //
- // Clear background
- //
- GUI_ClearRect(0, 50, 319, 239);
- GUI_Delay(1000);
- //
- // Set callback for background window
- //
- _cbOldBk = WM_SetCallback(WM_HBKWIN, _cbBkWindow);(11)
- //
- // Move a window over background
- //
- _MoveWindow("Background has been redrawn");
- //
- // Delete callback for Background window
- //
- WM_SetCallback(WM_HBKWIN, _cbOldBk);(12)
- }
- }
-
- /*********************************************************************
- *
- * Public code
- *
- **********************************************************************
- */
- /*********************************************************************
- *
- * MainTask
- */
- void MainTask(void) {
- GUI_Init();
- _DemoRedraw();
- }
1. 桌面窗口回调函数。
2. 在回调函数的WM_PAINT消息中清除一块区域。
3. 另一个创建窗口的回调函数。
4. 函数WM_GetInsideRect返回客户区的坐标,该区域由活动小工具尺寸减去边界尺寸确定。此函数向活动窗口发送一条消息,检索内部矩形。如果小工具不处理此消息(也即意味着小工具没有边界),则需使用WM_GetClientRect函数计算出矩形。结果通过窗口坐标给出。也即,GUI_RECT结构中的x0和y0相当于x和y的边界尺寸,x1和y1相当于窗口尺寸减去边界尺寸-1。
5. 调用函数GUI_ClearRectEx清除部分区域。
6. 函数WM_CreateWindow中每个参数的含义需要大家详细研究下官方手册,这里就不做解释了。
7. 通过函数WM_MoveWindow()实现窗口位置的移动,注意这里移动的是相对距离。
8. 删除这个创建的窗口。
9. 通过函数WM_Invalidate(WM_HBKWIN)使得桌面窗口无效,然后调用函数GUI_Exec()就会执行重绘。
10. 执行第一种情况:移动窗口,但是不做桌面窗口的重绘。
11. 给桌面窗口设置专门的回调函数。
12. 执行第二种情况:移动窗口,并执行桌面窗口的重绘。
这个演示实例的主要功能就是两种情况,一种是演示:移动窗口的情况下,但是不做桌面窗口的重绘。另一种是:移动窗口,并执行桌面窗口的重绘。通过这两种情况的演示可以帮助大家对回调函数有一个更好的认识。
第一幅:没有执行桌面回调函数的情况:
第二幅:执行桌面回调函数的情况:
34.4 总结
本期教程就跟大家讲这么多,希望通过本期教程让大家对窗口管理器有更好的认识,不过还需要大家在模拟器或者开发板上面多做这方面的练习。