• C++ FastDelegate 扩展,实现与.net类似的事件处理功能


    熟悉.NET的人都知道,  .NET使用委托可以快速实现观察者模式,免去写很多繁杂重复的代码。遗憾的是,C++并没有提供这样的模型,为了达到相似的目的,需要继承一个类并重写virtual方法,这种做法需要写很多代码,效率比较低下。然而,在强大的C++面前,没有什么是不可能的,已经有很多人针对这个问题进行过研究,并且实现了各种委托模型,其中最著名的就是FastDelegate。为了让使用FastDelegate更象.NET,我新添加几个模板,主要如下:

    首先添加一个两个类用于模拟事件发生源及事件参数类:

       1: // 定义事件发送源(类似于.net的sender)
       2: class IEventSource
       3: {
       4: public:
       5:     virtual ~IEventSource (){}
       6: };
       7:  
       8: using namespace fastdelegate;
       9:  
      10: // 定义标准的事件参数
      11: class CEventArgs
      12: {
      13: public:
      14:     CEventArgs (void)
      15:     {
      16:         bHandled = FALSE;
      17:     }
      18:  
      19:     BOOL    bHandled;
      20: };

    然后是定义一个事件句柄管理类:

       1: // 定义事件句柄,用于管理事件中加入的委托
       2: template <class TBase>
       3: class CEventHandlerBase
       4: {
       5: public:
       6:     virtual ~CEventHandlerBase ()
       7:     {
       8:         for (int i = _delegates.GetSize () - 1; i >= 0; i --)
       9:         {
      10:             delete (TBase*) _delegates[i];
      11:         }
      12:         _delegates.Empty ();
      13:     }
      14:  
      15:     size_t GetCount (void) { return _delegates.GetSize (); }
      16:  
      17:     // 添加委托
      18:     void operator += (TBase& eventDelegate)
      19:     {
      20:         _delegates.Add (new TBase (eventDelegate));
      21:     }
      22:  
      23:     // 删除委托
      24:     void operator -= (TBase& eventDelegate)
      25:     {
      26:         for (int i = _delegates.GetSize () - 1; i >= 0; i --)
      27:         {
      28:             if (*((TBase*) _delegates[i]) == eventDelegate)
      29:             {
      30:                 delete (TBase*) _delegates[i];
      31:                 _delegates.Remove (i);
      32:             }
      33:         }
      34:     }
      35:  
      36: public:
      37:     CStdPtrArray _delegates;
      38: };

    最后定义一个宏用于快速创建事件句柄:

       1: // 定义生成事件句柄的类 handleClass 为句柄类名称,eventClass 为参数类名称
       2: #define DEFINE_EVENT_HANDLER(handleClass, eventClass) 
       3:     typedef FastDelegate2<IEventSource *, eventClass *> eventClass##Delegate;
       4:     class UILIB_API handleClass : public CEventHandlerBase<eventClass##Delegate>
       5:     {
       6:         public:
       7:         void Fire (IEventSource* sender, eventClass* e)
       8:         {
       9:             for (int i = _delegates.GetSize () - 1; i >= 0; i --)
      10:             {
      11:                 (*(eventClass##Delegate*) _delegates[i]) (sender, e);
      12:             }
      13:         }
      14:     }
      15:  
      16: DEFINE_EVENT_HANDLER (CStdEventHandler, CEventArgs);

    使用如有两种情况,一是只用CEventArgs参数类型就可以满足要求,二是需扩展自己的参数类型。如果需要扩展参数,代码如下:

       1: class CMouseEventArgs : public CEventArgs
       2: {
       3: public:
       4:     CMouseEventArgs (MouseButtons button1, int clicks1, int x1, int y1, int delta1);
       5:  
       6:     MouseButtons button; int clicks; int x; int y; int delta;
       7: };
       8:  
       9: // void handler (IEventSource* sender, CMouseEventArgs* e);
      10: DEFINE_EVENT_HANDLER (CMouseEventDelegate, CMouseEventArgs);

    应用代码示例如下:

       1: class CGlobalWindowMsgHook : public IEventSource
       2: {
       3: private:
       4:     CGlobalWindowMsgHook (void);
       5: public:
       6:     ~CGlobalWindowMsgHook (void);
       7:  
       8:     static CGlobalWindowMsgHook* instance (void);
       9:  
      10:     // 定义鼠标点击事件
      11:     CMouseEventDelegate MouseClick;
      12:  
      13:     ……
      14: protected:
      15:     static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
      16:     {
      17:         CGlobalWindowMsgHook* This = instance();
      18:         PMSLLHOOKSTRUCT hookStruct = (PMSLLHOOKSTRUCT)lParam;
      19:         
      20:         int msg = wParam;
      21:         int x = hookStruct->pt.x;
      22:         int y = hookStruct->pt.y;
      23:         int delta = (short)((hookStruct->mouseData >> 16) & 0xffff);
      24:         
      25:         if (msg == WM_LBUTTONUP)
      26:         {
      27:             // 触发鼠标点击事件
      28:             This->MouseDown.Fire (This, &CMouseEventArgs (Left, 0, x, y, delta));
      29:         }
      30:         ……
      31:     }
      32:     ……
      33: };
      34:  
      35: // 测试类
      36: class CTest
      37: {
      38: public:
      39:     CTest ()
      40:     {
      41:         CGlobalWindowMsgHook::instance()->MouseClick += MakeDelegate (this, &CTest::MouseDownHandler);
      42:     }
      43:     ~CTest ()
      44:     {
      45:         CGlobalWindowMsgHook::instance()->MouseClick -= MakeDelegate (this, &CTest::MouseDownHandler);
      46:     }
      47:  
      48:     void MouseDownHandler (IEventSource* sender, CMouseEventArgs* e)
      49:     {
      50:         printf (_T("hello"));
      51:     }
      52: }
  • 相关阅读:
    .NET设计模式外观模式(Façade Pattern)
    .NET设计模式创建型模式专题总结(Creational Pattern)
    MFC深入浅出消息映射的实现
    .NET设计模式代理模式(Proxy Pattern)
    .NET设计模式工厂方法模式(Factory Method)
    Web Services Security (转)
    MYSQL数据库的查询优化技术
    U盘插入拔出提示
    SQL存储过程(ASP.NET)
    在SQL Server中使用种子表生成流水号注意顺序
  • 原文地址:https://www.cnblogs.com/ihaoqi/p/3239156.html
Copyright © 2020-2023  润新知