μC/GUI 为窗口和窗口对象(控件)提供的回调机制实质是一个事件驱动系统。正如在大多数视窗系统中一样,原则是控制流程不只是从用户程序到图形系统(用户程序调用图形系统函数来更新窗口),而且可以从用户程序到图形系统,同时也从图形系统回到用户程序,意思是图形系统也可以调用用户程序提供的回调函数来达到更新窗口的目的。这种机制——常常表现好莱坞法则的特点(“不要打电话给我们,我们会打电话给你们!”)——主要是视窗管理器为了启动窗口重绘的需要。与传统程序比较有差异,但它使对视窗管理器的无效逻辑开发成为可能。
其原型函数原型void callback(WM_MESSAGE* pMsg);
其中WM_MESSAGE结构体原型:
struct WM_MESSAGE {
int MsgId; /* type of message */ //可以发现UC/GUI中的ID的类型为int
WM_HWIN hWin; /* Destination window */ //实际上hWin的类型为signed int 后面会发现hWin指的是创建的一个窗体
WM_HWIN hWinSrc; /* Source window */ //同样 说明这些只是一些数字 hWinSrc指的是hWin中的控件的ID号
union { // 下面你会看出共同体Data中存放的是hWinSrc控件对应的消息类型
const void* p; /* Some messages need more info ... Pointer is declared "const" because some systems (M16C) have 4 byte const, byte 2 byte default ptrs */
int v;
GUI_COLOR Color;
} Data;
};
回调函数的执行行为依赖于它收到的消息类型。系统中给出的消息类型:
MsgId 元素使用的消息类型
WM_PAINT 重绘窗口(因为内容至少部分无效)。
WM_CREATE 一个窗口创建后产即发送。
WM_DELETE 告诉窗口释放它的数据结构(如果有的话),然后它将会被删除。
WM_SIZE 当一个窗口的大小改变后发送到它。
WM_MOVE 当一个窗口移动后发送到它。
WM_SHOW 当一个窗口收到显示命令后发送到它。
WM_HIDE 当一个窗口收到隐藏命令后发送到它。
WM_TOUCH 触摸屏消息。
应用程序可以为它自己的用途定义附加消息。为了保证它们使用的消息ID 不会与μC/GUI
使用的消息ID 同名,用户定义的消息的编号以WM_USER 为开始。你应该像下面所展示的一样
定义你自己的消息:
#define MY_MESSAGE_AAA WM_USER+0
#define MY_MESSAGE_BBB WM_USER+1
在这里
这是说明书给出的回调机制
下面分析一下典型的数字面板输入机制:
现在主函数中加载 hNumPad = GUI_CreateDialogBox(_aDialogNumPad,
GUI_COUNTOF(_aDialogNumPad),
_cbDialogNumPad, WM_HBKWIN, 0, 0); /* Create the numpad dialog *///该函数产生了数字面板
//对应回调函数_cbDialogNumPad
static void _cbDialogNumPad(WM_MESSAGE * pMsg) {
GUI_RECT r;
int i, NCode, Id, Pressed = 0;
WM_HWIN hDlg, hItem;
hDlg = pMsg->hWin; // 获得窗口的句柄
switch (pMsg->MsgId) { //根据窗口的消息类型执行相应的内容
case WM_PAINT: //窗口重绘 此处绘出了面板的边框
WM_GetClientRect(&r);
GUI_SetColor(GUI_RED);
GUI_DrawRect(r.x0, r.y0, r.x1, r.y1); /* Draw rectangle around it */
/* Draw the bright sides */
GUI_SetColor(0xffffff);
GUI_DrawHLine(r.y0 + 1, r.x0 + 1, r.x1 - 2); /* Draw top line */
GUI_DrawVLine(r.x0 + 1, r.y0 + 1, r.y1 - 2);
/* Draw the dark sides */
GUI_SetColor(0x555555);
GUI_DrawHLine(r.y1-1, r.x0 + 1, r.x1 - 1);
GUI_DrawVLine(r.x1-1, r.y0 + 1, r.y1 - 2);
break;
case WM_INIT_DIALOG: //窗口的初始化 控件的各种属性 颜色 文本
for (i = 0; i < GUI_COUNTOF(_aDialogNumPad) - 1; i++) {
hItem = WM_GetDialogItem(hDlg, GUI_ID_USER + i); //返回一个对话框中控件的句柄 根据此句柄 设置控件的属性句柄是根据控件的ID号得到的
BUTTON_SetFocussable(hItem, 0); /* Set all buttons non focussable */
BUTTON_SetBkColor(hItem,0,GUI_BLUE);
switch (i) {
case 13:
BUTTON_SetBitmapEx(hItem, 0, &_bmArrowLeft, 15, 10); /* Set bitmap for arrow left button (unpressed) */
BUTTON_SetBitmapEx(hItem, 1, &_bmArrowLeft, 15, 10); /* Set bitmap for arrow left button (pressed) */
break;
case 14:
BUTTON_SetBitmapEx(hItem, 0, &_bmArrowRight, 15, 10); /* Set bitmap for arrow right button (unpressed) */
BUTTON_SetBitmapEx(hItem, 1, &_bmArrowRight, 15, 10); /* Set bitmap for arrow right button (pressed) */
break;
}
}
hItem = WM_GetDialogItem(hDlg, GUI_ID_USER + 12);
break;
case WM_NOTIFY_PARENT: //通知父窗口控件发生了改变
Id = WM_GetId(pMsg->hWinSrc); /* Id of widget */ // 得到窗口控件的ID号
NCode = pMsg->Data.v; /* Notification code */// 控件的消息类型
switch (NCode) {
case WM_NOTIFICATION_CLICKED:
Pressed = 1;
case WM_NOTIFICATION_RELEASED:
if ((Id >= GUI_ID_USER) && (Id <= (GUI_ID_USER + GUI_COUNTOF(_aDialogNumPad) - 1))) {
int Key;
if (Id < GUI_ID_USER + 11) {
char acBuffer[10];
BUTTON_GetText(pMsg->hWinSrc, acBuffer, sizeof(acBuffer)); /* Get the text of the button */
Key = acBuffer[0];
} else {
Key = _aKey[Id - GUI_ID_USER - 11]; /* Get the text from the array */
}
GUI_SendKeyMsg(Key, Pressed); /* Send a key message to the focussed window */ //很关键的地方点击按钮之后要发送键值
}
break;
}
default:
WM_DefaultProc(pMsg);
}
}
从上面的程序可以看出回调函数工作过程可以归结为如下过程:1.获取窗口的句柄 1.根据窗口的消息类型作出相应的判断:WN_PAINT:窗口的. WM_INIT_DIALOG:初始化窗口控件 要根据控件的ID号得到控件句柄 从而根据句柄 设置控件的各种属性 ;;;;;WM_NOTIFY_PARENT:根据 WM_GetId(pMsg->hWinSrc); 得到变化控件的ID号,根据pMsg->Data.v,得到控件的消息类型 根据不同的控件发送GUI_SendKeyMsg(Key, Pressed); 键值。
文本的内容自会出现在另一个窗口的文本框中