DuiLib核心的大体结构图如下:
分为几个大部分:
-
控件
-
容器(本质也是控件)
-
UI构建解析器(XML解析)
-
窗体管理器(消息循环,消息映射,消息处理,窗口管理等)
-
渲染引擎
DuiLib 消息循环剖析
DuiLib的消息循环非常灵活,但不熟悉的可能会觉得非常混乱,不知道该如何下手。所以,我总结了下DuiLib的各种消息响应的方式,帮助大家理解DuiLib和加快开发速度。
其消息处理架构较为灵活,基本上在消息能过滤到的地方,都给出了扩展接口。
看了DuiLib入门教程后,对消息机制的处理有些模糊,为了屏蔽Esc按键,都花了大半天的时间。究其原因,是因为对DuiLib消息过滤不了解。
你至少应该看过上面提及的那篇入门教程,看过一些DuiLib的代码,但可能没看懂,那么这篇文章会给你指点迷津。
Win32消息路由如下:
-
消息产生。
-
系统将消息排列到其应该排放的线程消息队列中。
-
线程中的消息循环调用GetMessage(or PeekMessage)获取消息。
-
传送消息TranslateMessage and DispatchMessage to 窗口过程(Windows procedure)。
-
在窗口过程里进行消息处理
我们看到消息经过几个步骤,DuiLib架构可以让你在某些步骤间进行消息过滤。首先,第1、2和3步骤,DuiLib并不关心。DuiLib对消息处理集中在CPaintManagerUI类中(也就是上面提到的窗体管理器)。DuiLib在发送到窗口过程的前和后都进行了消息过滤。
DuiLib的消息渠,也就是所谓的消息循环在CPaintManagerUI::MessageLoop()或者CWindowWnd::ShowModal()中实现。俩套代码的核心基本一致,以MessageLoop为例:
void CPaintManagerUI::MessageLoop()
{
MSG msg = { 0 };
while( ::GetMessage(&msg, NULL, 0, 0) ) {
// CPaintManagerUI::TranslateMessage进行消息过滤
if( !CPaintManagerUI::TranslateMessage(&msg) ) {
::TranslateMessage(&msg);
try{
::DispatchMessage(&msg);
} catch(...) {
DUITRACE(_T("EXCEPTION: %s(%d)\n"), __FILET__, __LINE__);
#ifdef _DEBUG
throw "CPaintManagerUI::MessageLoop";
#endif
}
}
}
}
3和4之间,DuiLib调用CPaintManagerUI::TranslateMessage做了过滤,类似MFC的PreTranlateMessage。
想象一下,如果不使用这套消息循环代码,我们如何能做到在消息发送到窗口过程前进行常规过滤(Hook等拦截技术除外)?答案肯定是做不到。因为那段循环 代码你是无法控制的。CPaintManagerUI::TranslateMessage将无法被调用,所以,可以看到DuiLib中几乎所有的 demo在创建玩消息后,都调用了这俩个消息循环函数。下面是TranslateMessage代码: