RE: [boost] Re: Java style GUI in C++

Edward Diener wrote:
Why not use boost::signals for your event interface. It is much better than hand-coded actions and listeners, since any type of function can handle an event. The technology is already in Boost so why re-invent the wheel.
The signals library looks very good, but it solves half the problem. You need to work out what types of signals are raised: MouseUp MouseDown MouseDoubleClick MouseMove and have a signal for each. This would mean that you could have hundreds of signals! It might be easier to group events by type, use signals to dispatch them and an event handler like I suggested to deal with them, e.g. MouseEvent( unsigned int event, const MouseEvent & info ); KeyEvent( unsigned int event, const KeyEvent & info ); This might be useful for command/reflection type events, having a std::list< boost::signal< bool ( const Event & ) > > or even std::map< std::string, boost::signal< ... > > Regards, Reece _________________________________________________________________ Express yourself with cool new emoticons http://www.msn.co.uk/specials/myemo

Why not use boost::signals for your event interface. It is much better than hand-coded actions and listeners, since any type of function can handle an event. The technology is already in Boost so why re-invent the wheel.
The signals library looks very good, but it solves half the problem. You need to work out what types of signals are raised: MouseUp MouseDown MouseDoubleClick MouseMove and have a signal for each. This would mean that you could have hundreds of signals!
What makes this worse is that you often want to synthesise other events eg: - MouseClick+LeftAlt - MouseMove-Left-Down (think 'mouse gestures') - etc I mentioned previously the problem that most toolkits have -> they require N x M code paths to be implemented, when N is the number of events/signals/whatever-the-metaphore, and M is the number of widgets. Ideally you want to make the problem domain become an N + M problem... there are toolkits that already do this -> most of them implement message maps.
It might be easier to group events by type, use signals to dispatch them and an event handler like I suggested to deal with them, e.g. MouseEvent( unsigned int event, const MouseEvent & info ); KeyEvent( unsigned int event, const KeyEvent & info );
this suffers the same problem as I am describing above, eg: a button widget that needs to handle a button press event, will need two seperate code paths, just to execute the same functionaly (ie the button press). Mathew Robertson

Ideally you want to make the problem domain become an N + M problem... there are toolkits that already do this -> most of them implement message maps.
no message maps in win32gui. (that is, you don't have to manually create it - it's created behind the scenes ;)) Best, John -- John Torjo Freelancer -- john@torjo.com Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.3beta released - check out splitter/simple_viewer, a File Explorer/Viewer all in about 200 lines of code! Professional Logging Solution for FREE -- http://www.torjo.com/code/logging.zip (logging - C++) -- http://www.torjo.com/logview/ (viewing/filtering - Win32) -- http://www.torjo.com/logbreak/ (debugging - Win32)

Mathew Robertson wrote:
Why not use boost::signals for your event interface. It is much better than hand-coded actions and listeners, since any type of function can handle an event. The technology is already in Boost so why re-invent the wheel.
The signals library looks very good, but it solves half the problem. You need to work out what types of signals are raised: MouseUp MouseDown MouseDoubleClick MouseMove and have a signal for each. This would mean that you could have hundreds of signals!
What makes this worse is that you often want to synthesise other events eg:
- MouseClick+LeftAlt - MouseMove-Left-Down (think 'mouse gestures') - etc
Just create a boost::signal<> for the mouse click and pass along all the information about the keyboard with it to the handler. Let the handler decide what should then be done with it. The handler could also be you, internally, ready to trigger a new event for some special situation. The point being that if you decide to have X number of events for a particular class, and you decide that some subset of X can be handled by the user, you are going to have to trigger those events anyway, so having subset-X boost::signals to do it by is no less of a cost than any other way. Remember also that boost::signal<> are just variabales like anything else and can be inherited like anything else by a specific derived class over a broader base class. There is no reason, if you have a particular mouse event as a boost::signal<> for a base class type of "window" to have to create another mouse event of the exact same type, as a boost::signal<>, for the derived class.

