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以后再分析
- Duilib 窗口流程
- duilib 窗口问题
- Duilib登录窗口
- DUILIB创建菜单窗口
- duilib : 窗口拖动
- duilib : 模态窗口
- DUILIB异形窗口实现
- DUILIB异形窗口实现
- DUILIB创建菜单窗口
- duilib : 模态窗口
- DUILIB异形窗口实现
- duilib 无标题窗口拖动
- duilib 消息流程
- duilib基本流程
- duilib创建可拖动窗口
- DuiLib 通用窗口类封装
- DuiLib窗口增加阴影效果
- Duilib中消息流程分析
- frame中如何引入WEB-INF中的jsp页面
- eclipse下android模拟器安装
- vsftpd安装和配置(备忘)
- 关于STM32中GPIO的8种工作模式
- 欢迎使用CSDN-markdown编辑器
- Duilib 窗口流程
- Educational Codeforces Round 2 E - Lomsat gelral(树形dp+启发式合并)
- Git 的 .gitignore 配置
- OSPF建立邻居、邻接关系
- jQuery Easing 使用方法及其图解
- 字符串分割,字符串拷贝,单词逆置,单词逆置
- jquery.datatables.js表格编辑与删除
- [python标准库]math——数学函数
- 自动化测试工具selenium初探