• DirectUI的消息流转


    Windows是一个基于消息循环的系统,DirectUI同样遵循这样的消息流转。当界面呈现、用户点击、定时器等各种各样的消息一旦进入windows消息循环队列,系统自动调用该窗口的WndProc过程。对于DirectUI程序来说,因为所有的界面都是逻辑界面,均基于程序运行之初通过CreateWindowEx生成的原始窗口,因此,所有的消息最开始都会先流转到DirectUI中CWindowWnd类的__WndProc函数中,然后再统一的分发。

     
    可以在Duilib的应用中通过设置断点来跟踪整个消息的流程,大体上,下图表示了这个流转过程:
     
    值得注意的是,多个界面,如CWindowWnd, Container等,可以共用同一个CPaintManagerUI来管理界面呈现与消息分发,只需要调用同一个CPaintManagerUI的AddNotifier【这个一般意味着你需要定义一个全局的CPaintMagagerUI变量而不是一个类的变量】。
    尤其值得注意的是,共用同一个CPaintManagerUI的情况下,很多时候可能是使用界面元素如Button的Name来区分是哪一个元素,因此,务必注意每个元素的名字是唯一的。
    下面是才代码摘录出来的片段:
     

    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);
    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);
    }
    }

    将自身加入到消息收听队列:

    g_PM->AddNotifier(this);//g_PM为全局的CPaintManagerUI变量


    HandleMassage的实现:

    LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    LRESULT lRes = 0;
    BOOL bHandled = TRUE;
    switch( uMsg ) {
    case WM_CREATE: lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
    case WM_CLOSE: lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
    case WM_DESTROY: lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
    case WM_NCACTIVATE: lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
    case WM_NCCALCSIZE: lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
    case WM_NCPAINT: lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
    case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
    case WM_SIZE: lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
    case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
    case WM_SYSCOMMAND: lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
    case WM_KEYDOWN:
    OutputDebugString(_T("It is a key down "));
    break;
    default:
    bHandled = FALSE;
    }
    if( bHandled ) return lRes;
    if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
    return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    }

    遍历收听者并发送通知:

    ......

    if( !bAsync ) {
    // Send to all listeners
    if( Msg.pSender != NULL ) {
    if( Msg.pSender->OnNotify ) Msg.pSender->OnNotify(&Msg);
    }
    for( int i = 0; i < m_aNotifiers.GetSize(); i++ ) {
    static_cast<INotifyUI*>(m_aNotifiers[i])->Notify(Msg);
    }
    }

    ......

    Notify的实现:

    void SettingUI::Notify(TNotifyUI& msg)
    {
    CStdString name = msg.pSender->GetName();

    if (msg.sType == _T("windowinit"))
    {
    }
    else if( msg.sType == _T("click") )
    {

    }

    .....

     

    http://sogoodlife.blog.163.com/blog/static/458502602012610508332/

  • 相关阅读:
    vue定义data的三种方式与区别
    利用Python开发App实战
    序列化:ProtoBuf 与 JSON 的比较 !
    年轻人不讲武德,where 1=1 是什么鬼?
    Java 生成随机数的 5 种方式,你知道几种?
    卸载 Navicat!事实已证明,正版客户端,它更牛逼……
    MySQL大表优化方案
    鹅厂是如何使用 Git 的?
    灵魂一问:一个TCP连接可以发多少个HTTP请求?
    新来的老大说,“公司以后禁止使用Lombok”,我表示反对~
  • 原文地址:https://www.cnblogs.com/findumars/p/5794175.html
Copyright © 2020-2023  润新知