Why not use boost::signals for your event interface. It is much better than hand-coded actions and listeners, since any type of function can handle an event. The technology is already in Boost so why re-invent the wheel.
The signals library looks very good, but it solves half the problem. You need to work out what types of signals are raised: MouseUp MouseDown MouseDoubleClick MouseMove and have a signal for each. This would mean that you could have hundreds of signals!
What makes this worse is that you often want to synthesise other events eg:
- MouseClick+LeftAlt - MouseMove-Left-Down (think 'mouse gestures') - etc
Just create a boost::signal<> for the mouse click and pass along all the information about the keyboard with it to the handler.
Possibly - except that the keyboard event will have generated its own event, which would have been passed to the widget in a previous signal. You could pass the key event in the same wrapper as the mouse event (or vice-versa), but then you are saying something about how the dispatcher handles events, which would limit you ability to do some things (eg for drag'n'drop situations, keyboard/mouse handling gets 'interesting' as you need to forward the events to the correct target window). In this case, you would want your 'gesture capable widget sub-class' (or something similar), to synthesise a MouseGesture event (or LeftAltClick event), so that your child widget implementations need only handle the single MouseGesture event, rather than, MouseMove, MouseMoveLeft, MouseMoveDown, etc.
Let the handler decide what should then be done with it. The handler could also be you, internally, ready to trigger a new event for some special situation. The point being that if you decide to have X number of events for a particular class, and you decide that some subset of X can be handled by the user, you are going to have to trigger those events anyway, so having subset-X boost::signals to do it by is no less of a cost than any other way. Remember also that boost::signal<> are just variabales like anything else and can be inherited like anything else by a specific derived class over a broader base class. There is no reason, if you have a particular mouse event as a boost::signal<> for a base class type of "window" to have to create another mouse event of the exact same type, as a boost::signal<>, for the derived class.
Certainly... I dont have a specific aversion to using boost::signal<>... just that most of the examples / suggestions that have been preented so far, have some specific limitations. All I am trying to do is to highlight those limitations, specifically a) N+M event-to-action handling, b) bi-directional event information, c) run-time unknown-event dispatch capability regards, Mathew

Mathew Robertson wrote:
Why not use boost::signals for your event interface. It is much better than hand-coded actions and listeners, since any type of function can handle an event. The technology is already in Boost so why re-invent the wheel.
The signals library looks very good, but it solves half the problem. You need to work out what types of signals are raised: MouseUp MouseDown MouseDoubleClick MouseMove and have a signal for each. This would mean that you could have hundreds of signals!
What makes this worse is that you often want to synthesise other events eg:
- MouseClick+LeftAlt - MouseMove-Left-Down (think 'mouse gestures') - etc
Just create a boost::signal<> for the mouse click and pass along all the information about the keyboard with it to the handler.
Possibly - except that the keyboard event will have generated its own event, which would have been passed to the widget in a previous signal. You could pass the key event in the same wrapper as the mouse event (or vice-versa), but then you are saying something about how the dispatcher handles events, which would limit you ability to do some things (eg for drag'n'drop situations, keyboard/mouse handling gets 'interesting' as you need to forward the events to the correct target window).
I do not see how any of this is impacted by boost::signal<>. If you are saying that events must be created on-the-fly at run-time, with the parameters unknown until run-time, rather than at compile time, I agree with you that boost::signal<> is a compile time mechanism since every signal has its parameters and return value. Still creating events at run-time implies that some handler knows what the parameters of those events must be, so there is no problem creating a signal for them at compile time to which a handler can attach itself.
In this case, you would want your 'gesture capable widget sub-class' (or something similar), to synthesise a MouseGesture event (or LeftAltClick event), so that your child widget implementations need only handle the single MouseGesture event, rather than, MouseMove, MouseMoveLeft, MouseMoveDown, etc.
Whatever you synthesize as an event can be represented as a boost::signal<>. In your subclass just add your MouseGesture, and document it as an event which combines some of the functionality of the other mouse events. It is then up to the programmer whether they want to handle the MouseGesture or the individual mouse events.
Let the handler decide what should then be done with it. The handler could also be you, internally, ready to trigger a new event for some special situation. The point being that if you decide to have X number of events for a particular class, and you decide that some subset of X can be handled by the user, you are going to have to trigger those events anyway, so having subset-X boost::signals to do it by is no less of a cost than any other way. Remember also that boost::signal<> are just variabales like anything else and can be inherited like anything else by a specific derived class over a broader base class. There is no reason, if you have a particular mouse event as a boost::signal<> for a base class type of "window" to have to create another mouse event of the exact same type, as a boost::signal<>, for the derived class.
Certainly... I dont have a specific aversion to using boost::signal<>... just that most of the examples / suggestions that have been preented so far, have some specific limitations. All I am trying to do is to highlight those limitations, specifically a) N+M event-to-action handling, b) bi-directional event information, c) run-time unknown-event dispatch capability
a) I do not undersatand what the problem with boost::signal<> is in this case. A signal can have any number of slots to handle an event, and can produce any number of signals itself in response to an event. b) I have answered this above. c) I agree if the event is completely unknown then boost::signal<> can not be used. But in that case I don't see how any handler can handle it. If the event is vague enough to require void * types of parameters ( or boost::any or boost::variant as alternatives ) the handler still must have some way to know, through other means which usually means other parameters, what the events is generating. In that case a broader boost::signal<> can be specified at compile time, such as boost::signal<void (void * /* or boost::any, boost::variant */,int whattype info)> etc. I do not doubt that there may be an event mechanism which specifies that events must be created at run-time on the fly, as it were, but I still do not see how handlers can handle them without parameters being passed to the handler which tells what the event is about. I do understand that there is a run-time memory cost with specify boost::signal<> within a class at compile time as an object. If you are creating a huge number of signals at run-time then you may not want to pay the cost. But I personally have never worked with an event mechanism which didn't make it reasonable to specify the signals one wants for a class at compile-time, and still easily work within the memory constraints of the system. Remember also that it is possible to create boost::signal<> at run-time in just the same way one creates any C++ variable at run-time, through dynamic memory and 'new', or better by using boost::shared_ptr<> ( or std::auto_ptr<> ).

