第一章 第四小節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

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