- UID
- 1029342
- 性别
- 男
|
那么, 程序执行到弹出消息框之前, 消息 WM_NOTIFY_PARENT 都是由对话框的消息处理函数_cbCallback处理的,在弹出消息框之后, 如我们在(二)上面的分析, 就知道以后的消息都是由 消息框的_MESSAGEBOX_cbCallback来处理的,此时, 在消息LOOP中马上又会发现上一次的MOUSE消息, 因为这个点击OK产生的消息还在, 并没有产生新的消息,[说来其实UCGUI中的消息是没有什么队列的, 是接收一个处理一个, 即时处理那种, 这样就简单了很多,]那么又一次进行WM_NOTIFY_PARENT的GUI_ID_OK按钮的处理,只不过这个处理是在消息框的_MESSAGEBOX_cbCallback函数中进行的,在这个函数里面默认的对于GUI_ID_OK的处理就是调用GUI_EndDialog(hWin, 1); 一旦调用这个函数,那么产生的结果就如同先前分析的, 会导致WM_DeleteWindow的调用, 而将_cb的值清为空, 并清除hWin及其所有了窗体.从而结束了LOOP消息处理.所以, 我们可以看到, 在点击对话框的OK后, 弹出消息框, 之后即使我们不调用清除对话框的函数, 什么也不做.也会导到消息LOOP结束, 退出所有窗口消息的处理.
其实, 须要进一步说明的是, 在UCGUI中, 似乎在设计时只是支持单窗口的消息处理, 如果要多窗口的支持,可以如同示例中一样, 启用多任务支持, 不然, 在单任务下, 一个MainTask中只能支持一个独立窗体, 但是,显然我们如果只是为了要弹出一个消息框而启动一个任务, 这未免太不实际.
解决的办*, 还是有的, 那就是了解UCGUI, 自己来修改. 可以如下做-------
[如上创建一对话框及消息框, 对话框与消息框即为如下所讲的外部独立窗体]
1. 经过详细的分析, 认识到在消息处理中, 创建一个独立窗体,则其窗口消息处理函数就会成为整个UCGUI中的消息的外部接收口, 用户所能处理到所有消息均在此处接收到.
2. 如果在后来在创建独立窗体, 则后来的窗口的消息处理函数代替了先前创建的窗口的消息处理. 那么, 如果不使它替代,而是用一个数组将所有消息处理函数都存放起来,然后在内部将消息往外传的地方(即外部独立窗口消息函数被调用处)修改成调用所有非空的外部独立窗口消息处量函数(而不是单个).这样就可以达到每个独立窗口消息处理函数都被调用,各自独立运行. 但要注意和解决的问题是, 消息该如何分配到各独立窗口.
3.在清除独立窗体时, 只是将此独立窗体对应的消息处理函数清零, 并清除该窗体及其的所有子窗体. 使其不再处理消息.
那么. 我们在点击OK关闭对话框, 也就是清除对话框并让其退出消息接收. 对于弹出的消息框,我们希望它作为一个新的独立窗体而进入窗体消息接收与处理. 就达到了我们的目的.
这是理论上的分析. 我将把实际修改后的东东也发上来, 做一示例.
五. 对UCGUI源码做出部分修改以实现多独立窗口支持.
[2005-6-30 2:30]
在第三节当中, 我们通过进一步的分析源码, 大致找到了解决问题的办*, 但那只是理论上的指导,实际上的修改其实还会带来其它的很多问题, 因为在UCGUI体系中, 对其源码作出改动, 一定都会影响到其它的地方,现在我们就实际的源码修改说明几点要注意的问题:
1、将原来的_cb一个变量, 修改成一个结构为new_cb的结构数组,有10个元素,
/static WM_CALLBACK* _cb;
typedef struct win_cb{
WM_CALLBACK* _cb;
WM_HWIN hwin; /_cb消息函数对应的窗口..
WM_HWIN hclient;/_cb消息函数对应的窗体窗户区...
}new_cb,*lpnew_cb;
static int dialog_pos = 0;/在数组中当前可用作存窗体消息函数的元素.
static int MAX_DIALOG = 10;/最多可支持打开的独立窗口数, 其实可以改成支持无数个,但这里作简单处理
int checkHasDialog(); /检查是否还有独立窗体存在, 以决定是否退出消息LOOP...
int getDialogIndex(lpnew_cb lp_cb);/获取当前可用于存放独立窗体的位置索引,创建新独立窗体时调用.
static new_cb _cb[10]; /独立窗口数组创建一个新的独立窗体, 将此窗体加入到独立窗体数组当/中时,必须注意几个问题,在如下的新旧代码对比中说明:
/新修改后的创建对话框的函数...
int GUI_ExecDialogBox(const GUI_WIDGET_CREATE_INFO* paWidget,
int NumWidgets, WM_CALLBACK* cb, WM_HWIN hParent,
int x0, int y0)
{
/ _cb = cb;
dialog_pos = getDialogIndex(_cb);
if(dialog_pos != -1) _cb[dialog_pos]._cb = cb;
else return _r;
GUI_CreateDialogBox(paWidget, NumWidgets, _cbDialog, hParent, x0,y0);
/ while (_cb) {
return _r;
}
/旧的创建对话框的函数...
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;
}
WM_HWIN GUI_CreateDialogBox(const GUI_WIDGET_CREATE_INFO* paWidget,int NumWidgets, WM_CALLBACK* cb, WM_HWIN hParent,
int x0, int y0)
{
WM_HWIN hDialog =paWidget->pfCreateIndirect(paWidget, hParent, x0,y0, cb);
WM_HWIN hDialogClient = WM_GetClientWindow(hDialog);
_cb[dialog_pos].hwin = hDialog;
_cb[dialog_pos ].hclient = hDialogClient;/加到GUI_CreateDialogBox中的,其余不变...
WIDGET_OrState(hDialog, paWidget->Flags);
........
}
[1]、getDialogIndex(_cb),创建新的独立窗体前,首先就要在独立窗体数组中查找空位置,如果独立窗体已达最大数,则不可再加入独立窗体,这里我做的是简单处理,没有用到动态内存分配,将独立窗体数组扩大,主要是因为是演示,读者自己可以试度支持无限独立窗体。
[2]、_cb[dialog_pos]._cb = cb独立窗口的窗口消息处理函数必须在GUI_CreateDialogBox之前赋值,因为在GUI_CreateDialogBox中就会用到这个窗口消息处理函数。
[3]、_cb[dialog_pos]中的hwin等窗口句柄的处理加到创建对话框当中,千万不要在创建完对话框后再根据返回的对话框句柄初始化,因为在创建对话的子窗体时就会调用到对话框消息处理函数,如果hwin此时未初始化,则在_cDialog()中就无*分发消息,这样对话框中的子窗体都无*正确显示的。
[4]、GUI_ExecDialogBox中的窗口消息LOOP被注掉了,改为放到MainTask中调用,这一点与我们WIN下面就很类似了,而且事实证明,这个改进是非常有用的,因为当我们把窗体都创建了之后,再来执行消息LOOP的话,可以避免前面创建独立窗体的消息LOOP被后面创建的消息LOOP中断的作用,只有后面的窗体关闭掉后,才会返回到先前的窗体消息LOOP当中,在我们一直谈论的话题当中,点OK按钮弹出一个消息框,这个流程其实是这样的:
------点击OK的消息处理流程:在没有弹出消息框之前,是在一直进行着对话框的窗口消息LOOP,当点击对话框上的OK按扭时(消息LOOP中的点击处理在WM_HandlePID()进行),WM_HandlePID()调用WM_SendMessage向OK按扭窗体发送WM_TOUCH消息,再到BUTTON的消息处理函数_BUTTON_Callback中处理WM_TOUCH(_OnTouch)消息,然后OK按钮中还要调用WM_NotifyParent转发WM_NOTIFY_PARENT消息到父窗体,此时父窗体才开如执行弹出消息框的代码,所以此时我们可以了解到,如果窗口消息LOOP在GUI_ExecDialogBox当中进行的话,那么表明原来的对话框中进行的窗口消息LOOP就会被新创建的消息框挂起来了,一直要等到消息框中的窗口消息LOOP结束返回为止,这当中会造成在对话框窗口消息LOOP中的WM_LOCK调用后,WM_UNLOCK的调用一直要等到消息框的窗口消息LOOP结束为止。 |
|