duilib消息响应总结

按照如下方式传递消息:

首先是主窗口的回调函数,然后是主窗口的HandleMessage,最后是调用CPaintManagerUI::MessageHandler处理界面及其子控件

1.LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2.LRESULT WindowImplBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
3.bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)

消息循环如下:获取消息,发放消息

    UINT CWindowWnd::ShowModal()
{
    ASSERT(::IsWindow(m_hWnd));
    UINT nRet = 0;
    HWND hWndParent = GetWindowOwner(m_hWnd);
    ::ShowWindow(m_hWnd, SW_SHOWNORMAL);
    ::EnableWindow(hWndParent, FALSE);
    MSG msg = { 0 };
    while( ::IsWindow(m_hWnd) && ::GetMessage(&msg, NULL, 0, 0) ) {
        if( msg.message == WM_CLOSE && msg.hwnd == m_hWnd ) {
            nRet = msg.wParam;
            ::EnableWindow(hWndParent, TRUE);
            ::SetFocus(hWndParent);
        }
        if( !CPaintManagerUI::TranslateMessage(&msg) ) {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
        if( msg.message == WM_QUIT ) break;
    }
    ::EnableWindow(hWndParent, TRUE);
    ::SetFocus(hWndParent);
    if( msg.message == WM_QUIT ) ::PostQuitMessage(msg.wParam);
    return nRet;
}

 

sendnotify

    1.发送消息

m_pManager->SendNotify(this, DUI_MSGTYPE_CLICK);

2.注册消息函数
        DUI_BEGIN_MESSAGE_MAP(WindowImplBase, CNotifyPump)
        DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK,OnClick)
    DUI_END_MESSAGE_MAP()

3.消息响应函数
    void WindowImplBase::OnClick(TNotifyUI& msg)
    {
        CDuiString sCtrlName = msg.pSender->GetName();
        if( sCtrlName == _T("closebtn") ) {
            Close();
            return; 
        }
        else if( sCtrlName == _T("minbtn")) { 
            SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); 
            return; 
        }
        else if( sCtrlName == _T("maxbtn")) { 
            SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); 
            return; 
        }
        else if( sCtrlName == _T("restorebtn")) { 
            SendMessage(WM_SYSCOMMAND, SC_RESTORE, 0); 
            return; 
        }
        return;
    }

    // Structure for notifications to the outside world
    typedef struct tagTNotifyUI
    {
        CDuiString sType;//操作类型
        CDuiString sVirtualWnd;//虚拟窗口
        CControlUI* pSender;//控件发送者
        DWORD dwTimestamp;//发送时间
        POINT ptMouse;//鼠标位置
        WPARAM wParam;//参数1
        LPARAM lParam;//参数2
    } TNotifyUI;

看下CWindowWnd类与CPaintManagerUI类是咋进行消息分发的吧.

 

// Structure for notifications from the system
    // to the control implementation.//系统向控件发送的消息
    typedef struct UILIB_API tagTEventUI
    {
        int Type;//类型
        CControlUI* pSender;//发送的控件
        DWORD dwTimestamp;//发送时间
        POINT ptMouse;//鼠标位置
        TCHAR chKey;
        WORD wKeyState;
        WPARAM wParam;
        LPARAM lParam;
    } TEventUI;

case WM_TIMER:
            {
                for( int i = 0; i < m_aTimers.GetSize(); i++ ) {
                    const TIMERINFO* pTimer = static_cast<TIMERINFO*>(m_aTimers[i]);
                    if(pTimer->hWnd == m_hWndPaint && 
                        pTimer->uWinTimer == LOWORD(wParam) && 
                        pTimer->bKilled == false)
                    {
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_TIMER;
                        event.pSender = pTimer->pSender;
                        event.dwTimestamp = ::GetTickCount();
                        event.ptMouse = m_ptLastMousePos;
                        event.wKeyState = MapKeyState();
                        event.wParam = pTimer->nLocalID;
                        event.lParam = lParam;
                        pTimer->pSender->Event(event);
                        break;
                    }
                }
            }

1. 先看下CPaintManagerUI类的MessageLoop函数:

 

