Duilib 窗口流程

来源:互联网 发布:淘宝购物节 编辑:程序博客网 时间:2024/04/29 07:31

从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以后再分析

 

0 0
原创粉丝点击