在如上的代码中我们可以看到, 当UCGUI中有一个独立的窗体退出后, _cb会被清为0, 此时退出GUI窗口LOOP.即结束了UCGUI窗口消息处理.其实, GUI_MessageBox弹出的消息框其实也是一种对话框,在这里我们就可以发觉UCGUI的窗口支持系统还不是非常的完备, 我们期待的结果是, 点击对话框的OK, 弹出消息框,GUI_EndDialog关闭掉对话框, 消息框继续有反应, 如果没有在OK按钮中调用GUI_EndDialog关闭对话框,则对话框与消息框都要能够正常反应.
关于这个问题的解决, 我想还要进一步了解UCGUI窗口处理的细节.
三.寻找问题的解决办法
在我们发现这个问题, 我们已经粗步分析了, 问题不是出在我们编写程序上, 而上UCGUI的内部, 那么要解决这个问题,我们就要进一步了解UCGUI的窗口体系.其实换一句话说, 在嵌入式应用中, 窗口的强大直接决定到GUI系统的体积大小,并不是所有的情况都要有这种支持, 也不一定说是UCGUI的BUG, 当然我们希望在下一版本不再有这个问题.
下面是详细分析:
1. 对话框
void MainTask(void) {
GUI_Init();
WM_SetDesktopColor(GUI_RED);
WM_SetCreateFlags(WM_CF_MEMDEV);
GUI_ExecDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate),&_cbCallback, 0, 0, 0);
}
上面是我们创建对话框的程序, 是我们编写的代码, 具体看GUI_ExecDialogBox()这个函数代码如下,它主要用以下两个作用:
[1].创建对话框中的的所有子窗体.
[2].进入消息LOOP, 收集并转发消息到对应窗体进行处理. 消息如WM_TOUCH及WM_KEY,这些消息被分发到对话框中各子窗体中去处理, 要理解如下的尽, 父窗体(对话框)之所以能够处理其上子控件消息, 全都是因为子控件在传递,父窗体中对子窗体的消息进行处理, 也可以不处理, 我们编程者要处理时, 则要清楚哪些消息是可以处理的, 不然无法编写程序,所以子窗体中的消息一直都在往父窗体中发送, 与父窗体有无处理没有关系.
int GUI_ExecDialogBox(const GUI_WIDGET_CREATE_INFO*paWidget,
int NumWidgets, WM_CALLBACK* cb, WM_HWIN hParent,
int x0, int y0)
{
_cb = cb;
GUI_CreateDialogBox(paWidget, NumWidgets, _cbDialog, hParent, x0,y0);
while (_cb) {
if (!GUI_Exec())
GUI_X_ExecIdle();
}
return _r;
}
2. 消息框
其实消息框本身就是一个只含静态文框及OK按钮的对话框, 在对话框的WM_NOTIFY_PARENT消息中弹出消息框:
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch (NCode) {
case WM_NOTIFICATION_RELEASED:
if (Id == GUI_ID_OK) {
GUI_EndDialog(hWin, 0);
}
if (Id == GUI_ID_CANCEL) {
GUI_EndDialog(hWin, 1);
}
break;
}
break;
在关闭对话框之前弹出一个消息框, 当我们都不点击消息框与对话框的OK按钮来结束时, 他们都有反应也可以前后台切换,不存在什么问题. 问题就出在关闭其中一个后, 其它的一个也无任何的反应.
这个原因, 在上面有过过粗步的分析, 但没有进入到UCGUI的实现机制内, 现在我们来看一下.
_cb = cb;
while (_cb) {
if (!GUI_Exec())
GUI_X_ExecIdle();
}
这个LOOP, 其实它就是类似我们非常熟悉的WIN下面的消息LOOP, 其原理是一致的. _cb是什么东西呢?这里我们可以看到, 它其实就是对话框的窗口消息处理函数, 这里面有一个判断, 就是_cb非空时, 才进行消息LOOP,_cb在Dialog.c中的定义如下:
static WM_CALLBACK* _cb;
_cb是一个全局变量! 我们程序中创建对话框与弹出消息框时两次调用了GUI_ExecDialogBox,后一次的_cb将会把前面的值冲掉, 我们程序中, 可以知道它是消息框的窗口消息处理函数地址. 由引可知道谁在后面调用,则另外一个对话框的窗口消息处理函数根本就是无用的, 它的消息其实是被后来创建的对话框消息处理函数所处理的.
在while中有判断, 那么证明_cb是在GUI_Exec所产生的调用中有使用的.进一步看, 可以看到,调用的其实是如下面的箭头方向所指, 一步一步深入的, 其中最明显的一点就是,窗口消息处理函数是在WM_SendMessage中通过函数指针的调用中, 注意[]内部的就是真正被调用来处理消息的函数,它是是将消息一步一步的传到真正要处理此消息的窗体中, 在这里其实就是后面弹出的消息框窗体.
GUI_Exec--->GUI_Exec1-->WM_Exec--->WM_Exec1-->WM_HandlePID-->WM_SendMessage-->(*pWin->cb)(pMsg)[_FRAMEWIN_Callback]-->_OnTouch()--->(*cb)(pMsg)[_cbDialog]--(*_cb)(pMsg)[_MESSAGEBOX_cbCallback]
WM_HandlePID()----------专门处理MOUSE消息的函数.
WM_SendMessage()--------基层的分派消息的函数, 决定谁应该被调来来处理消息.
这里面有些人会提出一个问题, 为什么消息框与对话框的消息都在后来创建的消息处理函数里面处理而不会引发什么问题呢?
是的, 表面上看去, 消息框与对话框都好好的, 没什么异常, 但其实如果你在对话框中进行过消息的处理,那么你就可以很清楚的看到这些消息是从来不会发生的, 即使你在它的消息处理函数里下断点它也不会有任何中断.
至于其它的一些常用的消息的处理, 对话框与消息没有什么区别, 最重要的消息就是重画, 重画的时候,比如消息框与对话框有重叠的话, 当进行窗口前后切换将其中一个切换到前面来时, 会产生重画消息.这样就会重新计算一次该画到屏慕上的东西, 不光要发关重画消息到各窗口, 还会将整个屏慕的东西都重新计算一次, 并画出来.这一点还是很复杂的, 须要进一步学习.是GUI图形的一个难点和重点. 以后再详细分析.
进行到这里, 我们就可以比较明白的知道, 在点击OK后, 无论是消息框还是对话框, 哪一个先被关掉,都会掉用下面的GUI_EndDialog. 这里, _cb被清为零, 也就意味着消息LOOP到此结束了.所以后面另外一个未被关掉的当然不会再有任何响应了.
void GUI_EndDialog(WM_HWIN hWin, int r) {
_cb = NULL;
_r = r;
WM_DeleteWindow(hWin);
}
原因我们分析出来了. 现在我们要解决这个问题, 那还差一大步, 还有很多问题要进一步弄清, 为什么UCGUI是这样的机制.要如何解决.将会在下一步仔细学习分析.
楼主再仔细读一下我的分析, 结合实际自己也来分析一下, 问题虽然小, 但其实隐藏着的问题不小.你的所言其实还是没有理解清楚问题, 因为你所说的HIDE对话框. 其实没有点着问题实际,我们现在所讲的是UCGUI对于多个独立窗体的消息处理支持. UCGUI不完善.对这个目前没有支持.你要深入到这一点来理解问题.
再仔细看下我的分析. 有什么问题再提, 结合实际, 进行源码调试, 对于问题会有更多的了解....
四. 进一步分析找到解决办*.
点击对话框的OK按钮后, 其实这个时候,由于消息框是对话框后弹出来的,那么这个消息框的消息处理函数_MESSAGEBOX_cbCallback则成为_cb的值了,那么以后对话框与消息框的消息处理都是在消息框的_MESSAGEBOX_cbCallback里面处理的,如果你是在点击对话框的OK按扭之后弹出消息框.如下:
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch (NCode) {
case WM_NOTIFICATION_RELEASED:
if (Id == GUI_ID_OK) {
GUI_MessageBox("This text is shown\nin a message box",
"Caption/Title", GUI_MESSAGEBOX_CF_MOVEABLE);
GUI_EndDialog(hWin, 0);
}
if (Id == GUI_ID_CANCEL) {
GUI_EndDialog(hWin, 1);
} |