1、CDelegate类:成员主要包含:函数的指针、函数所属对象的指针、invoke函数和其他方便使用的重载操作符;其实就是保存了一个对象指针和它的一个成员函数的指针,invoke函数用于调用对象的成员函数。
class CDelegateBase
{
public:
CDelegateBase(void*pObject, void* pFn);
CDelegateBase(constCDelegateBase& rhs);
virtual~CDelegateBase();
bool Equals(constCDelegateBase& rhs) const;
bool operator()(void* param);
virtualCDelegateBase* Copy() const = 0; // add const for gcc
protected:
void* GetFn();
void* GetObject();
virtualbool Invoke(void* param) = 0;
private:
void* m_pObject;
void* m_pFn;
};
template <class O, class T>
class CDelegate : public CDelegateBase
{
typedefbool (T::* Fn)(void*);
public:
CDelegate(O*pObj, Fn pFn) : CDelegateBase(pObj, &pFn), m_pFn(pFn) { }
CDelegate(constCDelegate& rhs) : CDelegateBase(rhs) { m_pFn = rhs.m_pFn; }
virtualCDelegateBase* Copy() const { return new CDelegate(*this); }
protected:
virtualbool Invoke(void* param)
{
O* pObject= (O*) GetObject();
return(pObject->*m_pFn)(param);
}
private:
Fn m_pFn;
};
2、CEventSource类:主要成员变量:事件代理指针数组、重载的各个操作符;注意:CEventSource的+=操作符,将事件代理CDelegate对象保到其成员变量中;在需要的时候可以调用代理中的函数(通过invoke函数),例如:点击按钮时,见下面的实例。
classUILIB_API CEventSource
{
…
typedef bool (*FnType)(void*);
public:
~CEventSource();
void operator+= (const CDelegateBase& d);// add const for gcc
void operator+= (FnType pFn);
void operator-= (const CDelegateBase& d);
bool operator() (void* param);
protected:
CStdPtrArray m_aDelegates; //事件代理指针数组
};
3、MakeDelegate宏用于生成一个CDelegate对象。
template<class O, class T>
CDelegate<O,T> MakeDelegate(O* pObject, bool (T::* pFn)(void*))
{
return CDelegate<O, T>(pObject, pFn);
}
4、实例:
voidCFrameWindowWnd::OnPrepare()
{
CButtonUI* pBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("ButtonTest")));//获取控件
if( pBtn)
pBtn->OnNotify += MakeDelegate(this, &CFrameWindowWnd::OnBtnTest); //
}
boolCFrameWindowWnd::OnBtnTest(void* param)
{
TNotifyUI * msg =( TNotifyUI*) param;
if (msg.sType == DUI_MSGTYPE_CLICK)
{
//do something
}
Return true;
}
注意!上面OnNotify为在Control里面定义的CEventSource对象,在PaintManager的MessageHandler消息处理函数中调用,在此不用显式调用CEventSource;Duilib中的所有控件可以像上面那样用。
自定义的CEventSource需要在适当的地方自己调用,调用方法很简单,使用重载的 ()操作符。
//自定义CEventSource
CEventSourcecustomEvent;
还要像上面那样初始化(+=操作),在此省略。
voidCFrameWindowWnd::Notify( TNotifyUI& msg )
{
if (msg.sType == DUI_MSGTYPE_CLICK)
{
if (msg.pSender->GetName()== _T("ButtonTest "))
{
// 在此自己调用
customEvent((void*)msg);//参数如果不需要可以设为NULL
}
}
}
5、在使用时,可以在A类中定义CEventSource eA; eA可以绑定到B类中的函数进行处理;相当于在A中调用了B的函数。
简单举例:
A {
public:
CEventSource eA;
}
B{
Protected:
Am_a;
VoidInit()
{
m_a+= MakeDelegate (this, B::Fb);
}
boolFb(void *)
{
Returntrue;
}
}