@section overview_events_eventhandling Event Handling
There are two principal ways to handle events in wxWidgets. One of them uses
-<em>event table</em> macros and allows you to define the connection between events
+<em>event table</em> macros and allows you to define the binding between events
and their handlers only statically, i.e., during program compilation. The other
-one uses wxEvtHandler::Connect() call and can be used to connect, and
-disconnect, the handlers dynamically, i.e., during run-time depending on some
-conditions. It also allows the direct connection of the events of one object to a
-handler method in another object. The static event tables can only handle
-events in the object where they are defined so using Connect() is more flexible
-than using the event tables. On the other hand, event tables are more succinct
-and centralize all event handlers connection in one place. You can either
-choose a single approach that you find preferable or freely combine both
-methods in your program in different classes or even in one and the same class,
-although this is probably sufficiently confusing to be a bad idea.
-
-But before you make this choice, let us discuss these two ways in more
-detail. In the next section we provide a short introduction to handling the
-events using the event tables. Please see @ref overview_events_connect
-for the discussion of Connect().
+one uses wxEvtHandler::Bind<>() call and can be used to bind and
+unbind, the handlers dynamically, i.e. during run-time depending on some
+conditions. It also allows the direct binding of events to:
+@li A handler method in another object.
+@li An ordinary function like a static method or a global function.
+@li An arbitrary functor like boost::function<>.
+
+The static event tables can only handle events in the object where they are
+defined so using Bind<>() is more flexible than using the event tables. On the
+other hand, event tables are more succinct and centralize all event handler
+bindings in one place. You can either choose a single approach that you find
+preferable or freely combine both methods in your program in different classes
+or even in one and the same class, although this is probably sufficiently
+confusing to be a bad idea.
+
+Also notice that most of the existing wxWidgets tutorials and discussions use
+the event tables because they historically preceded the apparition of dynamic
+event handling in wxWidgets. But this absolutely doesn't mean that using the
+event tables is the preferred way: handling events dynamically is better in
+several aspects and you should strongly consider doing it if you are just
+starting with wxWidgets. On the other hand, you still need to know about the
+event tables if only because you are going to see them in many samples and
+examples.
+
+So before you make the choice between static event tables and dynamically
+connecting the event handlers, let us discuss these two ways in more detail. In
+the next section we provide a short introduction to handling the events using
+the event tables. Please see @ref overview_events_bind for the discussion of
+Bind<>().
@subsection overview_events_eventtables Event Handling with Event Tables
MyFrame class deriving from wxFrame.
First define one or more <em>event handlers</em>. They
-are just simple (non-virtual) methods of the class that take as a parameter a
+are just simple methods of the class that take as a parameter a
reference to an object of a wxEvent-derived class and have no return value (any
return information is passed via the argument, which is why it is non-const).
You also need to insert a macro
Let us now look at the details of this definition: the first line means that we
are defining the event table for MyFrame class and that its base class is
wxFrame, so events not processed by MyFrame will, by default, be handled by
-wxFrame. The next four lines define connections of individual events to their
+wxFrame. The next four lines define bindings of individual events to their
handlers: the first two of them map menu commands from the items with the
identifiers specified as the first macro parameter to two different member
functions. In the next one, @c EVT_SIZE means that any changes in the size of
events.
-@subsection overview_events_connect Dynamic Event Handling
-
-As with the event tables, decide in which class you intend to
-handle the events first and, as before, this class must derive from
-wxEvtHandler (usually indirectly via wxWindow). See the declaration of MyFrame
-in the previous section. However the similarities end here and both the syntax
-and the possibilities of handling events in this way are rather different.
+@subsection overview_events_bind Dynamic Event Handling
+The possibilities of handling events in this way are rather different.
Let us start by looking at the syntax: the first obvious difference is that you
need not use DECLARE_EVENT_TABLE() nor BEGIN_EVENT_TABLE() and the
associated macros. Instead, in any place in your code, but usually in
the code of the class defining the handler itself (and definitely not in the
-global scope as with the event tables), call its Connect() method like this:
+global scope as with the event tables), call its Bind<>() method like this:
@code
MyFrame::MyFrame(...)
{
- Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
- wxCommandEventHandler(MyFrame::OnExit));
+ Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExit, this, wxID_EXIT);
}
@endcode
-This class should be self-explanatory except for wxCommandEventHandler part:
-this is a macro that ensures that the method is of the correct type by using
-static_cast in the same way as the event table macros.
+Note that @c this pointer must be specified here.
Now let us describe the semantic differences:
<ul>
<li>
- Event handlers can be connected at any moment. For example, it's possible
- to do some initialization first and only connect the handlers if and when
+ Event handlers can be bound at any moment. For example, it's possible
+ to do some initialization first and only bind the handlers if and when
it succeeds. This can avoid the need to test that the object was properly
- initialized in the event handlers themselves. With Connect() they
+ initialized in the event handlers themselves. With Bind<>() they
simply won't be called if it wasn't correctly initialized.
</li>
<li>
- As a slight extension of the above, the handlers can also be
- Disconnect()-ed at any time and maybe later reconnected. Of course,
+ As a slight extension of the above, the handlers can also be unbound at
+ any time with Unbind<>() (and maybe rebound later). Of course,
it's also possible to emulate this behaviour with the classic
- static (i.e., connected via event tables) handlers by using an internal
+ static (i.e., bound via event tables) handlers by using an internal
flag indicating whether the handler is currently enabled and returning
- from it if it isn't, but using dynamically connected handlers requires
+ from it if it isn't, but using dynamically bind handlers requires
less code and is also usually more clear.
</li>
<li>
- Also notice that you must derive a class inherited from, say,
- wxTextCtrl even if you don't want to modify the control behaviour at
- all but just want to handle some of its events. This is especially
- inconvenient when the control is loaded from the XRC. Connecting the
- event handler dynamically bypasses the need for this unwanted
- sub-classing.
- </li>
-
- <li>
- Last but very, very far from least is the possibility to connect an
- event of some object to a method of another object. This is impossible
- to do with event tables because it is not possible to specify the
- object to dispatch the event to so it necessarily needs to be sent to
- the same object which generated the event. Not so with Connect() which
- has an optional @c eventSink parameter that can be used to specify the
- object which will handle the event. Of course, in this case the method
- being connected must belong to the class that is the type of the
- @c eventSink object! To give a quick example, people often want to catch
- mouse movement events happening when the mouse is in one of the frame
- children in the frame itself. Doing it in a naive way doesn't work:
+ Almost last but very, very far from least is the increased flexibility
+ which allows to bind an event to:
+ @li A method in another object.
+ @li An ordinary function like a static method or a global function.
+ @li An arbitrary functor like boost::function<>.
+
+ This is impossible to do with the event tables because it is not
+ possible to specify these handlers to dispatch the event to, so it
+ necessarily needs to be sent to the same object which generated the
+ event. Not so with Bind<>() which can be used to specify these handlers
+ which will handle the event. To give a quick example, a common question
+ is how to receive the mouse movement events happening when the mouse is
+ in one of the frame children in the frame itself. Doing it in a naive
+ way doesn't work:
<ul>
<li>
A @c EVT_LEAVE_WINDOW(MyFrame::OnMouseLeave) line in the frame
@code
MyFrame::MyFrame(...)
{
- m_child->Connect(wxID_ANY, wxEVT_LEAVE_WINDOW,
- wxMouseEventHandler(MyFrame::OnMouseLeave),
- NULL, // unused extra data parameter
- this); // this indicates the object to connect to
+ m_child->Bind(wxEVT_LEAVE_WINDOW, &MyFrame::OnMouseLeave, this);
}
@endcode
will work exactly as expected. Note that you can get the object that
wxEvent::GetEventObject() method of @c event argument passed to the
event handler.
</li>
+
+ <li>
+ Really last point is the consequence of the previous one: because of
+ increased flexibility of Bind(), it is also safer as it is impossible
+ to accidentally use a method of another class. Instead of run-time
+ crashes you will get compilation errors in this case when using Bind().
+ </li>
</ul>
-To summarize, using Connect() requires slightly more typing but is much more
+Let us now look at more examples of how to use different event handlers using
+the two overloads of Bind() function: first one for the object methods and the
+other one for arbitrary functors (callable objects, including simple functions):
+
+In addition to using a method of the object generating the event itself, you
+can use a method from a completely different object as an event handler:
+
+@code
+void MyFrameHandler::OnFrameExit( wxCommandEvent & )
+{
+ // Do something useful.
+}
+
+MyFrameHandler myFrameHandler;
+
+MyFrame::MyFrame()
+{
+ Bind( wxEVT_COMMAND_MENU_SELECTED, &MyFrameHandler::OnFrameExit,
+ &myFrameHandler, wxID_EXIT );
+}
+@endcode
+
+Note that @c MyFrameHandler doesn't need to derive from wxEvtHandler. But
+keep in mind that then the lifetime of @c myFrameHandler must be greater than
+that of @c MyFrame object -- or at least it needs to be unbound before being
+destroyed.
+
+
+To use an ordinary function or a static method as an event handler you would
+write something like this:
+
+@code
+void HandleExit( wxCommandEvent & )
+{
+ // Do something useful
+}
+
+MyFrame::MyFrame()
+{
+ Bind( wxEVT_COMMAND_MENU_SELECTED, &HandleExit, wxID_EXIT );
+}
+@endcode
+
+And finally you can bind to an arbitrary functor and use it as an event
+handler:
+
+@code
+
+struct MyFunctor
+{
+ void operator()( wxCommandEvent & )
+ {
+ // Do something useful
+ }
+};
+
+MyFunctor myFunctor;
+
+MyFrame::MyFrame()
+{
+ Bind( wxEVT_COMMAND_MENU_SELECTED, &myFunctor, wxID_EXIT );
+}
+@endcode
+
+A common example of a functor is boost::function<>:
+
+@code
+using namespace boost;
+
+void MyHandler::OnExit( wxCommandEvent & )
+{
+ // Do something useful
+}
+
+MyHandler myHandler;
+
+MyFrame::MyFrame()
+{
+ function< void ( wxCommandEvent & ) > exitHandler( bind( &MyHandler::OnExit, &myHandler, _1 ));
+
+ Bind( wxEVT_COMMAND_MENU_SELECTED, exitHandler, wxID_EXIT );
+}
+@endcode
+
+
+With the aid of boost::bind<>() you can even use methods or functions which
+don't quite have the correct signature:
+
+@code
+void MyHandler::OnExit( int exitCode, wxCommandEvent &, wxString goodByeMessage )
+{
+ // Do something useful
+}
+
+MyHandler myHandler;
+
+MyFrame::MyFrame()
+{
+ function< void ( wxCommandEvent & ) > exitHandler(
+ bind( &MyHandler::OnExit, &myHandler, EXIT_FAILURE, _1, "Bye" ));
+
+ Bind( wxEVT_COMMAND_MENU_SELECTED, exitHandler, wxID_EXIT );
+}
+@endcode
+
+
+To summarize, using Bind<>() requires slightly more typing but is much more
flexible than using static event tables so don't hesitate to use it when you
need this extra power. On the other hand, event tables are still perfectly fine
in simple situations where this extra flexibility is not needed.
</li>
<li value="3">
- The list of dynamically connected event handlers, i.e., those for which
- Connect() was called, is consulted. Notice that this is done before
+ The list of dynamically bind event handlers, i.e., those for which
+ Bind<>() was called, is consulted. Notice that this is done before
checking the static event table entries, so if both a dynamic and a static
event handler match the same event, the static one is never going to be
used.
@image html overview_events_winstack.png
(referring to the image, if @c W->ProcessEvent is called, it immediately calls
@c A->ProcessEvent; if nor @c A nor @c B handle the event, then the wxWindow
- itself is used - i.e. the dynamically connected event handlers and static
+ itself is used - i.e. the dynamically bind event handlers and static
event table entries of wxWindow are looked as the last possibility, after
all pushed event handlers were tested).
Note however that usually there are no wxEvtHandler chains nor wxWindows stacks
wxString text = event.GetText();
}
-// example of code handling the event with Connect():
+// example of code handling the event with Bind<>():
MyFrame::MyFrame()
{
- Connect(ID_MY_WINDOW, MY_EVENT, &MyFrame::OnMyEvent);
+ Bind(MY_EVENT, &MyFrame::OnMyEvent, this, ID_MY_WINDOW);
}
// example of code generating the event
typedef void (wxEvtHandler::*MyPlotEventFunction)(MyPlotEvent&);
#define MyPlotEventHandler(func) wxEVENT_HANDLER_CAST(MyPlotEventFunction, func)
-// if your code is only built sing reasonably modern compilers, you could just
+// if your code is only built using reasonably modern compilers, you could just
// do this instead:
#define MyPlotEventHandler(func) (&func)
// finally define a macro for creating the event table entries for the new
// event type
//
-// remember that you don't need this at all if you only use Connect() and that
+// remember that you don't need this at all if you only use Bind<>() and that
// you can replace MyPlotEventHandler(func) with just &func unless you use a
// really old compiler
#define MY_EVT_PLOT_CLICK(id, func) \
MyFrame::MyFrame()
{
- Connect(ID_MY_WINDOW, MY_PLOT_CLICKED, &MyFrame::OnPlot);
+ Bind(MY_PLOT_CLICKED, &MyFrame::OnPlot, this, ID_MY_WINDOW);
}
void MyFrame::OnPlot(MyPlotEvent& event)
wxWidgets level, it should never be called directly as the event handlers are
not part of wxWidgets API and should never be called directly.
-Finally, please notice that the event handlers themselves shouldn't be virtual.
-They should always be non-virtual and usually private (as there is no need to
-make them public) methods of a wxEvtHandler-derived class.
@subsection overview_events_prog User Generated Events vs Programmatically Generated Events
@subsection overview_events_pluggable Pluggable Event Handlers
-<em>TODO: Probably deprecated, Connect() provides a better way to do this</em>
+<em>TODO: Probably deprecated, Bind() provides a better way to do this</em>
In fact, you don't have to derive a new class from a window class
if you don't want to. You can derive a new class from wxEvtHandler instead,
care about the exact identifier either because you're not going to process the
events from the control being created or because you process the events
from all controls in one place (in which case you should specify @c wxID_ANY
-in the event table or wxEvtHandler::Connect call
+in the event table or wxEvtHandler::Bind call
as well). The automatically generated identifiers are always negative and so
will never conflict with the user-specified identifiers which must be always
positive.