[cpp] view plaincopyprint?

  1. void CPaintManagerUI::MessageLoop()  
  2. {  
  3.     MSG msg = { 0 };  
  4.     while( ::GetMessage(&msg, NULL, 0, 0) ) {    // 获取消息  
  5.         if( !CPaintManagerUI::TranslateMessage(&msg) ) { // 消息过滤  
  6.             ::TranslateMessage(&msg);  
  7.             ::DispatchMessage(&msg); // 分发到窗口的消息处理窗口中. 也就是调用CWindowWnd类的__WndProc函数或是__ControlProc函数.  
  8.         }  
  9.     }  
  10. }  

消息第一次会由CPaintManagerUI类的TranslateMessage消息接收到.

 

2. 调用CWindowWnd::Create创建窗口.  完成以下操作:

1) 如果要子类下Window的控件(就是系统的控件, 而不是duilib的模拟控件), 就设置__ControlProc函数为消息回调函数.

2)不子类化, 就注册窗口类. 此时设置__WndProc为窗口消息处理回调函数.  

3)用CreateWindowEx API函数创建窗口.

这里先不看子类化相关的, 我要先看明白标准的窗口创建过程.  这也操作后消息就会分发到__WndProc了, 

3. 看下__WndProc函数的定义: 

 

[cpp] view plaincopyprint?

  1. LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     CWindowWnd* pThis = NULL;  
  4.     if( uMsg == WM_NCCREATE ) { // 要在此消息中把类于窗口进行绑定  
  5.         LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);   // 来自于CreateWindowEx函数的最后一个参数( 也就是CWindowWnd对象指针了 )  
  6.         pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);  
  7.         pThis->m_hWnd = hWnd;  
  8.         ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis)); // 设置到窗口的用户数据中  
  9.     }   
  10.     else {  
  11.         pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));  
  12.         if( uMsg == WM_NCDESTROY && pThis != NULL ) {  
  13.             LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);    // 收到窗口能处理到的最后一个消息了, 要进行收尾工作了.  
  14.             ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);    // 取消类对象与窗口的绑定关系  
  15.             if( pThis->m_bSubclassed ) pThis->Unsubclass();  
  16.             pThis->m_hWnd = NULL;  
  17.             pThis->OnFinalMessage(hWnd);  
  18.             return lRes;  
  19.         }  
  20.     }  
  21.     if( pThis != NULL ) {  
  22.         return pThis->HandleMessage(uMsg, wParam, lParam);  // 在此调用继承类的消息处理函数  
  23.     }   
  24.     else {  
  25.         return ::DefWindowProc(hWnd, uMsg, wParam, lParam); // 未绑定类对象, 就调用默认的窗口消息处理函数  
  26.     }  
  27. }  


 

 

 

 

消息第二次就由__WndProc接收到, 然后再传到CWindowWnd类的HandlerMessage函数中.

 

 

3. 看看CWindowWnd类的继承类对于HandlerMessage虚函数的实现.

 

[cpp] view plaincopyprint?

  1. LRESULT CMainWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )  
  2. {  
  3.     LRESULT lRes        = 0;    // 消息处理返回值.  
  4.     BOOL    bHandled    = TRUE; // 消息是否要继续往下传.  
  5.     switch ( uMsg )  
  6.     {  
  7.     case WM_CREATE: lRes    = OnInitResource( bHandled ); break;  // 进行初始化工作. 比如最重要的XML加载解析工作.  
  8.     default:  
  9.         bHandled    = FALSE;  
  10.     }  
  11.   
  12.     if ( bHandled )  
  13.     {  
  14.         return lRes;  
  15.     }  
  16.   
  17.     if ( m_pm.MessageHandler( uMsg, wParam, lParam, lRes ) )    // 传给CPaintManagerUI::MessageHandler函数进行具体的控件处理工作  
  18.     {  
  19.         return lRes;  
  20.     }  
  21.   
  22.     return CWindowWnd::HandleMessage( uMsg, wParam, lParam );  // 没处理过的就调用CWindowWnd类的默认消息处理函数吧.  
  23. }  


 

 

 

 

