• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Error

            C++博客 首頁 新隨筆 聯系 聚合 管理
              217 Posts :: 61 Stories :: 32 Comments :: 0 Trackbacks

            從GameDemo.cpp看起

             

            1回顧通常的sdk窗口程序流程:注冊窗口-創建窗口-顯示窗口-啟動消息循環

             

            1.1注冊窗口類

            Duilib中最平凡的真實窗口類是:CWindowWnd,關于窗口注冊提供了兩個函數,嚴格的說應該是幾個:

            RegisterWindowClass()

            RegisterSuperclass()

            GetWindowClassName()

            GetSuperClassName()

            GetClassStyle()

            在我的理解中,后面兩個虛函數的意義應該是:上面這些接口分兩組,一組是用于正常注冊使用,一組用于擴展。

            使用的時候用自定義的窗口對象從CWindowWnd繼承下來,然后定制自己需要的window class

            1.2創建窗口

                CGameFrameWnd* pFrame = new CGameFrameWnd();
                if( pFrame == NULL ) return 0;
                pFrame->Create(NULL, _T(""), UI_WNDSTYLE_FRAME, 0L, 0, 0, 1024, 738);
            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            CWindowWnd帶有mfc CWnd類似的Create接口用于創建窗口,同事注冊窗口類也通過虛函數的方式延后到子類實現,super機制(如果有super優先注冊)也帶進來。

                if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
                if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            1.3顯示窗口

            和sdk是一樣的

            ::ShowWindow(*pFrame, SW_SHOWMAXIMIZED);

            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } 1.4消息循環

            CPaintManagerUI::MessageLoop();
            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            1.5消息回調函數

            在窗口類注冊的時候應該要注冊窗口回調函數指針,Duilib中默認是在CWindowWnd::RegisterWindow注冊:

            bool CWindowWnd::RegisterWindowClass()
            {
                WNDCLASS wc = { 0 };
                wc.style = GetClassStyle();
                wc.cbClsExtra = 0;
                wc.cbWndExtra = 0;
                wc.hIcon = NULL;
                wc.lpfnWndProc = CWindowWnd::__WndProc;

            __WndProc是CWindowWnd的一個靜態成員,這個函數值得看一下:

            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);
                }
            }
            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            針對WM_NCCREATE這個消息有一個管用技巧,先復習下這個消息:

            The WM_NCCREATE message is sent prior to the WM_CREATE message when a window is first created.

            我的理解中,這個消息應該是窗口收到的第一個消息。

            還有WM_NCDESTROY這個特殊的消息。

            當然了,還有這個牛逼的戲法:

            ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));

            總的來說一句話,兩個消息NC create destroy對應的應該有連個函數,但是原本的OnNcCreate響應隱藏在了__WndProc中,還有一個函數OnFinalMessage。this指針藏在SetWindowLongPtr(hWnd, GWLP_USERDATA,,,

            好了底層需要注意的就只有這兩個函數,其他的消息都應該是拋給子類去處理了。

            既然是玩directUi,就重點關注一下WM_NCPAINT消息,也一個也很重要的消息WM_NCHITTEST。

            不知道為什么這里用的都是NC系列消息。

            NC應該是理解成none client,初步觀察Duilib的size拖拉支持是使用NCHITTEST+SIZE消息來實現的。

            看NCPAINT消息體里邊沒有任何代碼這很詭異,所以還是看看完整的消息響應函數,是不是漏掉了什么:

                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;
                    default:
                        bHandled = FALSE;
                    }
                    if( bHandled ) return lRes;
                    if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
                    return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
                }
            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            乍看之下這里的消息處理至少分為三層,CWindowWnd派生類本身沒有處理的消息將會被送到m_pm中去處理,如果m_pm.MessageHandler返回false消息最后還是CWindowWnd處理。

            bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
            {
            //#ifdef _DEBUG
            //    switch( uMsg ) {
            //    case WM_NCPAINT:
            //    case WM_NCHITTEST:
            //    case WM_SETCURSOR:
            //       break;
            //    default:
            //       DUITRACE(_T("MSG: %-20s (%08ld)"), DUITRACEMSG(uMsg), ::GetTickCount());
            //    }
            //#endif
                // Not ready yet?
                if( m_hWndPaint == NULL ) return false;
                
                TNotifyUI* pMsg = NULL;
                while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) ) {
                    m_aAsyncNotify.Remove(0);
                    if( pMsg->pSender != NULL ) {
                        if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
                    }
                    for( int j = 0; j < m_aNotifiers.GetSize(); j++ ) {
                        static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
                    }
                    delete pMsg;
                }
                
                // Cycle through listeners
                for( int i = 0; i < m_aMessageFilters.GetSize(); i++ ) 
                {
                    bool bHandled = false;
                    LRESULT lResult = static_cast<IMessageFilterUI*>(m_aMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);
                    if( bHandled ) {
                        lRes = lResult;
                        return true;
                    }
                }
                // Custom handling of events
                switch( uMsg ) {
                case WM_APP + 1:
                    {
                        for( int i = 0; i < m_aDelayedCleanup.GetSize(); i++ ) 
                            delete static_cast<CControlUI*>(m_aDelayedCleanup[i]);
                        m_aDelayedCleanup.Empty();
                    }
                    break;
                case WM_CLOSE:
                    {
                        // Make sure all matching "closing" events are sent
                        TEventUI event = { 0 };
                        event.ptMouse = m_ptLastMousePos;
                        event.dwTimestamp = ::GetTickCount();
                        if( m_pEventHover != NULL ) {
                            event.Type = UIEVENT_MOUSELEAVE;
                            event.pSender = m_pEventHover;
                            m_pEventHover->Event(event);
                        }
                        if( m_pEventClick != NULL ) {
                            event.Type = UIEVENT_BUTTONUP;
                            event.pSender = m_pEventClick;
                            m_pEventClick->Event(event);
                        }
            
                        SetFocus(NULL);
            
                        // Hmmph, the usual Windows tricks to avoid
                        // focus loss...
                        HWND hwndParent = GetWindowOwner(m_hWndPaint);
                        if( hwndParent != NULL ) ::SetFocus(hwndParent);
                    }
                    break;
                case WM_ERASEBKGND:
                    {
                        // We'll do the painting here...
                        lRes = 1;
                    }
                    return true;
                case WM_PAINT:
                    {
                        // Should we paint?
                        RECT rcPaint = { 0 };
                        if( !::GetUpdateRect(m_hWndPaint, &rcPaint, FALSE) ) return true;
                        if( m_pRoot == NULL ) {
                            PAINTSTRUCT ps = { 0 };
                            ::BeginPaint(m_hWndPaint, &ps);
                            ::EndPaint(m_hWndPaint, &ps);
                            return true;
                        }            
                        // Do we need to resize anything?
                        // This is the time where we layout the controls on the form.
                        // We delay this even from the WM_SIZE messages since resizing can be
                        // a very expensize operation.
                        if( m_bUpdateNeeded ) {
                            m_bUpdateNeeded = false;
                            RECT rcClient = { 0 };
                            ::GetClientRect(m_hWndPaint, &rcClient);
                            if( !::IsRectEmpty(&rcClient) ) {
                                if( m_pRoot->IsUpdateNeeded() ) {
                                    m_pRoot->SetPos(rcClient);
                                    if( m_hDcOffscreen != NULL ) ::DeleteDC(m_hDcOffscreen);
                                    if( m_hDcBackground != NULL ) ::DeleteDC(m_hDcBackground);
                                    if( m_hbmpOffscreen != NULL ) ::DeleteObject(m_hbmpOffscreen);
                                    if( m_hbmpBackground != NULL ) ::DeleteObject(m_hbmpBackground);
                                    m_hDcOffscreen = NULL;
                                    m_hDcBackground = NULL;
                                    m_hbmpOffscreen = NULL;
                                    m_hbmpBackground = NULL;
                                }
                                else {
                                    CControlUI* pControl = NULL;
                                    while( pControl = m_pRoot->FindControl(__FindControlFromUpdate, NULL, UIFIND_VISIBLE | UIFIND_ME_FIRST) ) {
                                        pControl->SetPos( pControl->GetPos() );
                                    }
                                }
                                // We'll want to notify the window when it is first initialized
                                // with the correct layout. The window form would take the time
                                // to submit swipes/animations.
                                if( m_bFirstLayout ) {
                                    m_bFirstLayout = false;
                                    SendNotify(m_pRoot, DUI_MSGTYPE_WINDOWINIT,  0, 0, false);
                                }
                            }
                        }
                        // Set focus to first control?
                        if( m_bFocusNeeded ) {
                            SetNextTabControl();
                        }
                        //
                        // Render screen
                        //
                        // Prepare offscreen bitmap?
                        if( m_bOffscreenPaint && m_hbmpOffscreen == NULL )
                        {
                            RECT rcClient = { 0 };
                            ::GetClientRect(m_hWndPaint, &rcClient);
                            m_hDcOffscreen = ::CreateCompatibleDC(m_hDcPaint);
                            m_hbmpOffscreen = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 
                            ASSERT(m_hDcOffscreen);
                            ASSERT(m_hbmpOffscreen);
                        }
                        // Begin Windows paint
                        PAINTSTRUCT ps = { 0 };
                        ::BeginPaint(m_hWndPaint, &ps);
                        if( m_bOffscreenPaint )
                        {
                            HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(m_hDcOffscreen, m_hbmpOffscreen);
                            int iSaveDC = ::SaveDC(m_hDcOffscreen);
                            if( m_bAlphaBackground ) {
                                if( m_hbmpBackground == NULL ) {
                                    RECT rcClient = { 0 };
                                    ::GetClientRect(m_hWndPaint, &rcClient);
                                    m_hDcBackground = ::CreateCompatibleDC(m_hDcPaint);;
                                    m_hbmpBackground = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 
                                    ASSERT(m_hDcBackground);
                                    ASSERT(m_hbmpBackground);
                                    ::SelectObject(m_hDcBackground, m_hbmpBackground);
                                    ::BitBlt(m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                                        ps.rcPaint.bottom - ps.rcPaint.top, ps.hdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                                }
                                else
                                    ::SelectObject(m_hDcBackground, m_hbmpBackground);
                                ::BitBlt(m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                                    ps.rcPaint.bottom - ps.rcPaint.top, m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                            }
                            m_pRoot->DoPaint(m_hDcOffscreen, ps.rcPaint);
                            for( int i = 0; i < m_aPostPaintControls.GetSize(); i++ ) {
                                CControlUI* pPostPaintControl = static_cast<CControlUI*>(m_aPostPaintControls[i]);
                                pPostPaintControl->DoPostPaint(m_hDcOffscreen, ps.rcPaint);
                            }
                            ::RestoreDC(m_hDcOffscreen, iSaveDC);
                            ::BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                                ps.rcPaint.bottom - ps.rcPaint.top, m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                            ::SelectObject(m_hDcOffscreen, hOldBitmap);
            
                            if( m_bShowUpdateRect ) {
                                HPEN hOldPen = (HPEN)::SelectObject(ps.hdc, m_hUpdateRectPen);
                                ::SelectObject(ps.hdc, ::GetStockObject(HOLLOW_BRUSH));
                                ::Rectangle(ps.hdc, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
                                ::SelectObject(ps.hdc, hOldPen);
                            }
                        }
                        else
                        {
                            // A standard paint job
                            int iSaveDC = ::SaveDC(ps.hdc);
                            m_pRoot->DoPaint(ps.hdc, ps.rcPaint);
                            ::RestoreDC(ps.hdc, iSaveDC);
                        }
                        // All Done!
                        ::EndPaint(m_hWndPaint, &ps);
                    }
                    // If any of the painting requested a resize again, we'll need
                    // to invalidate the entire window once more.
                    if( m_bUpdateNeeded ) {
                        ::InvalidateRect(m_hWndPaint, NULL, FALSE);
                    }
                    return true;
                case WM_PRINTCLIENT:
                    {
                        RECT rcClient;
                        ::GetClientRect(m_hWndPaint, &rcClient);
                        HDC hDC = (HDC) wParam;
                        int save = ::SaveDC(hDC);
                        m_pRoot->DoPaint(hDC, rcClient);
                        // Check for traversing children. The crux is that WM_PRINT will assume
                        // that the DC is positioned at frame coordinates and will paint the child
                        // control at the wrong position. We'll simulate the entire thing instead.
                        if( (lParam & PRF_CHILDREN) != 0 ) {
                            HWND hWndChild = ::GetWindow(m_hWndPaint, GW_CHILD);
                            while( hWndChild != NULL ) {
                                RECT rcPos = { 0 };
                                ::GetWindowRect(hWndChild, &rcPos);
                                ::MapWindowPoints(HWND_DESKTOP, m_hWndPaint, reinterpret_cast<LPPOINT>(&rcPos), 2);
                                ::SetWindowOrgEx(hDC, -rcPos.left, -rcPos.top, NULL);
                                // NOTE: We use WM_PRINT here rather than the expected WM_PRINTCLIENT
                                //       since the latter will not print the nonclient correctly for
                                //       EDIT controls.
                                ::SendMessage(hWndChild, WM_PRINT, wParam, lParam | PRF_NONCLIENT);
                                hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT);
                            }
                        }
                        ::RestoreDC(hDC, save);
                    }
                    break;
                case WM_GETMINMAXINFO:
                    {
                        LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
                        if( m_szMinWindow.cx > 0 ) lpMMI->ptMinTrackSize.x = m_szMinWindow.cx;
                        if( m_szMinWindow.cy > 0 ) lpMMI->ptMinTrackSize.y = m_szMinWindow.cy;
                        if( m_szMaxWindow.cx > 0 ) lpMMI->ptMaxTrackSize.x = m_szMaxWindow.cx;
                        if( m_szMaxWindow.cy > 0 ) lpMMI->ptMaxTrackSize.y = m_szMaxWindow.cy;
                    }
                    break;
                case WM_SIZE:
                    {
                        if( m_pFocus != NULL ) {
                            TEventUI event = { 0 };
                            event.Type = UIEVENT_WINDOWSIZE;
                            event.pSender = m_pFocus;
                            event.dwTimestamp = ::GetTickCount();
                            m_pFocus->Event(event);
                        }
                        if( m_pRoot != NULL ) m_pRoot->NeedUpdate();
                    }
                    return true;
                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.wParam = pTimer->nLocalID;
                                event.dwTimestamp = ::GetTickCount();
                                pTimer->pSender->Event(event);
                                break;
                            }
                        }
                    }
                    break;
                case WM_MOUSEHOVER:
                    {
                        m_bMouseTracking = false;
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        CControlUI* pHover = FindControl(pt);
                        if( pHover == NULL ) break;
                        // Generate mouse hover event
                        if( m_pEventHover != NULL ) {
                            TEventUI event = { 0 };
                            event.ptMouse = pt;
                            event.Type = UIEVENT_MOUSEHOVER;
                            event.pSender = m_pEventHover;
                            event.dwTimestamp = ::GetTickCount();
                            m_pEventHover->Event(event);
                        }
                        // Create tooltip information
                        CDuiString sToolTip = pHover->GetToolTip();
                        if( sToolTip.IsEmpty() ) return true;
                        ::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));
                        m_ToolTip.cbSize = sizeof(TOOLINFO);
                        m_ToolTip.uFlags = TTF_IDISHWND;
                        m_ToolTip.hwnd = m_hWndPaint;
                        m_ToolTip.uId = (UINT_PTR) m_hWndPaint;
                        m_ToolTip.hinst = m_hInstance;
                        m_ToolTip.lpszText = const_cast<LPTSTR>( (LPCTSTR) sToolTip );
                        m_ToolTip.rect = pHover->GetPos();
                        if( m_hwndTooltip == NULL ) {
                            m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWndPaint, NULL, m_hInstance, NULL);
                            ::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip);
                        }
                        ::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM) &m_ToolTip);
                        ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);
                    }
                    return true;
                case WM_MOUSELEAVE:
                    {
                        if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);
                        if( m_bMouseTracking ) ::SendMessage(m_hWndPaint, WM_MOUSEMOVE, 0, (LPARAM) -1);
                        m_bMouseTracking = false;
                    }
                    break;
                case WM_MOUSEMOVE:
                    {
                        // Start tracking this entire window again...
                        if( !m_bMouseTracking ) {
                            TRACKMOUSEEVENT tme = { 0 };
                            tme.cbSize = sizeof(TRACKMOUSEEVENT);
                            tme.dwFlags = TME_HOVER | TME_LEAVE;
                            tme.hwndTrack = m_hWndPaint;
                            tme.dwHoverTime = m_hwndTooltip == NULL ? 400UL : (DWORD) ::SendMessage(m_hwndTooltip, TTM_GETDELAYTIME, TTDT_INITIAL, 0L);
                            _TrackMouseEvent(&tme);
                            m_bMouseTracking = true;
                        }
                        // Generate the appropriate mouse messages
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        m_ptLastMousePos = pt;
                        CControlUI* pNewHover = FindControl(pt);
                        if( pNewHover != NULL && pNewHover->GetManager() != this ) break;
                        TEventUI event = { 0 };
                        event.ptMouse = pt;
                        event.dwTimestamp = ::GetTickCount();
                        if( pNewHover != m_pEventHover && m_pEventHover != NULL ) {
                            event.Type = UIEVENT_MOUSELEAVE;
                            event.pSender = m_pEventHover;
                            m_pEventHover->Event(event);
                            m_pEventHover = NULL;
                            if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);
                        }
                        if( pNewHover != m_pEventHover && pNewHover != NULL ) {
                            event.Type = UIEVENT_MOUSEENTER;
                            event.pSender = pNewHover;
                            pNewHover->Event(event);
                            m_pEventHover = pNewHover;
                        }
                        if( m_pEventClick != NULL ) {
                            event.Type = UIEVENT_MOUSEMOVE;
                            event.pSender = m_pEventClick;
                            m_pEventClick->Event(event);
                        }
                        else if( pNewHover != NULL ) {
                            event.Type = UIEVENT_MOUSEMOVE;
                            event.pSender = pNewHover;
                            pNewHover->Event(event);
                        }
                    }
                    break;
                case WM_LBUTTONDOWN:
                    {
                        // We alway set focus back to our app (this helps
                        // when Win32 child windows are placed on the dialog
                        // and we need to remove them on focus change).
                        ::SetFocus(m_hWndPaint);
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        m_ptLastMousePos = pt;
                        CControlUI* pControl = FindControl(pt);
                        if( pControl == NULL ) break;
                        if( pControl->GetManager() != this ) break;
                        m_pEventClick = pControl;
                        pControl->SetFocus();
                        SetCapture();
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_BUTTONDOWN;
                        event.pSender = pControl;
                        event.wParam = wParam;
                        event.lParam = lParam;
                        event.ptMouse = pt;
                        event.wKeyState = (WORD)wParam;
                        event.dwTimestamp = ::GetTickCount();
                        pControl->Event(event);
                    }
                    break;
                case WM_LBUTTONDBLCLK:
                    {
                        ::SetFocus(m_hWndPaint);
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        m_ptLastMousePos = pt;
                        CControlUI* pControl = FindControl(pt);
                        if( pControl == NULL ) break;
                        if( pControl->GetManager() != this ) break;
                        SetCapture();
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_DBLCLICK;
                        event.pSender = pControl;
                        event.ptMouse = pt;
                        event.wKeyState = (WORD)wParam;
                        event.dwTimestamp = ::GetTickCount();
                        pControl->Event(event);
                        m_pEventClick = pControl;
                    }
                    break;
                case WM_LBUTTONUP:
                    {
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        m_ptLastMousePos = pt;
                        if( m_pEventClick == NULL ) break;
                        ReleaseCapture();
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_BUTTONUP;
                        event.pSender = m_pEventClick;
                        event.wParam = wParam;
                        event.lParam = lParam;
                        event.ptMouse = pt;
                        event.wKeyState = (WORD)wParam;
                        event.dwTimestamp = ::GetTickCount();
                        m_pEventClick->Event(event);
                        m_pEventClick = NULL;
                    }
                    break;
                case WM_RBUTTONDOWN:
                    {
                        ::SetFocus(m_hWndPaint);
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        m_ptLastMousePos = pt;
                        CControlUI* pControl = FindControl(pt);
                        if( pControl == NULL ) break;
                        if( pControl->GetManager() != this ) break;
                        pControl->SetFocus();
                        SetCapture();
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_RBUTTONDOWN;
                        event.pSender = pControl;
                        event.wParam = wParam;
                        event.lParam = lParam;
                        event.ptMouse = pt;
                        event.wKeyState = (WORD)wParam;
                        event.dwTimestamp = ::GetTickCount();
                        pControl->Event(event);
                        m_pEventClick = pControl;
                    }
                    break;
                case WM_CONTEXTMENU:
                    {
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        ::ScreenToClient(m_hWndPaint, &pt);
                        m_ptLastMousePos = pt;
                        if( m_pEventClick == NULL ) break;
                        ReleaseCapture();
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_CONTEXTMENU;
                        event.pSender = m_pEventClick;
                        event.ptMouse = pt;
                        event.wKeyState = (WORD)wParam;
                        event.lParam = (LPARAM)m_pEventClick;
                        event.dwTimestamp = ::GetTickCount();
                        m_pEventClick->Event(event);
                        m_pEventClick = NULL;
                    }
                    break;
                case WM_MOUSEWHEEL:
                    {
                        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                        ::ScreenToClient(m_hWndPaint, &pt);
                        m_ptLastMousePos = pt;
                        CControlUI* pControl = FindControl(pt);
                        if( pControl == NULL ) break;
                        if( pControl->GetManager() != this ) break;
                        int zDelta = (int) (short) HIWORD(wParam);
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_SCROLLWHEEL;
                        event.pSender = pControl;
                        event.wParam = MAKELPARAM(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0);
                        event.lParam = lParam;
                        event.wKeyState = MapKeyState();
                        event.dwTimestamp = ::GetTickCount();
                        pControl->Event(event);
            
                        // Let's make sure that the scroll item below the cursor is the same as before...
                        ::SendMessage(m_hWndPaint, WM_MOUSEMOVE, 0, (LPARAM) MAKELPARAM(m_ptLastMousePos.x, m_ptLastMousePos.y));
                    }
                    break;
                case WM_CHAR:
                    {
                        if( m_pFocus == NULL ) break;
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_CHAR;
                        event.chKey = (TCHAR)wParam;
                        event.ptMouse = m_ptLastMousePos;
                        event.wKeyState = MapKeyState();
                        event.dwTimestamp = ::GetTickCount();
                        m_pFocus->Event(event);
                    }
                    break;
                case WM_KEYDOWN:
                    {
                        if( m_pFocus == NULL ) break;
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_KEYDOWN;
                        event.chKey = (TCHAR)wParam;
                        event.ptMouse = m_ptLastMousePos;
                        event.wKeyState = MapKeyState();
                        event.dwTimestamp = ::GetTickCount();
                        m_pFocus->Event(event);
                        m_pEventKey = m_pFocus;
                    }
                    break;
                case WM_KEYUP:
                    {
                        if( m_pEventKey == NULL ) break;
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_KEYUP;
                        event.chKey = (TCHAR)wParam;
                        event.ptMouse = m_ptLastMousePos;
                        event.wKeyState = MapKeyState();
                        event.dwTimestamp = ::GetTickCount();
                        m_pEventKey->Event(event);
                        m_pEventKey = NULL;
                    }
                    break;
                case WM_SETCURSOR:
                    {
                        if( LOWORD(lParam) != HTCLIENT ) break;
                        if( m_bMouseCapture ) return true;
            
                        POINT pt = { 0 };
                        ::GetCursorPos(&pt);
                        ::ScreenToClient(m_hWndPaint, &pt);
                        CControlUI* pControl = FindControl(pt);
                        if( pControl == NULL ) break;
                        if( (pControl->GetControlFlags() & UIFLAG_SETCURSOR) == 0 ) break;
                        TEventUI event = { 0 };
                        event.Type = UIEVENT_SETCURSOR;
                        event.wParam = wParam;
                        event.lParam = lParam;
                        event.ptMouse = pt;
                        event.wKeyState = MapKeyState();
                        event.dwTimestamp = ::GetTickCount();
                        pControl->Event(event);
                    }
                    return true;
                case WM_NOTIFY:
                    {
                        LPNMHDR lpNMHDR = (LPNMHDR) lParam;
                        if( lpNMHDR != NULL ) lRes = ::SendMessage(lpNMHDR->hwndFrom, OCM__BASE + uMsg, wParam, lParam);
                        return true;
                    }
                    break;
                case WM_COMMAND:
                    {
                        if( lParam == 0 ) break;
                        HWND hWndChild = (HWND) lParam;
                        lRes = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
                        return true;
                    }
                    break;
                case WM_CTLCOLOREDIT:
                case WM_CTLCOLORSTATIC:
                    {
                        // Refer To: http://msdn.microsoft.com/en-us/library/bb761691(v=vs.85).aspx
                        // Read-only or disabled edit controls do not send the WM_CTLCOLOREDIT message; instead, they send the WM_CTLCOLORSTATIC message.
                        if( lParam == 0 ) break;
                        HWND hWndChild = (HWND) lParam;
                        lRes = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
                        return true;
                    }
                    break;
                default:
                    break;
                }
            
                pMsg = NULL;
                while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) ) {
                    m_aAsyncNotify.Remove(0);
                    if( pMsg->pSender != NULL ) {
                        if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
                    }
                    for( int j = 0; j < m_aNotifiers.GetSize(); j++ ) {
                        static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
                    }
                    delete pMsg;
                }
            
                return false;
            }
            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            我去這里代碼有點多,先簡單捋一下,首先處理了如下消息:

            WM_CTLCOLOREDIT:
            WM_CTLCOLORSTATIC
            WM_COMMAND:
            WM_NOTIFY:
            WM_SETCURSOR:
            WM_KEYUP
            WM_KEYDOWN
            WM_CHAR
            WM_MOUSEWHEEL
            WM_CONTEXTMENU
            WM_RBUTTONDOWN
            WM_LBUTTONUP
            WM_LBUTTONDBLCLK
            WM_LBUTTONDOWN
            WM_MOUSEMOVE
            WM_MOUSELEAVE
            WM_MOUSEHOVER
            WM_TIMER
            WM_SIZE
            WM_GETMINMAXINFO
            WM_PRINTCLIENT
            WM_PAINT
            WM_ERASEBKGND
            WM_CLOSE
            WM_APP

            除了這些消息還有一個特別的東西需要留意:

            m_aAsyncNotify以后再分析

             

             

            .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

            posted on 2013-03-07 21:39 Enic 閱讀(2223) 評論(0)  編輯 收藏 引用 所屬分類: Duilib
            国产精品久久久久久久久久免费| 亚洲伊人久久综合中文成人网| 无码精品久久久久久人妻中字| 久久超碰97人人做人人爱| 国产精品一区二区久久| 久久国产精品偷99| 亚洲AV无码1区2区久久| 91精品久久久久久无码| 中文精品99久久国产| 亚洲国产成人久久综合碰碰动漫3d | 亚洲精品国精品久久99热| 色婷婷综合久久久久中文一区二区| 国内精品久久久久久久97牛牛 | WWW婷婷AV久久久影片| 久久天天躁狠狠躁夜夜2020老熟妇| 久久精品午夜一区二区福利| 国内精品久久久久久久coent| 色婷婷综合久久久久中文一区二区| 国产日韩久久久精品影院首页| 欧美一区二区三区久久综合| 亚洲精品无码久久久| 久久久久亚洲AV无码专区网站| 国产精品久久久久影视不卡| 亚洲欧美日韩中文久久| 手机看片久久高清国产日韩 | 久久精品一本到99热免费| 武侠古典久久婷婷狼人伊人| 久久se这里只有精品| 国内精品久久久久久麻豆| 国产精品一久久香蕉产线看| 久久婷婷国产综合精品| 亚洲色大成网站www久久九| 无码人妻久久一区二区三区蜜桃 | 99久久这里只精品国产免费| 九九热久久免费视频| 国产午夜精品久久久久九九| 日韩精品久久久久久| 亚洲国产精品人久久| 精品久久久久久久中文字幕| 99久久精品国产一区二区蜜芽| 久久亚洲国产欧洲精品一|