duilib界面库消息流程分析

标签: 界面库 duilib
31人阅读 评论(0) 收藏 举报
分类:

对照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创建窗口

Create中主要完成以下操作:

  • 如果要子类下Window的控件(就是系统的控件, 而不是duilib的模拟控件), 就设置__ControlProc函数为消息回调函数.
  • 不子类化, 就注册窗口类. 此时设置__WndProc为窗口消息处理回调函数.
  • 用CreateWindowEx API函数创建窗口.

注:
__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 );  //进行初始化工作. 比如最重要的XML加载解析工作. 
        break;  
    default:  
        bHandled  = FALSE;  
        break;
    }  

    if ( bHandled )  
    {  
        return lRes;  
    }  

    //传给CPaintManagerUI::MessageHandler函数进行具体的控件处理工作  
    if ( m_pm.MessageHandler( uMsg, wParam, lParam, lRes ) )    
    {  
        return lRes;  
    }  

    //没处理过的就调用CWindowWnd类的默认消息处理函数吧. 
    return CWindowWnd::HandleMessage( uMsg, wParam, lParam );   
}

在这里就是用户要按消息进行具体的处理了. 之后要传到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来模拟 )  
}

6. 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 )

  6. 其它基本的窗口相关消息的处理.
    CPaintManagerUI把DUILIB内部的事件都是用TEventUI结构的形式调用CControlUI类的Event函数来投递的.

查看评论

Duilib界面库使用简介

Duilib简介 windows下一款非常好的界面库,实现了UI和逻辑代码的分离,详细介绍百度即可。 使用步骤 如何下载编译duilib我就不说了,github上有编译好的,这里假设你已经有了d...
  • rankun1
  • rankun1
  • 2016-09-07 16:23:39
  • 2135

Duilib消息处理流程图解

要想熟练运用Duilib,熟悉他的消息处理机制是必须的。 网上找了一篇Duilib消息处理剖析,http://blog.csdn.net/rankun1/article/details/5409...
  • rankun1
  • rankun1
  • 2017-01-10 10:00:33
  • 437

初识Duilib界面库

国内首个开源 的directui 界面库,开放,共享,惠众,共赢,遵循bsd协议,可以免费用于商业项目,目前支持Windows 32 、Window CE、Mobile等平台。Duilib 是一款强大...
  • wangshubo1989
  • wangshubo1989
  • 2015-09-02 16:42:51
  • 2131

国内首个directui开源界面库---Duilib

来自:http://www.oschina.net/p/duilib 国内首个开源 的directui 界面库,开放,共享,惠众,共赢,遵循bsd协议,可以免费用于商业项目,目前支持Window...
  • shanzhizi
  • shanzhizi
  • 2013-12-23 15:05:28
  • 3408

Duilib界面库入门笔记(一)

最近需要写一个界面,要用到duilib这个界面库,大家懂的,作为一个新手只能求助度娘了!然而这个界面库已经停止更新,文档也是非常的少,我只能自己慢慢体会。因此我把自己的学习笔记写下来,希望能对要入门的...
  • czhhxx
  • czhhxx
  • 2016-07-30 12:46:17
  • 527

C++轻量级界面库DuiLib简介(二)—使用DuiLib

书接上文。 前面我们已经建立好test.xml文件了,现在要做的是把刚建好的xml文件和所用到的图标文件打包形成一个压缩包(test.zip)。在VS 编译器中导入这个test.zip的资源。我这里最...
  • u010721235
  • u010721235
  • 2016-07-04 16:08:00
  • 942

sciter2-界面库及demo(比duilib还好用的界面库)

  • 2013年06月27日 16:19
  • 10.06MB
  • 下载

Dui lib开源界面库

  • 2012年07月10日 11:34
  • 2.7MB
  • 下载

duilib 消息流程

消息循环小探:     在程序中如果想要处理某消息,可以在GetMessage中截获后处理,当然也可以在窗口过程中直接处理。这里要注意的是,有点事件根本没有进入消息循环,而是直接发送到了窗口过程,比如...
  • zxm342698145
  • zxm342698145
  • 2014-05-22 09:46:40
  • 7402

duilib界面库源代码

  • 2010年08月21日 13:34
  • 203KB
  • 下载
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 8425
    积分: 565
    排名: 9万+
    博客专栏