您好,登錄后才能下訂單哦!
在Redrain duilib中,委托模式將事件發(fā)送與事件處理進行了解耦,并預(yù)定義了六個事件處理函數(shù)的原型,具體如下(對應(yīng)源文件UIDelegate.h):
typedef bool (*FunVoid)(void* pParam,LPARAM lParam,WPARAM wParam); typedef bool (*FunTEvent)(TEventUI* pTEventUI,LPARAM lParam,WPARAM wParam); typedef bool (*FunTNotify)(TNotifyUI* pTNotifyUI,LPARAM lParam,WPARAM wParam); typedef bool (T::*CMFunVoid)(void* pParam,P lParam,WPARAM wParam); typedef bool (T::*CMFunTEvent)(TEventUI* pTEventUI,P lParam,WPARAM wParam); typedef bool (T::*CMFunTNotify)(TNotifyUI* pTNotifyUI,P lParam,WPARAM wParam);
如果利用如下代碼給pCtrl控件的OnNotify添加一個委托函數(shù):
pCtrl->OnNotify += MakeDelegate<CTestWnd, CTestWnd, LPARAM>(this, &CTestWnd::OnTest);
其中CTestWnd::OnTest的定義如下:
bool CTestWnd::OnTest(void *pParam, LPARAM lParam, WPARAM wParam) { return true; }
分析下起處理流程:
1、用戶操作導(dǎo)致pCtrl發(fā)送某個事件;
2、調(diào)用CPaintManagerUI::MessageHandler;
3、在CPaintManagerUI::MessageHandler函數(shù)內(nèi)部調(diào)用pMsg->pSender->OnNotify(pMsg)。這里的pMsg->pSender是上面所說的pCtrl;
4、OnNotify是pCtrl的一個成員變量,對應(yīng)的類是CEventSource,該類對()進行了操作符重載,第3步中pMsg->pSender->OnNotify(pMsg),實際調(diào)用的是:
bool CEventSource::operator() (TNotifyUI* pTNotifyUI) { for( int i = 0; i < m_aDelegates.GetSize(); i++ ) { CDelegateBase* pObject = m_aDelegates.GetAt(i); if( pObject && !pObject->Invoke(pTNotifyUI,pObject->GetLParam(),pObject->GetWParam()) ) return false; } return true; }
而不是bool CEventSource::operator() (void* param) 和bool CEventSource::operator() (TEventUI* pTEventUI)。因為pMsg的類型是TNotifyUI。
5、第4部中調(diào)用Invoke函數(shù)如下:
virtual bool Invoke(TNotifyUI* pTNotifyUI,LPARAM lParam = NULL,WPARAM wParam = NULL) { O* pObject = (O*) GetObj(); if(pObject && GetNotifyTypeName().IsEmpty()) return (pObject->*m_pCMFunTNotify)(pTNotifyUI,(P)GetLParam(),GetWParam()); else if(pObject && pTNotifyUI && pTNotifyUI->sType == GetNotifyTypeName()) return (pObject->*m_pCMFunTNotify)(pTNotifyUI,(P)GetLParam(),GetWParam()); return true; };
他會調(diào)用pObject->*m_pCMFunTNotify。
問題來了,最開始我們調(diào)用
pCtrl->OnNotify += MakeDelegate<CTestWnd, CTestWnd, LPARAM>(this, &CTestWnd::OnTest);
MakeDelegate根據(jù)傳遞的參數(shù)以及CTestWnd::OnTest的函數(shù)原型,通過構(gòu)成函數(shù)
CDelegate(O* pObj, CMFunVoid pCMFunVoid,P lParam = NULL,WPARAM wParam = NULL) : CDelegateBase(pObj, *(FunVoid*)&pCMFunVoid,(LPARAM)lParam,wParam) , m_pCMFunVoid(pCMFunVoid) ,m_pCMFunTEvent(NULL) ,m_pCMFunTNotify(NULL) {}
得到一個委托對象,并添加到pCtrl->OnNotify中。很顯然,構(gòu)造的這個委托對象的m_pCMFunTNotify為NULL,而在第5步中卻調(diào)用了m_pCMFunTNotify,進而導(dǎo)致崩潰。
從上面的分析看,
typedef bool (*FunVoid)(void* pParam,LPARAM lParam,WPARAM wParam); typedef bool (*FunTEvent)(TEventUI* pTEventUI,LPARAM lParam,WPARAM wParam); typedef bool (T::*CMFunVoid)(void* pParam,P lParam,WPARAM wParam); typedef bool (T::*CMFunTEvent)(TEventUI* pTEventUI,P lParam,WPARAM wParam);
是不能使用的,除非對相關(guān)代碼進行進一步修改。
另外,對菜單項不要使用委托模式。如果使用了,在菜單項對應(yīng)的函數(shù)中彈出對話框時,會出現(xiàn)異常情況。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。