update documentation for Bind() (closes #10594)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59911 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -61,23 +61,27 @@ To be more precise, each event is described by:
|
||||
@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
|
||||
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 handlers connection in one place. You can either
|
||||
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.
|
||||
|
||||
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().
|
||||
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
|
||||
|
||||
@@ -90,7 +94,7 @@ containing the menu, so let's suppose that you need to handle some events in @c
|
||||
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
|
||||
@@ -150,7 +154,7 @@ the event table definition; just defining it in MyFrame class is @e not enough.
|
||||
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
|
||||
@@ -205,73 +209,59 @@ wxEvent-derived classes in the discussion of each control generating these
|
||||
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>
|
||||
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<>.
|
||||
|
||||
<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:
|
||||
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
|
||||
@@ -295,10 +285,7 @@ Now let us describe the semantic differences:
|
||||
@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
|
||||
@@ -306,9 +293,118 @@ Now let us describe the semantic differences:
|
||||
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
|
||||
Here are some more examples of how to use different event handlers.
|
||||
|
||||
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.
|
||||
@@ -344,8 +440,8 @@ doesn't count as having handled the event and the search continues):
|
||||
</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.
|
||||
@@ -370,7 +466,7 @@ doesn't count as having handled the event and the search continues):
|
||||
@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
|
||||
@@ -499,10 +595,10 @@ void MyFrame::OnMyEvent(wxCommandEvent& event)
|
||||
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
|
||||
@@ -561,14 +657,14 @@ wxDEFINE_EVENT(MY_PLOT_CLICKED, MyPlotEvent);
|
||||
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) \
|
||||
@@ -583,7 +679,7 @@ END_EVENT_TABLE()
|
||||
|
||||
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)
|
||||
@@ -626,9 +722,6 @@ code by the underlying toolkit or OS itself. But even if it does exist at
|
||||
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
|
||||
@@ -656,7 +749,7 @@ equivalents.
|
||||
|
||||
@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,
|
||||
@@ -703,7 +796,7 @@ generated for you automatically by wxWidgets. This is useful when you don't
|
||||
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.
|
||||
|
Reference in New Issue
Block a user