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