【问题标题】:Subscribing to events of one class in other订阅另一个类的事件
【发布时间】:2013-01-23 13:19:50
【问题描述】:

在我的 C++ 程序中,我创建了一个图像按钮控件,该控件具有图像按钮和点击测试功能,以确定鼠标是否在视频内单击。

class ImageButton{
public:
ImageButton(int xPos, int yPos, int width, int height);
virtual void onMousePress(); //triggered internally if the mouse clicked inside the button
virtual void onMousePressOutside() //triggered internally if the mouse clicked outside the button
private:
bool hitTest(int, int); //check if is in bounds
};

现在,我必须在另一个地方使用ImageButton 控件。因为,我来自 C#,所以我记得很容易使用控件并订阅它们的事件,例如

btnControl.Click += new MouseClickEventHandler(Sender e, EVentArgs e)

我刚刚开始使用 Poco 库在 C++ 中获得类似的事件订阅功能,但想问我如何创建这样一个可以在我的第二类和 onMousePress 中订阅的事件 @987654327 @ 触发第二个类中的订阅函数?

【问题讨论】:

标签: c# c++ poco


【解决方案1】:

一种方法是应用观察者设计模式。例如,ImageButton 类接收事件,感兴趣的客户端对象将注册到 ImageButton。在事件发生时,ImageButton 会通知所有注册的客户,而这些客户又负责在他们认为合适的情况下对事件做出反应。

如果您的库提供信号/槽机制,另一种类似的方法是使用信号/槽机制。根据我自己的经验,我更喜欢显式观察者模式应用程序而不是信号和插槽,因为程序中的执行流程是显式可见的。当广泛使用单/槽机制时,在某些时候事情开始神奇地发生,很难知道程序在做什么。

多年来,我们一直在我们的产品中将支持信号和插槽的 Qt 用于 GUI。过去,信号和槽无处不在。但是我们改变了我们的政策,只在严格的 GUI 代码中使用它,并且由于上述原因不再让它传播到业务代码中。

【讨论】:

    【解决方案2】:

    为了解决上述问题,我会执行以下操作,请检查它是否对您有帮助。

    class EventData
    {
    };
    
    // base class for all the secondary classes which expect to get a call back control from
    // the first object where we perform hit-test.
    
    class EventHandler
    {
    public:
    virtual void performAction(EventData* ed) = 0;
    };
    
    // Second class constructor can register itself to your first object.
    
    class SecondClass : public EventHandler
    {
    public:
        SecondClass()
        { 
            ImageButton::registerForEventAction(*this);
        }
        void performAction(EventData* ed)
        {
           // this method gets called back when a hit test gets passed and we will get control
           // at the same time at second object to perform necessary operation.
        }
    };
    
    // ... extending your first class with below method, and another member variable.
    
    class ImageButton 
    {
    // extension to base definition of ImageButton .. assuming namespace kind of convention 
    // just for simplicity and completeness
    
    private:
    std::vector<EventHandler&> registeredHandlers;
    
    public:
    static void ImageButton::registerForEventAction(EventHandler& eh)
    {
      // For Simplicity I'm assuming your First class object is singleton, if not you need to
      // figure out how you can get access to first object in your second class.
    
     ImageButton::getInstance().registeredHandlers.push_back(eh);
    }
    
    bool hitTest(int, int)
    {
    bool success = true; 
    // ideally above variable should be set to false at the start setting it to true for 
    // readability
    
       if (success) {
            for (std::vector<EventHandler&>::iterator i = registeredHandlers.begin(); i !=       registeredHandlers.end(); ++i) {
            // pass on any event data if you need to.
               (*i).performAction(NULL);
            }
        } // End of if
    }// End of method
    }; // End of Class Definition
    

    【讨论】:

    • 为什么将registerForEventAction()设为静态? this-&gt;registeredHandlers.push_back(eh); 不是更容易处理吗?
    • 是的,我在评论中提到过,所以如果 ImageButton 不是单例的,那么您不需要使用静态方法,但这需要找出我们需要参考的特定 ImageObject .我试图激励他(Soner Gönül)查看一个 ImageObject 的结果,并假设他会重构它以供他使用。
    【解决方案3】:

    如果您想使用类似于代表的东西,这应该非常接近:

    #include <functional>
    //typedef void (*VoidCallback)(void); // only works with static member functions
    typedef std::tr1::function<void (void)> VoidCallback;
    
    class ImageButton{
    public:
    // ...
        VoidCallback onMousePress;
        VoidCallback onMousePressOutside;
    private:
        bool hitTest(int x, int y) { onMousePress(); return true; }
    };
    
    class ImageButtonWrapper {
    private:
        ImageButton m_btn;
        static void foo() { printf("foo happened\n"); }
        void bar() { printf("this bar happened\n"); }
    public:
        ImageButtonWrapper() : m_btn(0,0,100,100) {
            m_btn.onMousePress = &foo;
            m_btn.onMousePressOutside = std::bind(&ImageButtonWrapper::bar, this);
        }
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      相关资源
      最近更新 更多