
John Torjo wrote:
I don't think you'd want any component to catch events generated by any other component. What I think you'd like is: handle on a dialog, any notification coming from its controls. If the dialog does not/cannot handle this notification, propagate it up the chain (dialog's parent, grand parent, etc.).
I heavily disagree with this model. That's MFC/OWL and I would guess plenty of other GUI environments, and it is old. There is no reason why any component shouldn't be able to hook events.
Please explain "hook events".
Be an event handler for a particular event. C++ Builder is single-cast so to be an event handler for an event was simply a matter of assigning one's object's member function to a __closure ( an extension which is dealt very neatly in standard C++ now using boost::bind ). Managed C++ .NET is multicast so one essentially "assigns" one's event handler to a delegate, which encapslates multicast events.
This is how win32gui handles events right now.
And I think this is how C++ Builder/.net handles events as well.
You are completely wrong on this last point. Any C++ Builder component can hook an event ( called a __closure ). Any .NET component can hook an event
Do you mean "respond to an event"?
Yes, if by that you mean have any type of function handle an event. In boost::signal<> this would be a slot, and boost::signal allows anything which can be a boost::function act as an event handler, which means an object's member function, a function object, or a global/static function.
( called a delegate ). I am not trying to put down what seems to be your excellent work in any way, but you are conceptually following a model for event generation/event handling which has been superceded IMHO. If you like that model, fine. But I want to point out to you that a much better model, and much more in the spirit of C++, is to allow any functor to handle an event. And of course boost::signal<> is built around this idea. If your events are multi-casting, which I am sure they must be, there is no reason putting limitations on who can handle them unless you are using a means of event generation which is in itself restrictive in what it can do. All you end up doing is making programmers who want to use your GUI angry that they must find workarounds for event handling for many cases for which you haven't yet conceived.
I could really use some examples here ;) Because I really can't think of any. Maybe we are mis-reading eachother ;)
Here is a general example of what I mean. I have a class which needs to respond to some event in your system. The event may be something which usually happens to a visual widget, but my class may neither be a widget as you define it, or it may be a widget but a non-visual one. In good old-fashioned Windows and MFC, only a visual widget ( read "window" or "control" ) can respond to the event. So you follow this paradigm and my poor class, or widget, if you will, despite the fact that it needs to respond to an event for whatever reason, can no longer do so without doing some exotic tricks. Why ? Because you have established some arbitrary barrier, something like "only a embedded widget, or another type of related widget window" can respond to the event. Of course there are no doubt tricks, such as have been used in Windows from time immemorial to get around such limitations, ie. creating a dummy window of the correct kind and doing god knows what other silly but necessary things. But why bother to create such a system with such limitations. When I say respond to some event I almost always mean that my event handler ( or slot if you like that term ) will invariably just be notified that a particular event has occurred, and will do something accordingly within itself. Yes, I understand that many events have responses which change the nature of the visual actions drastically, and that you may feel that you do not want to allow certain classes/widgets to do so, but there is still no reason for such a limitation even in this case. C++ was created to give the programmer maximum control and maximum responsibility. You should honor that design. If the user of your GUI library wants to shoot himself in the foot by having some weird class handle an event in a way that does something really idiotic, let him. Putting up barriers such as, "I think that only X,Y, and Z class member functions should be able to handle this event" is nonsensical. With boost::signal<> allow any class to handle an event. If you want to maintain control internally you can use boost::signal<> easily enough so that your handler is the first to handle an event and can short-circuit everyone else. But don't limit what can handle events or not to the outside user. Here is a real-world situation from my own programming, but because I am still working on the idea and it may be a product for which I charge someday, I will give the minimum information. I have a non-visual class ( or component if you will in certain RAD environments ) which needs to handle the possible OS change of locale by an end user. It turns out that for a particular OS for which I am programming, the message which denotes the change of locale is only sent to a top-level window of a process. So my non-visual component is forced to do some elaborate tricks to handle this message. In an OOP GUI system, built on events/handlers ( or signals/slots ), the system can catch the message and have an event for it which is signaled each time the message occurs with the appropriate parameters being passed. In such a system if it is decided that "only other windows and other specialized window-like widgets" can handle the event, I am back in square 1. But a truly great system says "anyone function, ie boost::function<>, can handle this event" and it is a breeze for my class/component to do so. Why not make that type of system for your end-user rather than the type which has already existed and caused endless programmers to waste their time figuring out how to work around its idiotic limitations. Edward Diener