Reece Dunn wrote:
Edward Diener wrote:
Why not use boost::signals for your event interface. It is much better than hand-coded actions and listeners, since any type of function can handle an event. The technology is already in Boost so why re-invent the wheel.
The signals library looks very good, but it solves half the problem. You need to work out what types of signals are raised: MouseUp MouseDown MouseDoubleClick MouseMove and have a signal for each. This would mean that you could have hundreds of signals!
You need to have a signal for each event which could occur anyway, so that others can handle them. But you shouldn't need to create a new signal in a derived class for an event which occurs in a base class.
It might be easier to group events by type, use signals to dispatch them and an event handler like I suggested to deal with them, e.g. MouseEvent( unsigned int event, const MouseEvent & info ); KeyEvent( unsigned int event, const KeyEvent & info );
Why do you have to create event handlers for people to use. Just create boost::signal<> which encapsulates the parameters you want to pass when the event occurs. Give it a name which relates to the event that is happening, and let anyone simply add their slot to the signal. When your code determines that the event has occurred, just trigger the signal and allow anyone, including your own internal code if necessary, to handle the event. Why do I like this ? Because systems that determine that one must be this-or-that to handle an event are always unnecessarily limiting in one way or another.

It might be easier to group events by type, use signals to dispatch them and an event handler like I suggested to deal with them, e.g. MouseEvent( unsigned int event, const MouseEvent & info ); KeyEvent( unsigned int event, const KeyEvent & info );
Why do you have to create event handlers for people to use. Just create boost::signal<> which encapsulates the parameters you want to pass when the event occurs. Give it a name which relates to the event that is happening, and let anyone simply add their slot to the signal. When your code determines that the event has occurred, just trigger the signal and allow anyone, including your own internal code if necessary, to handle the event. Why do I like this ? Because systems that determine that one must be this-or-that to handle an event are always unnecessarily limiting in one way or another.
The problem with the "registering your self in a slot" approach, is that most events generate actions -> ie they application flow is bi-directional. The signal/slot approach (usually) suffers from not being able to send a response back to the event sender. Mathew

Mathew Robertson wrote:
It might be easier to group events by type, use signals to dispatch them and an event handler like I suggested to deal with them, e.g. MouseEvent( unsigned int event, const MouseEvent & info ); KeyEvent( unsigned int event, const KeyEvent & info );
Why do you have to create event handlers for people to use. Just create boost::signal<> which encapsulates the parameters you want to pass when the event occurs. Give it a name which relates to the event that is happening, and let anyone simply add their slot to the signal. When your code determines that the event has occurred, just trigger the signal and allow anyone, including your own internal code if necessary, to handle the event. Why do I like this ? Because systems that determine that one must be this-or-that to handle an event are always unnecessarily limiting in one way or another.
The problem with the "registering your self in a slot" approach, is that most events generate actions -> ie they application flow is bi-directional. The signal/slot approach (usually) suffers from not being able to send a response back to the event sender.
The boost::signal<> is fully capable of returning a response. Take a look at it. Furthermore even if it weren't, it is child's play to pass a reference or pointer to something in which a response is put. Finally any handler of a boost::signal<> can generate their own event in response themselves.

It might be easier to group events by type, use signals to dispatch them and an event handler like I suggested to deal with them, e.g. MouseEvent( unsigned int event, const MouseEvent & info ); KeyEvent( unsigned int event, const KeyEvent & info );
Why do you have to create event handlers for people to use. Just create boost::signal<> which encapsulates the parameters you want to pass when the event occurs. Give it a name which relates to the event that is happening, and let anyone simply add their slot to the signal. When your code determines that the event has occurred, just trigger the signal and allow anyone, including your own internal code if necessary, to handle the event. Why do I like this ? Because systems that determine that one must be this-or-that to handle an event are always unnecessarily limiting in one way or another.
The problem with the "registering your self in a slot" approach, is that most events generate actions -> ie they application flow is bi-directional. The signal/slot approach (usually) suffers from not being able to send a response back to the event sender.
The boost::signal<> is fully capable of returning a response. Take a look at it. Furthermore even if it weren't, it is child's play to pass a reference or pointer to something in which a response is put. Finally any handler of a boost::signal<> can generate their own event in response themselves.
Exactly - but how many GUI toolkits actually make the API for the sender of the event, pass a reference to itself? Having myself had a look a little while ago, there arn't many. ... which was the point I was trying to highlight -> I must articulated myself correctly. Mathew

