duilib库分析: 消息流程分析
转
看下CWindowWnd类与CPaintManagerUI类是咋进行消息分发的吧.
1. 先看下CPaintManagerUI类的MessageLoop函数:
- void CPaintManagerUI::MessageLoop()
- {
- MSG msg = { 0 };
- while( ::GetMessage(&msg, NULL, 0, 0) ) { // 获取消息
- if( !CPaintManagerUI::TranslateMessage(&msg) ) { // 消息过滤
- ::TranslateMessage(&msg);
- ::DispatchMessage(&msg); // 分发到窗口的消息处理窗口中. 也就是调用CWindowWnd类的__WndProc函数或是__ControlProc函数.
- }
- }
- }
消息第一次会由CPaintManagerUI类的TranslateMessage消息接收到.
2. 调用CWindowWnd::Create创建窗口. 完成以下操作:
1) 如果要子类下Window的控件(就是系统的控件, 而不是duilib的模拟控件), 就设置__ControlProc函数为消息回调函数.
2)不子类化, 就注册窗口类. 此时设置__WndProc为窗口消息处理回调函数.
3)用CreateWindowEx API函数创建窗口.
这里先不看子类化相关的, 我要先看明白标准的窗口创建过程. 这也操作后消息就会分发到__WndProc了,
3. 看下__WndProc函数的定义:
- LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- CWindowWnd* pThis = NULL;
- if( uMsg == WM_NCCREATE ) { // 要在此消息中把类于窗口进行绑定
- LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); // 来自于CreateWindowEx函数的最后一个参数( 也就是CWindowWnd对象指针了 )
- pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
- pThis->m_hWnd = hWnd;
- ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis)); // 设置到窗口的用户数据中
- }
- else {
- pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
- if( uMsg == WM_NCDESTROY && pThis != NULL ) {
- LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam); // 收到窗口能处理到的最后一个消息了, 要进行收尾工作了.
- ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L); // 取消类对象与窗口的绑定关系
- if( pThis->m_bSubclassed ) pThis->Unsubclass();
- pThis->m_hWnd = NULL;
- pThis->OnFinalMessage(hWnd);
- return lRes;
- }
- }
- if( pThis != NULL ) {
- return pThis->HandleMessage(uMsg, wParam, lParam); // 在此调用继承类的消息处理函数
- }
- else {
- return ::DefWindowProc(hWnd, uMsg, wParam, lParam); // 未绑定类对象, 就调用默认的窗口消息处理函数
- }
- }
消息第二次就由__WndProc接收到, 然后再传到CWindowWnd类的HandlerMessage函数中.
3. 看看CWindowWnd类的继承类对于HandlerMessage虚函数的实现.
- LRESULT CMainWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )
- {
- LRESULT lRes = 0; // 消息处理返回值.
- BOOL bHandled = TRUE; // 消息是否要继续往下传.
- switch ( uMsg )
- {
- case WM_CREATE: lRes = OnInitResource( bHandled ); break; // 进行初始化工作. 比如最重要的XML加载解析工作.
- default:
- bHandled = FALSE;
- }
- if ( bHandled )
- {
- return lRes;
- }
- if ( m_pm.MessageHandler( uMsg, wParam, lParam, lRes ) ) // 传给CPaintManagerUI::MessageHandler函数进行具体的控件处理工作
- {
- return lRes;
- }
- return CWindowWnd::HandleMessage( uMsg, wParam, lParam ); // 没处理过的就调用CWindowWnd类的默认消息处理函数吧.
- }
在这里就是用户要按消息进行具体的处理了. 之后要传到CPaintManagerUI类对象的MessageHandler函数. 未处理的消息就要返回给CWindowWnd类的默认消息处理函数来处理了.
4. CPaintManagerUI类的TranslateMessage, MessageHandler函数的内容.
- BOOL CPaintManagerUI::TranslateMessage(const LPMSG pMsg)
- {
- HWND hwndParent = ::GetParent(pMsg->hwnd); // 获取消息接收窗口的父窗口
- UINT uStyle = GetWindowStyle(pMsg->hwnd); // 获取窗口的样式
- LRESULT lRes = 0;
- for( int i = 0; i < m_aPreMessages.GetSize(); i++ ) { // 这个m_aPreMessage保存着CPaintManagerUI类对象.
- CPaintManagerUI* pT = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);
- if( pMsg->hwnd == pT->GetPaintWindow() // 消息是否属于当前CPaintManagerUI绑定的窗口
- || (hwndParent == pT->GetPaintWindow() && ((uStyle & WS_CHILD) != 0)) ) // 消息是否为当前窗口中窗口的消息, (如ActiveX控件 )
- {
- if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return TRUE; // 此时就调用PreMessageHandler过滤函数.
- }
- }
- return FALSE;
- }
m_aPreMessage为静态成员变量, 在CPaintManagerUI::Init进行窗口与此类绑定时添加到此变量中.
5. CPaintManagerUI::PreMessageHandler消息过滤函数.
- BOOL CPaintManagerUI::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/)
- {
- // 遍历当前的消息过滤列表. m_aPreMessageFilter的元素为IMessageFilterUI接口.只一个虚函数MessageHandler.
- // 用户可以添加此接口的继承类变量到m_aPreMessageFilters列表中. ( 调用AddMessageFilter函数实现 )
- for( int i = 0; i < m_aPreMessageFilters.GetSize(); i++ )
- {
- BOOL bHandled = FALSE;
- LRESULT lResult = static_cast<IMessageFilterUI*>(m_aPreMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);
- if( bHandled ) {
- return TRUE;
- }
- }
- // 以下是对几个按键消息的过滤.
- // WM_KEYDOWN 检查是否为VK_TAB键, 要进行控件焦点的移动.
- // WM_SYSCHAR 获取与wParam中的字符加速键匹配的控件, 并激活它.
- // WM_SYSKEYDOWN 生成控件事件( 用TEventUI来模拟 )
- }
5. CPaintManagerUI::MessageHandler函数.
1) 遍历m_aMessageFilters列表中的IMessageFilterUI接口, 并调用MessageHandler函数, 再次进行相关的消息过滤功能.(与上面的m_aPreMessageFilters类似)
2) 在此会处理窗口的WM_PAINT消息. 显示所有控件的外观与状态.
3) 处理鼠标事件, 实现控件激活和相关事件.
4) 处理WM_TIMER消息, 所有控件要用CPaintManagerUI的SetTimer, KillTimer等函数实现计时器功能.
5) 处理CPaintManagerUI类的自定消息, WM_APP + 1与 +2,
WM_APP + 1是用于控件延迟销毁控件对象
WM_APP + 2销毁异步消息的处理.
( 异步控件消息用CPaintManagerUI::SendNotify函数, 把消息对象添加到m_aAsyncNotify列表中, 再PostMessage函数WM_APP + 2 )
5) 其它基本的窗口相关消息的处理.
CPaintManagerUI把DUILIB内部的事件都是用TEventUI结构的形式调用CControlUI类的Event函数来投递的.
duilib库分析: 消息流程分析的更多相关文章
- duilib库分析1.消息流程分析
看下CWindowWnd类与CPaintManagerUI类是咋进行消息分发的吧. 1. 先看下CPaintManagerUI类的MessageLoop函数: void CPaintManagerUI ...
- 前端JS模版库kino.razor - 原理流程分析 - 改进版轮子RazorJs
1.前言 从后台获取数据,在前端JS里面拼接字符串,不累吗?敢不敢找一款前端使使... 现在这种模板库比较多了,我用过的jquery-template .JsRender .听说过的一堆,还有各种MV ...
- 一、SDWebImage分析--库处理流程分析
二.SDWebImage分析--源码具体分析 这阵子看了SDWebImage的实现跟源代码.也看了下网上的一些总结. 这里我自己画了个流程图来辅助理解下SDWebImage这个库的实现流程.相信也是有 ...
- duilib库分析4.第二篇UIBase
DUiLib 源码分析 ——以UiLib 1.01版为分析目标 ——colin3dmax 分析于2011-6-16 19:44------------------------------------- ...
- Android之 MTP框架和流程分析
概要 本文的目的是介绍Android系统中MTP的一些相关知识.主要的内容包括:第1部分 MTP简介 对Mtp协议进行简单的介绍.第2部分 MTP框架 介绍 ...
- Android5 Zygote 与 SystemServer 启动流程分析
Android5 Zygote 与 SystemServer 启动流程分析 Android5 Zygote 与 SystemServer 启动流程分析 前言 zygote 进程 解析 zygoterc ...
- openstack之虚拟机创建流程分析
这篇博文静静的呆在草稿箱大半年了.假设不是由于某些原因被问到,以及由于忽略它而导致的损失,否则我也不知道什么时候会将它完毕.感谢这段时间经历的挫折,让我知道不足.希望你能给我更大的决心! 本文试图具体 ...
- VLC架构及流程分析
0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...
- 报时机器人的rasa shell执行流程分析
本文以报时机器人为载体,介绍了报时机器人的对话能力范围.配置文件功能和训练和运行命令,重点介绍了rasa shell命令启动后的程序执行过程. 一.报时机器人项目结构 1.对话能力范围 (1)能够 ...
随机推荐
- Sqli-labs less 40
Less-40 本关的sql语句为SELECT * FROM users WHERE id=('$id') LIMIT 0,1 我们根据sql语句构造以下的payload: http://127.0. ...
- Webpack教程一
比较 如果你熟悉原来一系列的构建工具,grunt或者gulp之类的,这里有一篇webpack和他们比较的文章可以读一读. Webpack Compared 安装 先装好node和npm,因为webpa ...
- java集合TreeMap应用---求一个字符串中,每一个字母出现的次数
package cn.itcast.p1.map.test; import java.util.Iterator; import java.util.Map; import java.util.Tre ...
- CodeIgniter 错误: In order to use the Session class you are required to set an encryption key
CodeIgniter SESSION 第一次用 session 遇到这个错误 , 说是要加一个密钥才可以使用,加就加吧, 打开 config.php 找到以下代码 /*|------------- ...
- UVALive 6187 Never Wait for Weights 带权并查集
题意:每次给出每两个数之间的大小差值.在给出关系的过程中插入询问:数a和数b的差值,若不能确定,输出UNKNOWN 解法:相对大小关系的处理:并查集 1.给出两点的相对大小关系后,找到两个点的根节点, ...
- poj 2349(最小生成树应用)
题目链接:http://poj.org/problem?id=2349 思路:由于有S个专门的通道,我们可以先求一次最小生成树,然后对于最小生成树上的边从大到小排序,前S-1条边用S-1个卫星通道连接 ...
- Spark源码分析(二)-SparkContext创建
原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3872785.html SparkContext是应用启动时创建的Spark上下文对象,是一个重要的入口 ...
- AA投资
AA投资创建于2015年,总部位于北京,创始人成妙绮和王浩泽,专注于天使轮的技术创新驱动的TMT项目投资. 投资方向 AA投资是一家2015年才成立的风险投资机构,专注于种子轮.天使轮.Pre-A轮的 ...
- Python十分钟学会
初试牛刀 假设你希望学习Python这门语言,却苦于找不到一个简短而全面的入门教程.那么本教程将花费十分钟的时间带你走入Python的大门.本文的内容介于教程(Toturial)和速查手册(Cheat ...
- # 图解TCP/IP读书笔记(五)
第五章.IP协议相关技术 IP旨在让最终目标主机收到数据包,但是在这一过程中仅仅有IP是无法实现通信的,因此还有需要作为为IP的辅助的各种协议支持. 协议 作用 特点 DNS(Domain Name ...