教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429
为了帮助大家更好的理解窗口管理器的回调函数和消息机制,本章教程专门做了两个相关的例子,帮助大家更好的理解。
43.1 初学者重要提示
43.2 用户自定义消息类型实例
43.3 桌面窗口回调函数实例
43.4 总结
下图是英文版手册里面API函数的位置:
第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的使用,学会了这个函数基本就学会了自定义消息的实现:
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更新一次对话框的客户区背景色:
这个例子为大家讲解如何给桌面窗口配置回调函数。实现源码如下(可以直接将代码复制到模拟器或者开发板上面运行)。
#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);
}
}
另外,测试中还发现一点,如果用户将函数WM_SetCreateFlags(WM_CF_MEMDEV)放在GUI_Init前面,桌面窗口也是可以自动重绘的,这样就可以不需要使用WM_SetCallback来设置桌面窗口回调函数或者使用函数WM_SetDesktopColor(GUI_BLUE),不过重绘的颜色固定为灰色。
----------------------------
这个程序的显示效果如下(分辨率480*272):
用户可以拖动这个窗口,鼠标点击到标题栏就可以拖动了,跟操作电脑端软件是一样的:
如果不设置桌面窗口回调函数,且函数WM_SetCreateFlags(WM_CF_MEMDEV)没有放在GUI_Init前面调用,那么拖动窗口的话,显示效果就是这个样子的:
显示成这个样子是因为桌面窗口没有执行重绘,导致拖动对话框的时候一直有上次显示的残影。
本章节就跟大家讲这么多,希望通过本章教程让大家对窗口管理器有更好的认识,不过还需要大家在模拟器或者开发板上面多做这方面的练习,将其它的窗口管理器API函数也调用测试下。