您当前的位置: 首页 >  ui

插件开发

暂无认证

  • 1浏览

    0关注

    492博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

第一章 第三小节Duilib的事件委托

插件开发 发布时间:2022-03-22 08:07:44 ,浏览量:1

文章目录
    • 1.事件委托
    • 2.作者答疑

1.事件委托

  在win32中,非常常见的各类消息,但消息的源头是各类事件,那在duilib中,是如何实现各种事件以供sdk运行的呢?首先,它定义了一个CDelegateBase基类,如下所示:

class UILIB_API CDelegateBase     
{
public:
    CDelegateBase(void* pObject, void* pFn);
    CDelegateBase(const CDelegateBase& rhs);
    virtual ~CDelegateBase();
    bool Equals(const CDelegateBase& rhs) const;
    bool operator() (void* param);
    virtual CDelegateBase* Copy() const = 0; // add const for gcc

protected:
    void* GetFn();
    void* GetObject();
    virtual bool Invoke(void* param) = 0;

private:
    void* m_pObject;
    void* m_pFn;
};

  它是一个纯虚函数,有Invoke和Copy两个接口,一个用于调用这个委托的实现(Invoke),另一个用于构建委托在内存中的副本时使用(Copy)。有了纯虚函数的范本,接下来有两种具体实现,一种是全局静态函数,另一种是对象内部函数。如下所示:

class CDelegateStatic: public CDelegateBase
{
    typedef bool (*Fn)(void*);
public:
    CDelegateStatic(Fn pFn) : CDelegateBase(NULL, pFn) { } 
    CDelegateStatic(const CDelegateStatic& rhs) : CDelegateBase(rhs) { } 
    virtual CDelegateBase* Copy() const { return new CDelegateStatic(*this); }

protected:
    virtual bool Invoke(void* param)//不需要传递实体对象
    {
        Fn pFn = (Fn)GetFn();
        return (*pFn)(param); 
    }
};

  另一种是对象内部函数,这时候为了应对各种不同类型对象的抽象,采用了C++的模板机制,如下所示:

template //对象及对象下的函数类型
class CDelegate : public CDelegateBase
{
    typedef bool (T::* Fn)(void*);
public:
    CDelegate(O* pObj, Fn pFn) : CDelegateBase(pObj, &pFn), m_pFn(pFn) { }
    CDelegate(const CDelegate& rhs) : CDelegateBase(rhs) { m_pFn = rhs.m_pFn; } 
    virtual CDelegateBase* Copy() const { return new CDelegate(*this); }

protected:
    virtual bool Invoke(void* param)
    {
        O* pObject = (O*) GetObject();
        return (pObject->*m_pFn)(param); 
    }  

private:
    Fn m_pFn;
};

  有了两种不同的委托对象的实现,接着就有两种常用的全局构造,如下所示:

template 
CDelegate MakeDelegate(O* pObject, bool (T::* pFn)(void*))//根据参数识别类型
{
    return CDelegate(pObject, pFn);
}
inline CDelegateStatic MakeDelegate(bool (*pFn)(void*))
{
    return CDelegateStatic(pFn); 
}

  最后才是委托对象真正的使用位置,事件源对象,它的内部就是委托对象的指针数组,如下所示:

class UILIB_API CEventSource
{
    typedef bool (*FnType)(void*);
public:
    ~CEventSource();
    operator bool();
    void operator+= (const CDelegateBase& d); // add const for gcc
    void operator+= (FnType pFn);
    void operator-= (const CDelegateBase& d);
    void operator-= (FnType pFn);
    bool operator() (void* param);
    void Clear();

protected:
    CStdPtrArray m_aDelegates;
};

  事件源类在Duilib中使用位置,就在CControlUI这个所有控件的基类里,如下所示;

    public:
        CEventSource OnInit;
        CEventSource OnDestroy;
        CEventSource OnSize;
        CEventSource OnEvent;
        CEventSource OnNotify;

  分为上述5种事件源,特别是OnNotify事件源,参数实现duilib中的自定义消息循环。具体实现查看下一小节,在duilib中的消息传递。

2.作者答疑

  如有疑问,请留言。

关注
打赏
1665481431
查看更多评论
立即登录/注册

微信扫码登录

0.0409s