第一章 第四小节Duilib的WindowImplBase基类(二)--CNotifyPump

  CNotifyPump是duilib的消息泵功能根父类,它实现的主要功能是虚拟窗口的维护和消息分发。如下所示:

// Structure for notifications to the outside world
typedef struct tagTNotifyUI
    {
        CDuiString sType;//消息类型
        CDuiString sVirtualWnd;//虚拟窗口
        CControlUI* pSender;//那个窗口发送
        DWORD dwTimestamp;
        POINT ptMouse;
        WPARAM wParam;
        LPARAM lParam;
    } TNotifyUI;
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()//类似mfc的消息映射机制
    private:
        CStdStringPtrMap m_VirtualWndMap;
    };

  请先阅读以上的代码注释,每一项都比较详细。然后就是还需要明白一些特定的概念,比如什么是虚拟窗口,字面意识就是假窗口,实际上的意思也差不多,指不是用win32函数创建的假窗口,但具有窗口的一部分功能。在这种假窗口中,demo里有个例子,就是RichListDemo,就是创建两个Tab子窗口。这两个Tab就是虚拟窗口,实现方式如下所示:

class CPage1 : public CNotifyPump
{
public:
	CPage1();
	void SetPaintMagager(CPaintManagerUI* pPaintMgr);

	DUI_DECLARE_MESSAGE_MAP()
	virtual void OnClick(TNotifyUI& msg);
	virtual void OnSelectChanged( TNotifyUI &msg );
	virtual void OnItemClick( TNotifyUI &msg );
private:
	CPaintManagerUI* m_pPaintManager;
};

  以上可以明白,虚拟窗口一般就是直接或者间接继承至CNotifyPump,当然不能继承至上一小节中的CWindowWnd,它创建了实际的win32窗口。
  那实际真正的消息是如何传递的呢?在NotifyPump函数中实现的,如下所示:

void CNotifyPump::NotifyPump(TNotifyUI& msg)
{
    if( !msg.sVirtualWnd.IsEmpty() ){
        for( int i = 0; i< m_VirtualWndMap.GetSize(); i++ ) {
            if( LPCTSTR key = m_VirtualWndMap.GetAt(i) ) {//虚拟窗口名
                if( _tcsicmp(key, msg.sVirtualWnd.GetData()) == 0 ){//消息中的窗口名是否一致
                    CNotifyPump* pObject = static_cast<CNotifyPump*>(m_VirtualWndMap.Find(key, false));
                    if( pObject && pObject->LoopDispatch(msg) )
                        return;
                }
            }
        }
    }
    LoopDispatch( msg );
}

  它实现的功能是查找本身虚拟窗口列表,查找对应虚拟窗口对象的LoopDispatch函数,如果存在,则调用对应的LoopDispatch函数,否则调用本身的LoopDispatch函数。如下所示:

bool CNotifyPump::LoopDispatch(TNotifyUI& msg)
{
    const DUI_MSGMAP_ENTRY* lpEntry = NULL;//消息列表
    const DUI_MSGMAP* pMessageMap = NULL;

//先获取本身的响应函数列表,接着再循环父类的响应函数列表
#ifndef UILIB_STATIC
    for(pMessageMap = GetMessageMap(); pMessageMap!=NULL; pMessageMap = (*pMessageMap->pfnGetBaseMap)())
#else
    for(pMessageMap = GetMessageMap(); pMessageMap!=NULL; pMessageMap = pMessageMap->pBaseMap)
#endif
    {
#ifndef UILIB_STATIC
        ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
#else
        ASSERT(pMessageMap != pMessageMap->pBaseMap);
#endif
        if ((lpEntry = DuiFindMessageEntry(pMessageMap->lpEntries,msg)) != NULL)//消息查找
        {
            goto LDispatch;
        }
    }
    return false;
//找到对应的消息,则采用对应的函数调用。
LDispatch:
    union DuiMessageMapFunctions mmf;
    mmf.pfn = lpEntry->pfn;

    bool bRet = false;
    int nSig;
    nSig = lpEntry->nSig;
    switch (nSig)
    {
    default:
        ASSERT(FALSE);
        break;
    case DuiSig_lwl:
        (this->*mmf.pfn_Notify_lwl)(msg.wParam,msg.lParam);// 跟普通函数指针不同,不能使用成员函数指针直接调用成员函数,而是要通过.*和->*运算符将成员函数指针和类对象或指向对象的指针绑定起来
        bRet = true;
        break;
    case DuiSig_vn:
        (this->*mmf.pfn_Notify_vn)(msg);//调用对应的响应函数
        bRet = true;
        break;
    }
    return bRet;
}

  使用成员函数指针:跟普通函数指针不同,不能使用成员函数指针直接调用成员函数,而是要通过.* ->*运算符将成员函数指针和类对象或指向对象的指针绑定起来。
  本章内容相对复杂些,再小节下,目标窗口继承至WindowImplBase基类,外部获取或者其它位置调用SendNotify函数,它再调用WindowImplBase基类的Notify函数,Notify函数实际调用的是CNotifyPump::NotifyPump(msg)函数,再由此进入消息的后续处理。


  欢迎光临知了软件开发网络平台,本公司定制开发各类软件,主要方向为桌面专业软件开发和插件定制开发,桌面软件主要包括文字图形识别类软件,信息管理类软件,3D打印类软件,视频类软件以及其它涉及专业的各类图形图像处理软件。插件包含AE插件,AI插件,PS插件,PDF插件,3DMAX插件以及Word,Excel等Office插件开发。详情请咨询,微信QQ:312117271,手机:18928899728,邮箱: [email protected].
公司网址:http://www.zhiliaos.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章