• DuiLib(一)——窗口及消息


    最近看了下开源界面库duilib的代码,写几篇相关的文章。网上已经有好多相关的文章了,我这里只是记录自己的学习过程,写到哪里算哪里权当自娱自乐

    duilib是一轻量级的direcui界面库,所谓directui是指在一真实的窗口之上画出各种控件。所以先从界面库的窗口及消息入手比较好,可以抓住树根,再顺着往上分析。

    duilib将窗口封装成类CWindowWnd,创建窗口之前要先注册窗口:

     1 bool CWindowWnd::RegisterWindowClass()
     2 {
     3     WNDCLASS wc = { 0 };
     4     wc.style = GetClassStyle();
     5     wc.cbClsExtra = 0;
     6     wc.cbWndExtra = 0;
     7     wc.hIcon = NULL;
     8     wc.lpfnWndProc = CWindowWnd::__WndProc;//窗口过程
     9     wc.hInstance = CPaintManagerUI::GetInstance();
    10     wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    11     wc.hbrBackground = NULL;
    12     wc.lpszMenuName  = NULL;
    13     wc.lpszClassName = GetWindowClassName();//窗口类名
    14     ATOM ret = ::RegisterClass(&wc);
    15     ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
    16     return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
    17 }
    1 HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
    2 {
    3     if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
    4     if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
    5     m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetInstance(), this);
    6     ASSERT(m_hWnd!=NULL);
    7     return m_hWnd;
    8 }

    窗口过程为CWindowWnd类的静态函数__WndProc

     1 LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     2 {
     3     CWindowWnd* pThis = NULL;
     4     if( uMsg == WM_NCCREATE ) {//before WM_CREATE
     5         LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
     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 ) {//after WM_DESTROY
    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         //消息处理
    23         return pThis->HandleMessage(uMsg, wParam, lParam);
    24     } 
    25     else {
    26         return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    27     }
    28 }

    窗口函数__WndProc:

    • 处理了WM_NCCREATE消息(WM_CREATE之前发送)和WM_NCDESTROY(WM_DESTROY之后发送)。前者保存了CWindowWnd对象指针,后者获取该指针,并调用虚函数OnFinalMessage,给用户一个最后清理的机会。
    • 调用虚函数HandleMessage,处理其他消息

     消息循环在哪?不在类CWindowWnd中,在CPaintManagerUI里!

    void CPaintManagerUI::MessageLoop()
    {
        MSG msg = { 0 };
        while( ::GetMessage(&msg, NULL, 0, 0) ) {
            if( !CPaintManagerUI::TranslateMessage(&msg) ) {
                ::TranslateMessage(&msg);
                ::DispatchMessage(&msg);
            }
        }
    }

    一个简单的示例:

    class CFrameWindowWnd : public CWindowWnd, public INotifyUI
    {
    public:
        CFrameWindowWnd() { };
        LPCTSTR GetWindowClassName() const { return _T("FrameWnd"); };
        UINT GetClassStyle() const { return UI_CLASSSTYLE_FRAME | CS_DBLCLKS; };
        void OnFinalMessage(HWND /*hWnd*/) { delete this; };
    
        void Notify(TNotifyUI& msg)
        {
            if( msg.sType == _T("windowinit") ) {
            }
            else if( msg.sType == _T("click") ) {
            }
        }
    
        //消息处理:窗口函数__WndProc ---> HandleMessage
        LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
            if( uMsg == WM_CREATE ) {
                m_pm.Init(m_hWnd);
                //根据XML创建控件
                CDialogBuilder builder;
                CControlUI* pRoot = builder.Create(_T("HelloWorld.xml"), (UINT)0, NULL, &m_pm);
                ASSERT(pRoot && "Failed to parse XML");
                m_pm.AttachDialog(pRoot);
                m_pm.AddNotifier(this);
                return 0;
            }
            else if( uMsg == WM_DESTROY ) {
                ::PostQuitMessage(0L);
            }
            else if( uMsg == WM_ERASEBKGND ) {
                return 1;
            }
    
            //消息处理:CPaintManagerUI::MessageHandler
            LRESULT lRes = 0;
            if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
            return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
        }
    
    public:
        CPaintManagerUI m_pm;
    };
    
    
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
    {
        CPaintManagerUI::SetInstance(hInstance);
        CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin\HelloWorldRes"));
    
        //COM
        HRESULT Hr = ::CoInitialize(NULL);
        if( FAILED(Hr) ) return 0;
    
        CFrameWindowWnd* pFrame = new CFrameWindowWnd();
        if( pFrame == NULL ) return 0;
    
        //注册窗口类、创建窗口
        pFrame->Create(NULL, _T("HelloWorld"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
        pFrame->CenterWindow();
        pFrame->ShowWindow(true);
    
        //消息循环
        CPaintManagerUI::MessageLoop();
    
        //COM
        ::CoUninitialize();
        return 0;
    }

    这个例子可以看到整个程序框架,注册、创建窗口、消息循环、消息处理等。

    关于窗口和消息,先写这么多。下一篇写控件创建

  • 相关阅读:
    Cesium中的坐标系及转换
    Cesium Workshop
    window.postMessage 跨窗口,跨iframe javascript 通信
    VUE课程参考---7、跑马灯效果
    VUE课程---9、事件绑定v-on
    VUE课程---8、属性绑定v-bind
    VUE课程---7、解决插值表达式闪烁问题
    小谈chrome调试命令:console.log的使用
    Hadoop平台配置总结
    hadoop 关闭进程时报错no 进程 to stop
  • 原文地址:https://www.cnblogs.com/dahai/p/3455727.html
Copyright © 2020-2023  润新知