第34章
窗口管理器实例(一)
为了帮助大家更好的理解窗口管理器的回调和消息机制,本期教程专门做了三个相关的例子,帮助大家更好的理解。
34. 1 用户自定义消息类型实例
34. 2 桌面窗口回调函数实例
34. 3 官方WM_Redraw.c实例
34. 4 总结
34.1
用户自定义消息类型实例
这里用上期教程所介绍的自定义消息类型做一个实例。代码跟上期教程的三个实例类似。实现源码如下(可以直接将代码复制到模拟器或者开发板上面运行)。
#include
#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)
GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW};
static char ucBackColor;
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}
};
void PaintDialog(WM_MESSAGE * pMsg)
{
WM_HWIN hWin = pMsg->hWin;
GUI_SetBkColor(_acColor[ucBackColor]);
GUI_Clear();
}
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;
}
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);
}
}
void MainTask(void)
{
WM_HWIN hDlg;
GUI_Init();
WM_SetDesktopColor(GUI_BLUE);
WM_SetCreateFlags(WM_CF_MEMDEV);
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
#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
GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW};
static char ucBackColor;
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}
};
void PaintDialog(WM_MESSAGE * pMsg)
{
WM_HWIN hWin = pMsg->hWin;
//
GUI_SetBkColor(_acColor[ucBackColor]);
//
GUI_Clear();
}
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;
}
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);
}
}
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);
}
}
void MainTask(void)
{
WM_HWIN hDlg;
WM_SetCreateFlags(WM_CF_MEMDEV); (4)
GUI_Init();
WM_SetCallback(WM_HBKWIN, _cbBkWindow);(5)
//WM_SetDesktopColor(GUI_BLUE); (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 void _cbBkWindow(WM_MESSAGE* pMsg) {(1)
switch (pMsg->MsgId) {
case WM_PAINT:
GUI_ClearRect(0, 50, 319, 239);(2)
default:
WM_DefaultProc(pMsg);
}
}
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);
}
}
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();
}
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)
}
}
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
总结
本期教程就跟大家讲这么多,希望通过本期教程让大家对窗口管理器有更好的认识,不过还需要大家在模拟器或者开发板上面多做这方面的练习。