- 1.CNotifyPump类
- 2.作者答疑
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; iLoopDispatch(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)函数,再由此进入消息的后续处理。
2.作者答疑如有疑问,请留言。