0

In my C++ program here, I have created an image button control that has an image button and hit testing function to figure out if a mouse clicked inside the video.

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
};

Now, there's another where I have to utilitise this ImageButton control. Since, I come from C#, I remember using the controls very easily and subscribing to their events like

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

I have just started using the Poco library to get similar functionlaities of event subscribing here in C++ but wanted to ask how can I create such an event that can be subscribed in my second class and onMousePress of the ImageButton triggers the subscribed function in this second class?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
user1240679
  • 6,829
  • 17
  • 60
  • 89
  • This answer about C++ callbacks seems relevant: http://stackoverflow.com/a/2298865/645280 –  Jan 23 '13 at 14:11

3 Answers3

0

One way would be to apply the observer design pattern. For instance, ImageButton class receives events and interested client objects would register with ImageButton. Upon event occurrance, ImageButton notifies all registered clients, which in turn take responsibility for reacting to the event as they see fit.

Another yet similar approach would be to use signal/slot mechanism if your library provides it. From my own experience, I prefer explicit observer pattern application over signals and slots because the flow of execution in the program is explicitly visible. When using singal/slot mechanism extensivelly, at some point things start to happen magically and it is hart to tell what the program is doing.

We have been using Qt, which supports signals and slots, for GUI in our product for years. In the past, signals and slots were used everywhere. But have changed our policy to use it only in strictly GUI code and not let it propagate into the business code any more for reasons stated above.

Marko
  • 21
  • 5
0

for solving the above I would have done the following, check if it helps you out.

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
Vikas Putcha
  • 168
  • 1
  • 1
  • 9
  • Why make `registerForEventAction()` static? Wouldn't `this->registeredHandlers.push_back(eh);` be a lot easier to deal with? –  Jan 23 '13 at 14:39
  • Yeah, I mentioned that in my comment, so if the ImageButton is not singleton, then you need not use a static method, but that would demand to figure out the specific ImageObject to which we need to refer. I was trying to motivate him (Soner Gönül) to see the results for one ImageObject, and assumed he will refactor it for his usage. – Vikas Putcha Jan 24 '13 at 05:43
0

If you want to go with something similar to delegates, this should come pretty close:

#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);
    }
};