CNotifyPump 主要进行的是消息的映射还有相关VirtualWnd的操作
class UILIB_API CNotifyPump { public: bool AddVirtualWnd(CDuiString strName,CNotifyPump* pObject); bool RemoveVirtualWnd(CDuiString strName); void NotifyPump(TNotifyUI& msg); bool LoopDispatch(TNotifyUI& msg); DUI_DECLARE_MESSAGE_MAP() private: CStdStringPtrMap m_VirtualWndMap; };
这里用的比较好的是WinImplBase,在OnNotify中调用NotifyPump,当主窗口中有虚拟窗口,并且AddVirtualWnd之后,则会在调用主窗口的OnNotify之后,要去调用父类的__super::OnNotify。具体可以看官方demo中的RichListDemo
void CRichListWnd::Notify( TNotifyUI &msg ) { return WindowImplBase::Notify(msg); } CRichListWnd::CRichListWnd(void) { m_Page1.SetPaintMagager(&m_PaintManager); m_Page2.SetPaintMagager(&m_PaintManager); AddVirtualWnd(_T("page1"),&m_Page1); AddVirtualWnd(_T("page2"),&m_Page2); } CRichListWnd::~CRichListWnd(void) { RemoveVirtualWnd(_T("page1")); RemoveVirtualWnd(_T("page2")); }
那对应的消息映射跟MFC中的消息映射差不多。
声明中:DUI_DECLARE_MESSAGE_MAP()
最主要的是里面的virtual const DUI_MSGMAP* GetMessageMap() const; 是virtual函数
所以在CNotifyPump调用GetMessageMap的时候会去调用子类的GetMessageMap
结论:所以当使用消息映射的时候就必须继承CNotifyPump类。
特别是使用虚拟窗口的时候,因为没有具体的control父类,所以必须也只能使用CNotifyPump来进行消息映射。
那系统是如何知道当前的控件是属于虚拟窗口的呢?
1、在解析xml的时候当遇到virtualwnd的属性名字,则会调用对应的
void CControlUI::SetVirtualWnd(LPCTSTR pstrValue) { m_sVirtualWnd = pstrValue; m_pManager->UsedVirtualWnd(true); }
然后当某个控件发生消息响应的时候在void CPaintManagerUI::SendNotify(TNotifyUI& Msg, bool bAsync /*= false*/)函数中会有该操作:
if( m_bUsedVirtualWnd ) { Msg.sVirtualWnd = Msg.pSender->GetVirtualWnd(); }
具体该GetVirtualWnd则可以看CControlUI的GetVirtualWnd函数,当本身的虚拟窗口的名称是空的时候则会父节点查找是否是父窗口。
这样的一系列操作之后,当调用CNotifyPump::NotifyPump的时候则就可以判断该控件是属于哪个虚拟窗口,进而通过Loopdispatch中查找该虚拟窗口对应的消息事件,并响应对应的事件操作。
注意:当前的主窗口要添加对应的虚拟窗口,否则在NotifyPump中即使本身是虚拟窗口也无法被找到。
AddVirtualWnd(_T("page1"),&m_Page1);
然后在析构的时候则需要RemoveVirtualWnd(_T("page1"));
================================================
这里额外说一下tooltip,刚开始一直不知道duilib使用什么机制进行显示的
当鼠标在某个控件上停留(WM_MOUSEHOVER)并且该控件有对应的tooltip内容,则程序会显示相应的内容。
具体是bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)的WM_MOUSEHOVER
// 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_SETMAXTIPWIDTH,0, pHover->GetToolTipWidth()); ::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM) &m_ToolTip); ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);
但是这里发现一个小问题,就是控件为CEditUI并且里面的内容被选中的时候,使用tooltip鼠标只有在控件的边缘才能显示出来,在编辑框的内部时候却无法显示,具体这个则是因为CEditUI内部使用了系统默认的CEdit控件。