1 消息处理
在duilib中我们一般会创建一个继承WindowImplBase的窗口,然后重写Notify函数,在Notify函数中处理控件消息,比如button的消息类型就是click,代码如下所示:
class MyWnd :public DuiLib::WindowImplBase{
...
virtual void Notify(DuiLib::TNotifyUI& msg) override;
};
void MyWnd::Notify(DuiLib::TNotifyUI& msg)
{
if (msg.sType == _T("click")){
}
}
那么内部是怎么调用notify这个函数进行消息通知的呢?
2 Notify调用过程
以button的点击消息为例,在notify函数中打上断点,点击按钮,堆栈信息如下:
通过堆栈信息,我们就可以很清晰的看到消息传递过程,从下往上看。
2.1 MessageLoop
在使用duilib中,我们会使用DuiLib::CPaintManagerUI::MessageLoop()
来接收系统消息,代码实现如下:
void CPaintManagerUI::MessageLoop()
{
MSG msg = {
0 };
while( ::GetMessage(&msg, NULL, 0, 0) ) {
if( !CPaintManagerUI::TranslateMessage(&msg) ) {
::TranslateMessage(&msg);
try{
::DispatchMessage(&msg);
} catch(...) {
DUITRACE(_T("EXCEPTION: %s(%d)\n"), __FILET__, __LINE__);
#ifdef _DEBUG
throw "CPaintManagerUI::MessageLoop";
#endif
}
}
}
}
基本流程和win32程序差不多。通常我们写win32程序的时候,会通过GetMessage
获取消息队列所有的消息,再通过TranslateMessage
转义消息,DispatchMessage
分发消息,最后通过注册一个回调函数来处理消息。
通过堆栈信息显示停留在堆栈显示停留在 ::DispatchMessage(&msg)
这一行,那么duilib肯定也注册了一个回调函数来处理系统消息,通过堆栈可以发现是__WndProc
。
2.2 __WndProc
__WndProc的实现思路就是先获取窗口指针,然后调用窗口各自的HandleMessage函数处理消息,代码如下:
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)