Redrain duilib中事件委托存在的问题

  

在Redrain duilib中,委托模式将事件发送与事件处理进行了解耦,并预定义了六个事件处理函数的原型,具体如下(对应源文件UIDelegate。h):

typedef  bool  (* FunVoid) (void *, pParam, LPARAM  lParam, WPARAM 按钮);   typedef  bool  (* FunTEvent) (TEventUI *, pTEventUI, LPARAM  lParam, WPARAM 按钮);   typedef  bool  (* FunTNotify) (TNotifyUI *, pTNotifyUI, LPARAM  lParam, WPARAM 按钮);   typedef  bool  (T:: * CMFunVoid) (void *, pParam, P  lParam, WPARAM 按钮);   typedef  bool  (T:: * CMFunTEvent) (TEventUI *, pTEventUI, P  lParam, WPARAM 按钮);   typedef  bool  (T:: * CMFunTNotify) (TNotifyUI *, pTNotifyUI, P  lParam, WPARAM 按钮),


如果利用如下代码给pCtrl控件的OnNotify添加一个委托函数:

pCtrl→OnNotify  +=, MakeDelegate (,,, CTestWnd::击打);

其中CTestWnd::击打的定义如下:

bool  CTestWnd:击打(void  * pParam, LPARAM  lParam,, WPARAM 按钮)   {   ,,,return 真实;   }


分析下起处理流程:

1,用户操作导致pCtrl发送某个事件;

2,调用CPaintManagerUI:: MessageHandler;

3,在CPaintManagerUI:: MessageHandler函数内部调用pMsg→pSender→OnNotify (pMsg)。这里的pMsg→pSender是上面所说的pCtrl;

4, OnNotify是pCtrl的一个成员变量,对应的类是CEventSource,该类对()进行了操作符重载,第3步中pMsg→pSender→OnNotify (pMsg),实际调用的是:

bool  CEventSource::操作符(),(TNotifyUI *, pTNotifyUI),   {   (,int 小姐:=,0;,小姐:& lt;, m_aDelegates.GetSize();,我+ +,),{   时间=CDelegateBase *, pObject  m_aDelegates.GetAt(我);      如果,pObject ,,, ! pObject→调用(pTNotifyUI, pObject→GetLParam (), pObject→GetWParam ()),), return 假;   }   return 真实;   }

而不是bool CEventSource::操作符()(void *参数)和bool CEventSource::操作符()(TEventUI * pTEventUI)。因为pMsg的类型是TNotifyUI。

5,第4部中调用调用函数如下:

virtual  bool 调用(TNotifyUI *, pTNotifyUI, LPARAM  LPARAM =, NULL, WPARAM  WPARAM =, NULL)   {   啊,,,*,pObject =, (O *), GetObj ();   ,,,如果(pObject ,,, GetNotifyTypeName () .IsEmpty ())   ,,,,,,,return  (pObject→* m_pCMFunTNotify) (pTNotifyUI, (P) GetLParam (), GetWParam ());   ,,,else 如果(pObject ,,, pTNotifyUI ,,, pTNotifyUI→sType ==, GetNotifyTypeName ())   ,,,,,,,return  (pObject→* m_pCMFunTNotify) (pTNotifyUI, (P) GetLParam (), GetWParam ());   ,,,,,,,   ,,,return 真实;   };

他会调用pObject→* m_pCMFunTNotify。


问题来了,最开始我们调用

pCtrl→OnNotify  +=, MakeDelegate (,,, CTestWnd::击打);

MakeDelegate根据传递的参数以及CTestWnd::击打的函数原型,通过构成函数

CDelegate (O *, pObj,, CMFunVoid  pCMFunVoid, P  lParam =, NULL, WPARAM  WPARAM =, NULL)   ,:CDelegateBase (pObj, * (FunVoid *), pCMFunVoid, (LPARAM) LPARAM按钮)   ,,m_pCMFunVoid (pCMFunVoid)   ,,m_pCMFunTEvent(空)   ,,m_pCMFunTNotify(空)   以前,{}

得到一个委托对象,并添加到pCtrl→OnNotify中。很显然,构造的这个委托对象的m_pCMFunTNotify为零,而在第第五步中却调用了m_pCMFunTNotify,进而导致崩溃。


从上面的分析看,

typedef  bool  (* FunVoid) (void *, pParam, LPARAM  lParam, WPARAM 按钮);   typedef  bool  (* FunTEvent) (TEventUI *, pTEventUI, LPARAM  lParam, WPARAM 按钮);   typedef  bool  (T:: * CMFunVoid) (void *, pParam, P  lParam, WPARAM 按钮);   typedef  bool  (T:: * CMFunTEvent) (TEventUI *, pTEventUI, P  lParam, WPARAM 按钮),

是不能使用的,除非对相关代码进行进一步修改。


另外,对菜单项不要使用委托模式。如果使用了,在菜单项对应的函数中弹出对话框时,会出现异常情况。

Redrain duilib中事件委托存在的问题