duilib CNotifyPump

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;
};
View Code

这里用的比较好的是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"));
}
View Code

那对应的消息映射跟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);
View Code

但是这里发现一个小问题,就是控件为CEditUI并且里面的内容被选中的时候,使用tooltip鼠标只有在控件的边缘才能显示出来,在编辑框的内部时候却无法显示,具体这个则是因为CEditUI内部使用了系统默认的CEdit控件。

原文地址:https://www.cnblogs.com/cxiaoln/p/4421109.html