在这里就是用户要按消息进行具体的处理了. 之后要传到CPaintManagerUI类对象的MessageHandler函数. 未处理的消息就要返回给CWindowWnd类的默认消息处理函数来处理了. 

 

4.  CPaintManagerUI类的TranslateMessage, MessageHandler函数的内容.

 

[cpp] view plaincopyprint?

  1. BOOL CPaintManagerUI::TranslateMessage(const LPMSG pMsg)  
  2. {  
  3.     HWND hwndParent = ::GetParent(pMsg->hwnd); // 获取消息接收窗口的父窗口  
  4.     UINT uStyle = GetWindowStyle(pMsg->hwnd); // 获取窗口的样式  
  5.     LRESULT lRes = 0;  
  6.     for( int i = 0; i < m_aPreMessages.GetSize(); i++ ) { // 这个m_aPreMessage保存着CPaintManagerUI类对象.   
  7.         CPaintManagerUI* pT = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);  
  8.         if( pMsg->hwnd == pT->GetPaintWindow() // 消息是否属于当前CPaintManagerUI绑定的窗口  
  9.          || (hwndParent == pT->GetPaintWindow() && ((uStyle & WS_CHILD) != 0)) ) // 消息是否为当前窗口中窗口的消息, (如ActiveX控件 )  
  10.         {  
  11.             if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return TRUE; // 此时就调用PreMessageHandler过滤函数.  
  12.         }  
  13.     }  
  14.     return FALSE;  
  15. }  

m_aPreMessage为静态成员变量, 在CPaintManagerUI::Init进行窗口与此类绑定时添加到此变量中. 

 

 

5. CPaintManagerUI::PreMessageHandler消息过滤函数.

 

[cpp] view plaincopyprint?

  1. BOOL CPaintManagerUI::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/)  
  2. {  
  3.     // 遍历当前的消息过滤列表. m_aPreMessageFilter的元素为IMessageFilterUI接口.只一个虚函数MessageHandler.   
  4.     // 用户可以添加此接口的继承类变量到m_aPreMessageFilters列表中. ( 调用AddMessageFilter函数实现 )  
  5.     for( int i = 0; i < m_aPreMessageFilters.GetSize(); i++ )   
  6.     {  
  7.         BOOL bHandled = FALSE;  
  8.         LRESULT lResult = static_cast<IMessageFilterUI*>(m_aPreMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);  
  9.         if( bHandled ) {  
  10.             return TRUE;  
  11.         }  
  12.     }  
  13.     // 以下是对几个按键消息的过滤.  
  14.     // WM_KEYDOWN     检查是否为VK_TAB键, 要进行控件焦点的移动.  
  15.     // WM_SYSCHAR     获取与wParam中的字符加速键匹配的控件, 并激活它.  
  16.     // WM_SYSKEYDOWN  生成控件事件( 用TEventUI来模拟 )  
  17. }  


 

 

 

 

 

 

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类似MFC的消息响应如下:

DUI_DECLARE_MESSAGE_MAP()  
  
DUI_BEGIN_MESSAGE_MAP(CYmChatUI, CXMLWnd)  
    DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick)  
DUI_END_MESSAGE_MAP() 

绑定消息响应函数:

#define DUI_MSGTYPE_MENU                   (_T("menu"))  
#define DUI_MSGTYPE_LINK                   (_T("link"))  
  
#define DUI_MSGTYPE_TIMER                  (_T("timer"))  
#define DUI_MSGTYPE_CLICK                  (_T("click"))  
  
#define DUI_MSGTYPE_RETURN                 (_T("return"))  
#define DUI_MSGTYPE_SCROLL                 (_T("scroll"))  
  
#define DUI_MSGTYPE_DROPDOWN               (_T("dropdown"))  
#define DUI_MSGTYPE_SETFOCUS               (_T("setfocus"))  
  
#define DUI_MSGTYPE_KILLFOCUS              (_T("killfocus"))  
#define DUI_MSGTYPE_ITEMCLICK              (_T("itemclick"))  
#define DUI_MSGTYPE_TABSELECT              (_T("tabselect"))  
  