The problem with the "registering your self in a slot" approach, is that most events generate actions -> ie they application flow is bi-directional. The signal/slot approach (usually) suffers from not being able to send a response back to the event sender.
I think there's a bigger problem here - with boost::signal. When handling some events, in a certain handler - you might find yourself wanting to turn off further processing of events. Imagine this case: You might want to turn off commands (like, "File Save", "Undo", "Redo", etc.) which come from accelerators (key-stokes). In such a case, you'd like to register your event handler to handle commands first. Then, see if a command is enabled. If so, allow other handlers to handle it. If it's disabled, turn off further handling. Correct me if I'm wrong, but I don't think that's possible with boost::signal. Best, John -- John Torjo Freelancer -- john@torjo.com Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.3beta released - check out splitter/simple_viewer, a File Explorer/Viewer all in about 200 lines of code! Professional Logging Solution for FREE -- http://www.torjo.com/code/logging.zip (logging - C++) -- http://www.torjo.com/logview/ (viewing/filtering - Win32) -- http://www.torjo.com/logbreak/ (debugging - Win32)

From: John Torjo <john.lists@torjo.com>
The problem with the "registering your self in a slot" approach, is that most events generate actions -> ie they application flow is bi-directional. The signal/slot approach (usually) suffers from not being able to send a response back to the event sender.
I think there's a bigger problem here - with boost::signal. When handling some events, in a certain handler - you might find yourself wanting to turn off further processing of events.
Imagine this case: You might want to turn off commands (like, "File Save", "Undo", "Redo", etc.) which come from accelerators (key-stokes). In such a case, you'd like to register your event handler to handle commands first. Then, see if a command is enabled. If so, allow other handlers to handle it. If it's disabled, turn off further handling.
Correct me if I'm wrong, but I don't think that's possible with boost::signal.
I'm not Boost.Signal expert, but I think that is possible. You need to group your slots so that you can impose an order. Thus, the enabler would be in the group that sorts first. Then, your signal should be defined with a Combiner that won't call further signals if any returns false. That means that your enabler will always be called first and, if it returns true, the rest of the slots will be invoked. HTH -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Aug 23, 2004, at 4:27 PM, Rob Stewart wrote:
I'm not Boost.Signal expert, but I think that is possible. You need to group your slots so that you can impose an order. Thus, the enabler would be in the group that sorts first. Then, your signal should be defined with a Combiner that won't call further signals if any returns false. That means that your enabler will always be called first and, if it returns true, the rest of the slots will be invoked.
Yes, that'll work. Doug

I'm not Boost.Signal expert, but I think that is possible. You need to group your slots so that you can impose an order. Thus, the enabler would be in the group that sorts first. Then, your signal should be defined with a Combiner that won't call further signals if any returns false. That means that your enabler will always be called first and, if it returns true, the rest of the slots will be invoked.
Fine with me. However, what I want is to halt processing from any event handler. So, if I have 10 event handlers for an event, and handler 5 says stop, I won't call the rest. While that may or may not be possible with a boost::signal, I would prefer a simple (ordered) array of functions to call. Best, John -- John Torjo Freelancer -- john@torjo.com Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.3beta released - check out splitter/simple_viewer, a File Explorer/Viewer all in about 200 lines of code! Professional Logging Solution for FREE -- http://www.torjo.com/code/logging.zip (logging - C++) -- http://www.torjo.com/logview/ (viewing/filtering - Win32) -- http://www.torjo.com/logbreak/ (debugging - Win32)

From: John Torjo <john.lists@torjo.com>
I'm not Boost.Signal expert, but I think that is possible. You need to group your slots so that you can impose an order. Thus, the enabler would be in the group that sorts first. Then, your signal should be defined with a Combiner that won't call further signals if any returns false. That means that your enabler will always be called first and, if it returns true, the rest of the slots will be invoked.
Fine with me. However, what I want is to halt processing from any event handler. So, if I have 10 event handlers for an event, and handler 5 says stop, I won't call the rest.
The same solution applies.
While that may or may not be possible with a boost::signal, I would prefer a simple (ordered) array of functions to call.
Suit yourself. I was just pointing out that what you wanted was, indeed, possible with Boost.Signals and that you didn't need to reinvent it. Perhaps what you want could be implemented as an adjunct to Boost.Signals? That is, it could be another way to manage signals and slots that joins, rather than replaces, what exists. (It may also be possible to use a policy to control how the dispatching occurs such that the ordering you want is imposed and exposed.) -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (6)
-
Doug Gregor
-
Edward Diener
-
John Torjo
-
Mathew Robertson
-
Reece Dunn
-
Rob Stewart