correct and expand (while omitting the irrelevant bits which only distract from the main topic) the explanation of how events are processed
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55785 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -16,6 +16,8 @@ Classes: wxEvtHandler, wxWindow, wxEvent
|
|||||||
@li @ref overview_eventhandling_eventtables
|
@li @ref overview_eventhandling_eventtables
|
||||||
@li @ref overview_eventhandling_connect
|
@li @ref overview_eventhandling_connect
|
||||||
@li @ref overview_eventhandling_processing
|
@li @ref overview_eventhandling_processing
|
||||||
|
@li @ref overview_eventhandling_propagation
|
||||||
|
@li @ref overview_eventhandling_virtual
|
||||||
@li @ref overview_eventhandling_prog
|
@li @ref overview_eventhandling_prog
|
||||||
@li @ref overview_eventhandling_pluggable
|
@li @ref overview_eventhandling_pluggable
|
||||||
@li @ref overview_eventhandling_winid
|
@li @ref overview_eventhandling_winid
|
||||||
@@ -270,11 +272,10 @@ Now let us describe the semantic differences:
|
|||||||
NULL, // unused extra data parameter
|
NULL, // unused extra data parameter
|
||||||
this); // this indicates the object to connect to
|
this); // this indicates the object to connect to
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode will work exactly as expected. Note that you can get the
|
||||||
will work exactly as expected. Note that you can get the object which
|
object which generated the event -- and which is not the same as the
|
||||||
generated the event -- and which is not the same as the frame -- via
|
frame -- via wxEvent::GetEventObject() method of @c event argument
|
||||||
wxEvent::GetEventObject() method of @c event argument passed to the
|
passed to the event handler.
|
||||||
event handler.
|
|
||||||
<li>
|
<li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -286,74 +287,98 @@ in simple situations where this extra flexibility is not needed.
|
|||||||
|
|
||||||
@section overview_eventhandling_processing How Events are Processed
|
@section overview_eventhandling_processing How Events are Processed
|
||||||
|
|
||||||
|
The previous sections explain how to define event handlers but don't address
|
||||||
|
the question of how exactly does wxWidgets find the handler to call for the
|
||||||
|
given event. This section describes the algorithm used to do it in details.
|
||||||
|
|
||||||
When an event is received from the windowing system, wxWidgets calls
|
When an event is received from the windowing system, wxWidgets calls
|
||||||
wxEvtHandler::ProcessEvent on the first
|
wxEvtHandler::ProcessEvent() on the first event handler object belonging to the
|
||||||
event handler object belonging to the window generating the event.
|
window generating the event. The normal order of event table searching by
|
||||||
|
ProcessEvent() is as follows, with the event processing stopping as soon as a
|
||||||
It may be noted that wxWidgets' event processing system implements something
|
handler is found (unless the handler calls wxEvent::Skip() in which case it
|
||||||
very close to virtual methods in normal C++, i.e. it is possible to alter
|
doesn't count as having handled the event):
|
||||||
the behaviour of a class by overriding its event handling functions. In
|
|
||||||
many cases this works even for changing the behaviour of native controls.
|
|
||||||
|
|
||||||
For example it is possible to filter out a number of key events sent by the
|
|
||||||
system to a native text control by overriding wxTextCtrl and defining a
|
|
||||||
handler for key events using EVT_KEY_DOWN. This would indeed prevent
|
|
||||||
any key events from being sent to the native control - which might not be
|
|
||||||
what is desired. In this case the event handler function has to call Skip()
|
|
||||||
so as to indicate that the search for the event handler should continue.
|
|
||||||
|
|
||||||
To summarize, instead of explicitly calling the base class version as you
|
|
||||||
would have done with C++ virtual functions (i.e. @e wxTextCtrl::OnChar()),
|
|
||||||
you should instead call wxEvent::Skip.
|
|
||||||
|
|
||||||
In practice, this would look like this if the derived text control only
|
|
||||||
accepts 'a' to 'z' and 'A' to 'Z':
|
|
||||||
|
|
||||||
@code
|
|
||||||
void MyTextCtrl::OnChar(wxKeyEvent& event)
|
|
||||||
{
|
|
||||||
if ( isalpha( event.KeyCode() ) )
|
|
||||||
{
|
|
||||||
// key code is within legal range. we call event.Skip() so the
|
|
||||||
// event can be processed either in the base wxWidgets class
|
|
||||||
// or the native control.
|
|
||||||
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// illegal key hit. we don't call event.Skip() so the
|
|
||||||
// event is not processed anywhere else.
|
|
||||||
|
|
||||||
wxBell();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
The normal order of event table searching by ProcessEvent is as follows:
|
|
||||||
<ol>
|
<ol>
|
||||||
<li> If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled)
|
<li value="0">
|
||||||
the function skips to step (6).
|
Before anything else happens, wxApp::FilterEvent() is called. If it returns
|
||||||
<li> If the object is a wxWindow, @b ProcessEvent is recursively called on the window's
|
anything but -1 (default), the event handling stops immediately.
|
||||||
wxValidator. If this returns @true, the function exits.
|
</li>
|
||||||
<li> @b SearchEventTable is called for this event handler. If this fails, the base
|
|
||||||
class table is tried, and so on until no more tables exist or an appropriate
|
<li value="1">
|
||||||
function was found, in which case the function exits.
|
If this event handler is disabled via a call to
|
||||||
<li> The search is applied down the entire chain of event handlers (usually the chain has
|
wxEvtHandler::SetEvtHandlerEnabled() the next three steps are skipped and
|
||||||
a length of one). If this succeeds, the function exits.
|
the event handler resumes at step (5).
|
||||||
<li> If the object is a wxWindow and the event is set to set to propagate (in the library only
|
</li?
|
||||||
wxCommandEvent based events are set to propagate), @b ProcessEvent is recursively applied
|
|
||||||
to the parent window's event handler. If this returns @true, the function exits.
|
<li value="2">
|
||||||
<li> Finally, @b ProcessEvent is called on the wxApp object.
|
If the object is a wxWindow and has an associated validator, wxValidator
|
||||||
|
gets a chance to process the event.
|
||||||
|
</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
|
||||||
|
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.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li value="4">
|
||||||
|
The event table containing all the handlers defined using the event table
|
||||||
|
macros in this class and its base classes is examined. Notice that this
|
||||||
|
means that any event handler defined in a base class will be executed at
|
||||||
|
this step.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li value="5">
|
||||||
|
The event is passed to the next event handler, if any, in the event handler
|
||||||
|
chain. This chain can be formed using wxEvtHandler::SetNextHandler() or
|
||||||
|
wxWindow::PushEventHandler() but usually there is no next event handler and
|
||||||
|
chaining event handlers using these functions is much less useful now that
|
||||||
|
Connect() exists so this step will almost never do anything.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li value="6">
|
||||||
|
If the object is a wxWindow and the event is set to set to propagate (by
|
||||||
|
default only wxCommandEvent-derived events are set to propagate), then the
|
||||||
|
processing restarts from the step (1) (and excluding the step (7)) for the
|
||||||
|
parent window.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li value="7">
|
||||||
|
Finally, i.e. if the event is still not processed, the wxApp object itself
|
||||||
|
gets a last chance to process it.
|
||||||
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<b>Pay close attention to Step 5</b>. People often overlook or get
|
|
||||||
confused by this powerful feature of the wxWidgets event processing
|
<em>Please pay close attention to step 6!</em>. People often overlook or get
|
||||||
system. To put it a different way, events set to propagate
|
confused by this powerful feature of the wxWidgets event processing system. The
|
||||||
(see wxEvent::ShouldPropagate)
|
details of event propagation upwards the window hierarchy are described in the
|
||||||
(most likely derived either directly or indirectly from wxCommandEvent)
|
next section.
|
||||||
will travel up the containment hierarchy from child to parent until the
|
|
||||||
maximal propagation level is reached or an event handler is found that
|
Also please notice that there are additional steps in the event handling for
|
||||||
doesn't call @c event.Skip().
|
the windows making part of wxWidgets document-view framework, i.e.
|
||||||
|
wxDocParentFrame, wxDocChildFrame and their MDI equivalents wxDocMDIParentFrame
|
||||||
|
and wxDocMDIChildFrame. The parent frame classes modify the step (2) above to
|
||||||
|
send the events received by them to wxDocManager object first. This object, in
|
||||||
|
turn, sends the event to the current view and the view itself lets its
|
||||||
|
associated document to process the event first. The child frame classes send
|
||||||
|
the event directly to the associated view which still forwards it to its
|
||||||
|
document object. Notice that to avoid remembering the exact order in which the
|
||||||
|
events are processed in the document-view frame, the simplest, and recommended,
|
||||||
|
solution is to only handle the events at the view classes level, but not in the
|
||||||
|
document or document manager classes
|
||||||
|
|
||||||
|
|
||||||
|
@section overview_eventhandling_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 for 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
|
Finally, there is another additional complication (which, in fact, simplifies
|
||||||
life of wxWidgets programmers significantly): when propagating the command
|
life of wxWidgets programmers significantly): when propagating the command
|
||||||
@@ -377,15 +402,10 @@ that have a higher level of meaning and/or are generated by the window
|
|||||||
itself, (button click, menu select, tree expand, etc.) are command
|
itself, (button click, menu select, tree expand, etc.) are command
|
||||||
events and are sent up to the parent to see if it is interested in the event.
|
events and are sent up to the parent to see if it is interested in the event.
|
||||||
|
|
||||||
Note that your application may wish to override ProcessEvent to redirect processing of
|
As mentioned above, only command events are recursively applied to the parents
|
||||||
events. This is done in the document/view framework, for example, to allow event handlers
|
event handler in the library itself. As this quite often causes confusion for
|
||||||
to be defined in the document or view. To test for command events (which will probably
|
users, here is a list of system events which will @em not get sent to the
|
||||||
be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for efficiency,
|
parent's event handler:
|
||||||
instead of using the slower run-time type system.
|
|
||||||
|
|
||||||
As mentioned above, only command events are recursively applied to the parents event
|
|
||||||
handler in the library itself. As this quite often causes confusion for users,
|
|
||||||
here is a list of system events which will NOT get sent to the parent's event handler:
|
|
||||||
|
|
||||||
@li wxEvent: The event base class
|
@li wxEvent: The event base class
|
||||||
@li wxActivateEvent: A window or application activation event
|
@li wxActivateEvent: A window or application activation event
|
||||||
@@ -413,6 +433,32 @@ will have to be written that will override ProcessEvent() in order to pass
|
|||||||
all events (or any selection of them) to the parent window.
|
all events (or any selection of them) to the parent window.
|
||||||
|
|
||||||
|
|
||||||
|
@section overview_eventhandling_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 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 to
|
||||||
|
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 handler 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
|
@section overview_eventhandling_prog User Generated Events vs Programmatically Generated Events
|
||||||
|
|
||||||
While generically wxEvents can be generated both by user
|
While generically wxEvents can be generated both by user
|
||||||
|
Reference in New Issue
Block a user