#define DUI_MSGTYPE_ITEMSELECT             (_T("itemselect"))  
#define DUI_MSGTYPE_ITEMEXPAND             (_T("itemexpand"))  
  
#define DUI_MSGTYPE_WINDOWINIT             (_T("windowinit"))  
#define DUI_MSGTYPE_BUTTONDOWN             (_T("buttondown"))  
#define DUI_MSGTYPE_MOUSEENTER             (_T("mouseenter"))  
#define DUI_MSGTYPE_MOUSELEAVE             (_T("mouseleave"))  
  
#define DUI_MSGTYPE_TEXTCHANGED            (_T("textchanged"))  
#define DUI_MSGTYPE_HEADERCLICK            (_T("headerclick"))  
#define DUI_MSGTYPE_ITEMDBCLICK            (_T("itemdbclick"))  
#define DUI_MSGTYPE_SHOWACTIVEX            (_T("showactivex"))  
  
#define DUI_MSGTYPE_ITEMCOLLAPSE           (_T("itemcollapse"))  
#define DUI_MSGTYPE_ITEMACTIVATE           (_T("itemactivate"))  
#define DUI_MSGTYPE_VALUECHANGED           (_T("valuechanged"))  
  
#define DUI_MSGTYPE_SELECTCHANGED          (_T("selectchanged"))

映射到的函数:

//定义消息类型--执行函数宏  
#define DUI_ON_MSGTYPE(msgtype, memberFxn)                                \  
    { msgtype, _T(""), DuiSig_vn, (DUI_PMSG)&memberFxn},                  \  
//定义消息类型--控件名称--执行函数宏  
#define DUI_ON_MSGTYPE_CTRNAME(msgtype,ctrname,memberFxn)                 \  
    { msgtype, ctrname, DuiSig_vn, (DUI_PMSG)&memberFxn },                \  
//定义click消息的控件名称--执行函数宏  
#define DUI_ON_CLICK_CTRNAME(ctrname,memberFxn)                           \  
    { DUI_MSGTYPE_CLICK, ctrname, DuiSig_vn, (DUI_PMSG)&memberFxn },      \  
//定义selectchanged消息的控件名称--执行函数宏  
#define DUI_ON_SELECTCHANGED_CTRNAME(ctrname,memberFxn)                   \  
    { DUI_MSGTYPE_SELECTCHANGED,ctrname,DuiSig_vn,(DUI_PMSG)&memberFxn }, \  
//定义killfocus消息的控件名称--执行函数宏  
#define DUI_ON_KILLFOCUS_CTRNAME(ctrname,memberFxn)                       \  
    { DUI_MSGTYPE_KILLFOCUS,ctrname,DuiSig_vn,(DUI_PMSG)&memberFxn },     \  
//定义menu消息的控件名称--执行函数宏  
#define DUI_ON_MENU_CTRNAME(ctrname,memberFxn)                            \  
    { DUI_MSGTYPE_MENU,ctrname,DuiSig_vn,(DUI_PMSG)&memberFxn },          \  
//定义与控件名称无关的消息宏  
  //定义timer消息--执行函数宏  
#define DUI_ON_TIMER()                                                    \  
    { DUI_MSGTYPE_TIMER, _T(""), DuiSig_vn,(DUI_PMSG)&OnTimer },          \  

WindowImplBase也实现了一些常规消息的响应函数:

//点击事件  
virtual void OnClick(TNotifyUI& msg);  
//关闭窗口事件  
virtual LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//销毁窗口事件  
virtual LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//窗口尺寸改变时响应此事件  
virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);  
//拦截字符响应  
virtual LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);  
//拦截系统消息响应  
virtual LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);  
//窗口创建时响应  
virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);  
//键盘按下时响应  
virtual LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//失去焦点时响应  
virtual LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//获得焦点时响应  
virtual LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//左键按下响应  
virtual LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//左键抬起响应  
virtual LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//鼠标移动响应  
virtual LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//鼠标滚轮响应  
virtual LRESULT OnMouseWheel(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);  
//鼠标放在控件上响应  
virtual LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);  



作者:彦子凡
链接:https://www.jianshu.com/p/5422cdec2b8f
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值