Sign in to follow this  

GUI events system redesign

This topic is 4394 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

CONTEXT: I'm in the final stages of development of my C++ and OpenGL GUI, and I've found that the current events system design need improvements regarding flexibility (the user hasn't much control over the entire thing). I plan to use the "listeners" approach (implemented in both Java AWT and Java Swing). PROBLEM: Besides everything is good on paper, a little detail still annoys me: WHAT will be responsible for handling the events triggered by the GUI. The "Java way" seems a little bloatead, as an entire class must be created (inherited from, for example, "ActionListener"), a pure virtual method must be implemented (for example, "actionPerformed( ActionEvent e )"), and then passed to the "addListener" method. Look at the example bellow:
// Java way (pseudo-code)
// User class created ONLY to handle "action events" (eg. mouse click) on button1
class User_ActionListenerButton1 : public ActionListener {
    void actionPerformed( ActionEvent e ) {
    // Do whathever the user wants, like close the application or change the background color
    }
};

// "Bind" the listener to a button, so the "actionPerformed" method will be invoked
// when an "action event" is triggered
JButton button1;
button1.addActionListener( User_ActionListenerButton1 );
QUESTION: Do you know any solution that will do the same as the "Java way", but without having to spreaded "event classes" all over the application? Or do you think this is the way to go? The solutions that came in mind that could help me out are to use function pointers (I really dislike them, but they could give me enough freedom) or to make a SINGLE class inherit from MANY listener classes, like this:
class User_ListenerButton1 : public ActionListener : FocusListener : KeyListener {
    void ActionPerformed( ActionEvent e ) { ... }
    void FocusPerformed( FocusEvent e ) { ... }
    void KeyPerformed( KeyEvent e ) { ... }
};

JButton button1;
button1.addActionListener( User_Button1Listener );
button1.addFocusListener( User_Button1Listener );
button1.addKeyListener( User_Button1Listener );
Thanks a lot, guys! Please, send me some suggestions!

Share this post


Link to post
Share on other sites
Quote:
Original post by MajinMusashi
do you think this is the way to go?


I don't, i recommend using a generic signals & slots library like Boost.Signals (it's not the only one available) that allows you to use free & member functions, and "functors".

Share this post


Link to post
Share on other sites
I'd definitely go the "C#" route on this one... build some type of delegate/functor object into your GUI and bind events to functions that way instead of binding to interfaces. In general, it shouldn't be necessary to create new *types* to respond to events, just *functions* to handle them.

Share this post


Link to post
Share on other sites
In C++, I like to use boost::functions for that.


class button{
protected:
boost::function<void()> onClick;
public:
void set_onClick(boost::function<void()> f){onClick=f;}
void click(){if(onClick){onClick();}
};

struct echo_functor{
string s;
void operator()(){
cout << s;
}
void echo_mem_function(){
cout << s;
}
echo(string ss):s(ss){}
};

void echo_function(){
cout << "moo.";
}


button b1,b2,b3;
echo_functor echoer("moo.");

b1.set_onClick(echo_function);
b2.set_onClick(echoer); // uses operator()
b3.set_onClick(boost::bind(&echo_functor::echo_mem_function, echoer, _1));
b1.click();
b2.click();
b3.click();

// same thing, 3 ways.


Share this post


Link to post
Share on other sites
For variety, here's another solution: The way I'm doing this (in java) is by moving all the event handling code to scripts. UI classes have script hooks, and they implement their Listener interfaces with a call to the scripting system to execute the respective script that was assigned for the event. The scripts to be used are specified during interface definition (ie: in the xml files). Seems elegant to me, although I'm sure someone will find a reason why this is bad or ugly. ^_^;

Share this post


Link to post
Share on other sites
Quote:
Original post by TrueTom
Use FastDelegates to bind your event to everything that has the right signature.


Another vote for FastDelegates... it's what I use. And even though it relies on specific implementation details of the compiler (usually a no-no in my book), the fact that it works on virtually all major compilers in use (including the big two, GCC and MSVC.NET), it's a safe bet in my mind.

Share this post


Link to post
Share on other sites
Quote:
Original post by Simagery
Quote:
Original post by TrueTom
Use FastDelegates to bind your event to everything that has the right signature.


Another vote for FastDelegates... it's what I use.


The only issue with that (feature-wise) as far as i'm aware it does not come with direct support for multicasting or/and asynchronous calls although they can be added it's not like .NET delegates in every-sense. A signals & slots framework almost always comes with support for multicasting out of the box.

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
Quote:
Original post by Simagery
Another vote for FastDelegates... it's what I use.


The only issue with that (feature-wise) as far as i'm aware it does not come with direct support for multicasting or/and asynchronous calls although they can be added it's not like .NET delegates in every-sense. A signals & slots framework almost always comes with support for multicasting out of the box.


I always forget about that. The first thing I did with the FastDelegate code was to add multi-cast support (very trivial, suprised the author didn't do it originally).

Also, what do you mean by "asynchronous" delegates? I always use them as a nicer, cleaner form of function pointer. I'm assuming you don't actually mean delegating on a separate thread but instead mean gathering dispatches then dispatching them all at once at a later point? An example, perhaps?

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
Quote:
Original post by Simagery
An example, perhaps?

clickly


Alright, I guess that's what I expected from the name. I could see where that would definitely be useful in a GUI scenario, but I personally don't use delegates to that end -- I use them as better callbacks. To be honest, considering the dramatic difference between an asychronous delegate and a synchronous delegate I'd probably call the asynchronous delegate something different, just to impart to the user (and future code reader) that it's not a synchronous call and thus non-equivalent to a function call.

So, have you added asynch support to the FastDelegate example, or does the boost libraries provide that? If so, how is the threading pool implemented (or does the C++ version just spawn a new thread pthreads style?)?

Share this post


Link to post
Share on other sites

This topic is 4394 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this