update/reorganize events overview and changed links to it to reflect the fact that it speaks about events in general and not just about handling them

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58712 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-02-07 15:22:14 +00:00
parent 9a6fda2288
commit 3e083d652d
8 changed files with 237 additions and 206 deletions

View File

@@ -7,28 +7,57 @@
/////////////////////////////////////////////////////////////////////////////
/**
@page overview_events Events and Event Handling
@page overview_eventhandling Event Handling
Related classes: wxEvtHandler, wxWindow, wxEvent
Classes: wxEvtHandler, wxWindow, wxEvent
@li @ref overview_eventhandling_introduction
@li @ref overview_eventhandling_eventtables
@li @ref overview_eventhandling_connect
@li @ref overview_eventhandling_processing
@li @ref overview_eventhandling_propagation
@li @ref overview_eventhandling_virtual
@li @ref overview_eventhandling_prog
@li @ref overview_eventhandling_pluggable
@li @ref overview_eventhandling_winid
@li @ref overview_eventhandling_custom
@li @ref overview_eventhandling_macros
@li @ref overview_events_introduction
@li @ref overview_events_eventhandling
@li @ref overview_events_processing
@li @ref overview_events_custom
@li @ref overview_events_misc
<hr>
@section overview_eventhandling_introduction Introduction
@section overview_events_introduction Introduction to Events
Like with all the other GUI frameworks, the control of flow in wxWidgets
applications is event-based: the program normally performs most of its actions
in response to the events generated by the user. These events can be triggered
by using the input devices (such as keyboard, mouse, joystick) directly or,
more commonly, by a standard control which synthesizes such input events into
higher level events: for example, a wxButton can generate a click event when
the user presses the left mouse button on it and then releases it without
pressing @c Esc in the meanwhile. There are also events which don't directly
correspond to the user actions, such as wxTimerEvent or wxSocketEvent.
But in all cases wxWidgets represents these events in a uniform way and allows
you to handle them in the same way wherever they originate from. And while the
events are normally generated by wxWidgets itself, you can also do this, which
is especially useful when using custom events (see @ref overview_events_custom).
To be more precise, each event is described by:
- <em>Event type</em>: this is simply a value of type wxEventType which
uniquely identifies the type of the event. For example, clicking on a button,
selecting an item from a list box and pressing a key on the keyboard all
generate events with different event types.
- <em>Event class</em> carried by the event: each event has some information
associated with it and this data is represented by an object of a class
derived from wxEvent. Events of different types can use the same event class,
for example both button click and listbox selection events use wxCommandEvent
class (as do all the other simple control events), but the key press event
uses wxKeyEvent as the information associated with it is different.
- <em>Event source</em>: wxEvent stores the object which generated the event
and, for windows, its identifier (see @ref overview_events_winid). As it is
common to have more than one object generating events of the same type (e.g. a
typical window contains several buttons, all generating the same button click
event), checking the event source object or its id allows to distinguish
between them.
@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
@@ -46,10 +75,10 @@ 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_eventhandling_connect
events using the event tables. Please see @ref overview_events_connect
for the discussion of Connect().
@section overview_eventhandling_eventtables Event Handling with Event Tables
@subsection overview_events_eventtables Event Handling with Event Tables
To use an <em>event table</em> you must first decide in which class you wish to
handle the events. The only requirement imposed by wxWidgets is that this class
@@ -175,7 +204,7 @@ wxEvent-derived classes in the discussion of each control generating these
events.
@section overview_eventhandling_connect Dynamic Event Handling
@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
@@ -284,7 +313,7 @@ need this extra power. On the other hand, event tables are still perfectly fine
in simple situations where this extra flexibility is not needed.
@section overview_eventhandling_processing How Events are Processed
@section overview_events_processing How Events are Processed
The previous sections explain how to define event handlers but don't address
the question of how exactly wxWidgets finds the handler to call for the
@@ -332,12 +361,12 @@ doesn't count as having handled the event and the search continues):
The event is passed to the next event handler, if any, in the event handler
chain, i.e., the steps (1) to (4) are done for it. This chain can be formed
using wxEvtHandler::SetNextHandler():
@image html overview_eventhandling_chain.png
@image html overview_events_chain.png
(referring to the image, if @c A->ProcessEvent is called and it doesn't handle
the event, @c B->ProcessEvent will be called and so on...).
In the case of wxWindow you can build a stack (implemented using wxEvtHandler
double-linked list) using wxWindow::PushEventHandler():
@image html overview_eventhandling_winstack.png
@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
@@ -382,16 +411,15 @@ solution is to only handle the events at the view classes level, and not in the
document or document manager classes
@section overview_eventhandling_propagation How Events Propagate Upwards
@subsection overview_events_propagation How Events Propagate Upwards
As mentioned in the previous section, the events of the classes deriving from
wxCommandEvent are propagated by default to the parent window if they are not
processed in this window itself. But although by default only the command
events are propagated like this, other events can be propagated as well because
the event handling code uses wxEvent::ShouldPropagate() to check whether an
event should be propagated. It is also possible to propagate the event only a
limited number of times and not until it is processed (or a top level parent
window is reached).
As mentioned above, the events of the classes deriving from wxCommandEvent are
propagated by default to the parent window if they are not processed in this
window itself. But although by default only the command events are propagated
like this, other events can be propagated as well because the event handling
code uses wxEvent::ShouldPropagate() to check whether an event should be
propagated. It is also possible to propagate the event only a limited number of
times and not until it is processed (or a top level parent window is reached).
Finally, there is another additional complication (which, in fact, simplifies
life of wxWidgets programmers significantly): when propagating the command
@@ -446,118 +474,9 @@ will have to be written that will override ProcessEvent() in order to pass
all events (or any selection of them) to the parent window.
@section overview_eventhandling_virtual Event Handlers vs Virtual Methods
@section overview_events_custom Custom Event Summary
It may be noted that wxWidgets' event processing system implements something
close to virtual methods in normal C++ in spirit: both of these mechanisms
allow you to alter the behaviour of the base class by defining the event handling
functions in the derived classes.
There is however an important difference between the two mechanisms when you
want to invoke the default behaviour, as implemented by the base class, from a
derived class handler. With the virtual functions, you need to call the base
class function directly and you can do it either in the beginning of the
derived class handler function (to post-process the event) or at its end (to
pre-process the event). With the event handlers, you only have the option of
pre-processing the events and in order to still let the default behaviour
happen you must call wxEvent::Skip() and @em not call the base class event
handler directly. In fact, the event handler probably doesn't even exist in the
base class as the default behaviour is often implemented in platform-specific
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.
@section overview_eventhandling_prog User Generated Events vs Programmatically Generated Events
While generically wxEvents can be generated both by user
actions (e.g., resize of a wxWindow) and by calls to functions
(e.g., wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived
events only for the user-generated events. The only @b exceptions to this rule are:
@li wxNotebook::AddPage: No event-free alternatives
@li wxNotebook::AdvanceSelection: No event-free alternatives
@li wxNotebook::DeletePage: No event-free alternatives
@li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as
wxNotebook::SetSelection is deprecated
@li wxTreeCtrl::Delete: No event-free alternatives
@li wxTreeCtrl::DeleteAllItems: No event-free alternatives
@li wxTreeCtrl::EditLabel: No event-free alternatives
@li All wxTextCtrl methods
wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other
functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free
equivalents.
@section overview_eventhandling_pluggable Pluggable Event Handlers
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,
defining the appropriate event table, and then call wxWindow::SetEventHandler
(or, preferably, wxWindow::PushEventHandler) to make this
event handler the object that responds to events. This way, you can avoid
a lot of class derivation, and use instances of the same event handler class (but different
objects as the same event handler object shouldn't be used more than once) to
handle events from instances of different widget classes.
If you ever have to call a window's event handler
manually, use the GetEventHandler function to retrieve the window's event handler and use that
to call the member function. By default, GetEventHandler returns a pointer to the window itself
unless an application has redirected event handling using SetEventHandler or PushEventHandler.
One use of PushEventHandler is to temporarily or permanently change the
behaviour of the GUI. For example, you might want to invoke a dialog editor
in your application that changes aspects of dialog boxes. You can
grab all the input for an existing dialog box, and edit it 'in situ',
before restoring its behaviour to normal. So even if the application
has derived new classes to customize behaviour, your utility can indulge
in a spot of body-snatching. It could be a useful technique for on-line
tutorials, too, where you take a user through a serious of steps and
don't want them to diverge from the lesson. Here, you can examine the events
coming from buttons and windows, and if acceptable, pass them through to
the original event handler. Use PushEventHandler/PopEventHandler
to form a chain of event handlers, where each handler processes a different
range of events independently from the other handlers.
@section overview_eventhandling_winid Window Identifiers
Window identifiers are integers, and are used to
uniquely determine window identity in the event system (though you can use it
for other purposes). In fact, identifiers do not need to be unique
across your entire application as long they are unique within the
particular context you're interested in, such as a frame and its children. You
may use the @c wxID_OK identifier, for example, on any number of dialogs
as long as you don't have several within the same dialog.
If you pass @c wxID_ANY to a window constructor, an identifier will be
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
as well). The automatically generated identifiers are always negative and so
will never conflict with the user-specified identifiers which must be always
positive.
See @ref page_stdevtid for the list of standard identifiers available.
You can use wxID_HIGHEST to determine the number above which it is safe to
define your own identifiers. Or, you can use identifiers below wxID_LOWEST.
Finally, you can allocate identifiers dynamically using wxNewId() function too.
If you use wxNewId() consistently in your application, you can be sure that
your identifiers don't conflict accidentally.
@section overview_eventhandling_custom Custom Event Summary
@subsection overview_eventhandling_custom_general General approach
@subsection overview_events_custom_general General approach
Since version 2.2.x of wxWidgets, each event type is identified by an ID
given to the event type @e at runtime that makes it possible to add
@@ -585,7 +504,7 @@ See also the @ref page_samples_event for an example of code
defining and working with the custom event types.
@subsection overview_eventhandling_custom_existing Using Existing Event Classes
@subsection overview_events_custom_existing Using Existing Event Classes
If you just want to use a wxCommandEvent with a new event type, use
one of the generic event table macros listed below, without having to define a
@@ -629,7 +548,7 @@ void MyWindow::SendEvent()
@endcode
@subsection overview_eventhandling_custom_generic Generic Event Table Macros
@subsection overview_events_custom_generic Generic Event Table Macros
@beginTable
@row2col{EVT_CUSTOM(event\, id\, func),
@@ -653,7 +572,7 @@ void MyWindow::SendEvent()
@endTable
@subsection overview_eventhandling_custom_ownclass Defining Your Own Event Class
@subsection overview_events_custom_ownclass Defining Your Own Event Class
Under certain circumstances, you must define your own event
class e.g., for sending more complex data from one place to another. Apart
@@ -723,17 +642,124 @@ void MyWindow::SendEvent()
@endcode
@section overview_eventhandling_macros Event Handling Summary
@section overview_events_misc Miscellaneous Notes
@subsection overview_events_virtual Event Handlers vs Virtual Methods
It may be noted that wxWidgets' event processing system implements something
close to virtual methods in normal C++ in spirit: both of these mechanisms
allow you to alter the behaviour of the base class by defining the event handling
functions in the derived classes.
There is however an important difference between the two mechanisms when you
want to invoke the default behaviour, as implemented by the base class, from a
derived class handler. With the virtual functions, you need to call the base
class function directly and you can do it either in the beginning of the
derived class handler function (to post-process the event) or at its end (to
pre-process the event). With the event handlers, you only have the option of
pre-processing the events and in order to still let the default behaviour
happen you must call wxEvent::Skip() and @em not call the base class event
handler directly. In fact, the event handler probably doesn't even exist in the
base class as the default behaviour is often implemented in platform-specific
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
While generically wxEvents can be generated both by user
actions (e.g., resize of a wxWindow) and by calls to functions
(e.g., wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived
events only for the user-generated events. The only @b exceptions to this rule are:
@li wxNotebook::AddPage: No event-free alternatives
@li wxNotebook::AdvanceSelection: No event-free alternatives
@li wxNotebook::DeletePage: No event-free alternatives
@li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as
wxNotebook::SetSelection is deprecated
@li wxTreeCtrl::Delete: No event-free alternatives
@li wxTreeCtrl::DeleteAllItems: No event-free alternatives
@li wxTreeCtrl::EditLabel: No event-free alternatives
@li All wxTextCtrl methods
wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other
functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free
equivalents.
@subsection overview_events_pluggable Pluggable Event Handlers
<em>TODO: Probably deprecated, Connect() 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,
defining the appropriate event table, and then call wxWindow::SetEventHandler
(or, preferably, wxWindow::PushEventHandler) to make this
event handler the object that responds to events. This way, you can avoid
a lot of class derivation, and use instances of the same event handler class (but different
objects as the same event handler object shouldn't be used more than once) to
handle events from instances of different widget classes.
If you ever have to call a window's event handler
manually, use the GetEventHandler function to retrieve the window's event handler and use that
to call the member function. By default, GetEventHandler returns a pointer to the window itself
unless an application has redirected event handling using SetEventHandler or PushEventHandler.
One use of PushEventHandler is to temporarily or permanently change the
behaviour of the GUI. For example, you might want to invoke a dialog editor
in your application that changes aspects of dialog boxes. You can
grab all the input for an existing dialog box, and edit it 'in situ',
before restoring its behaviour to normal. So even if the application
has derived new classes to customize behaviour, your utility can indulge
in a spot of body-snatching. It could be a useful technique for on-line
tutorials, too, where you take a user through a serious of steps and
don't want them to diverge from the lesson. Here, you can examine the events
coming from buttons and windows, and if acceptable, pass them through to
the original event handler. Use PushEventHandler/PopEventHandler
to form a chain of event handlers, where each handler processes a different
range of events independently from the other handlers.
@subsection overview_events_winid Window Identifiers
Window identifiers are integers, and are used to
uniquely determine window identity in the event system (though you can use it
for other purposes). In fact, identifiers do not need to be unique
across your entire application as long they are unique within the
particular context you're interested in, such as a frame and its children. You
may use the @c wxID_OK identifier, for example, on any number of dialogs
as long as you don't have several within the same dialog.
If you pass @c wxID_ANY to a window constructor, an identifier will be
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
as well). The automatically generated identifiers are always negative and so
will never conflict with the user-specified identifiers which must be always
positive.
See @ref page_stdevtid for the list of standard identifiers available.
You can use wxID_HIGHEST to determine the number above which it is safe to
define your own identifiers. Or, you can use identifiers below wxID_LOWEST.
Finally, you can allocate identifiers dynamically using wxNewId() function too.
If you use wxNewId() consistently in your application, you can be sure that
your identifiers don't conflict accidentally.
@subsection overview_events_macros Event Handling Summary
For the full list of event classes, please see the
@ref group_class_events "event classes group page".
@todo For all controls, state clearly when calling a member function results in
an event being generated and when it doesn't (possibly updating also the
'Events generated by the user versus programmatically-generated events'
paragraph of the 'Event Handling Overview' with the list of the functions
that break the rule).
*/