]> git.saurik.com Git - wxWidgets.git/blame - docs/doxygen/overviews/eventhandling.h
substitute '@b NB:' with '@note'; first partial revision of e*h headers; replace...
[wxWidgets.git] / docs / doxygen / overviews / eventhandling.h
CommitLineData
15b6757b 1/////////////////////////////////////////////////////////////////////////////
3b88355f 2// Name: eventhandling.h
15b6757b
FM
3// Purpose: topic overview
4// Author: wxWidgets team
5// RCS-ID: $Id$
6// Licence: wxWindows license
7/////////////////////////////////////////////////////////////////////////////
8
880efa2a 9/**
36c9828f 10
dc28cdf8
FM
11@page overview_eventhandling Event Handling
12
13Classes: wxEvtHandler, wxWindow, wxEvent
14
15@li @ref overview_eventhandling_introduction
16@li @ref overview_eventhandling_processing
17@li @ref overview_eventhandling_prog
18@li @ref overview_eventhandling_pluggable
19@li @ref overview_eventhandling_winid
20@li @ref overview_eventhandling_custom
21@li @ref overview_eventhandling_macros
22
23
24<hr>
25
26
27@section overview_eventhandling_introduction Introduction
28
29Before version 2.0 of wxWidgets, events were handled by the application
30either by supplying callback functions, or by overriding virtual member
31functions such as @b OnSize.
32
33From wxWidgets 2.0, @e event tables are used instead, with a few exceptions.
34An event table is placed in an implementation file to tell wxWidgets how to map
35events to member functions. These member functions are not virtual functions, but
36they are all similar in form: they take a single wxEvent-derived argument,
37and have a void return type.
38Here's an example of an event table.
39
40@code
41BEGIN_EVENT_TABLE(MyFrame, wxFrame)
42EVT_MENU(wxID_EXIT, MyFrame::OnExit)
43EVT_MENU(DO_TEST, MyFrame::DoTest)
44EVT_SIZE(MyFrame::OnSize)
45EVT_BUTTON(BUTTON1, MyFrame::OnButton1)
46END_EVENT_TABLE()
47@endcode
48
49The first two entries map menu commands to two different member functions. The
50EVT_SIZE macro doesn't need a window identifier, since normally you are only
51interested in the current window's size events.
52
53The EVT_BUTTON macro demonstrates that the originating event does not have to
54come from the window class implementing the event table -- if the event source
55is a button within a panel within a frame, this will still work, because event
56tables are searched up through the hierarchy of windows for the command events.
57In this case, the button's event table will be searched, then the parent
58panel's, then the frame's.
59
60As mentioned before, the member functions that handle events do not have to be
61virtual. Indeed, the member functions should not be virtual as the event
62handler ignores that the functions are virtual, i.e. overriding a virtual
63member function in a derived class will not have any effect. These member
64functions take an event argument, and the class of event differs according to
65the type of event and the class of the originating window. For size events,
66wxSizeEvent is used. For menu commands and most control commands
67(such as button presses), wxCommandEvent is used. When controls get more
68complicated, then specific event classes are used, such as wxTreeEvent for
69events from wxTreeCtrl windows.
70
71As well as the event table in the implementation file, there must also be a
72DECLARE_EVENT_TABLE macro somewhere in the class declaration. For example:
73
74@code
75class MyFrame : public wxFrame
76{
77public:
78...
79void OnExit(wxCommandEvent& event);
80void OnSize(wxSizeEvent& event);
81
82protected:
83int m_count;
84...
85
86DECLARE_EVENT_TABLE()
87};
88@endcode
89
90Note that this macro may occur in any section of the class (public, protected
91or private) but that it is probably better to insert it at the end, as shown,
92because this macro implicitly changes the access to protected which may be
93quite unexpected if there is anything following it.
94
95Finally, if you don't like using macros for static initialization of the event
96tables you may also use wxEvtHandler::Connect to
97connect the events to the handlers dynamically, during run-time. See the
98@ref page_samples_event for an example of doing it.
99
100
101
409e6ce4 102@section overview_eventhandling_processing How Events are Processed
dc28cdf8
FM
103
104When an event is received from the windowing system, wxWidgets calls
105wxEvtHandler::ProcessEvent on the first
106event handler object belonging to the window generating the event.
107
108It may be noted that wxWidgets' event processing system implements something
109very close to virtual methods in normal C++, i.e. it is possible to alter
110the behaviour of a class by overriding its event handling functions. In
111many cases this works even for changing the behaviour of native controls.
112
113For example it is possible to filter out a number of key events sent by the
114system to a native text control by overriding wxTextCtrl and defining a
115handler for key events using EVT_KEY_DOWN. This would indeed prevent
116any key events from being sent to the native control - which might not be
117what is desired. In this case the event handler function has to call Skip()
118so as to indicate that the search for the event handler should continue.
119
120To summarize, instead of explicitly calling the base class version as you
121would have done with C++ virtual functions (i.e. @e wxTextCtrl::OnChar()),
122you should instead call wxEvent::Skip.
123
124In practice, this would look like this if the derived text control only
125accepts 'a' to 'z' and 'A' to 'Z':
126
127@code
128void MyTextCtrl::OnChar(wxKeyEvent& event)
129{
130 if ( isalpha( event.KeyCode() ) )
131 {
15b6757b
FM
132 // key code is within legal range. we call event.Skip() so the
133 // event can be processed either in the base wxWidgets class
134 // or the native control.
36c9828f 135
15b6757b 136 event.Skip();
dc28cdf8
FM
137 }
138 else
139 {
15b6757b
FM
140 // illegal key hit. we don't call event.Skip() so the
141 // event is not processed anywhere else.
36c9828f 142
15b6757b 143 wxBell();
dc28cdf8
FM
144 }
145}
146@endcode
147
148The normal order of event table searching by ProcessEvent is as follows:
149
150@li If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled)
151 the function skips to step (6).
152@li If the object is a wxWindow, @b ProcessEvent is recursively called on the window's
153 wxValidator. If this returns @true, the function exits.
154@li @b SearchEventTable is called for this event handler. If this fails, the base
155 class table is tried, and so on until no more tables exist or an appropriate
156 function was found, in which case the function exits.
157@li The search is applied down the entire chain of event handlers (usually the chain has
158 a length of one). If this succeeds, the function exits.
159@li If the object is a wxWindow and the event is set to set to propagate (in the library only
160 wxCommandEvent based events are set to propagate), @b ProcessEvent is recursively applied
161 to the parent window's event handler. If this returns @true, the function exits.
162@li Finally, @b ProcessEvent is called on the wxApp object.
163
164<b>Pay close attention to Step 5</b>. People often overlook or get
165confused by this powerful feature of the wxWidgets event processing
166system. To put it a different way, events set to propagate
167(see wxEvent::ShouldPropagate)
168(most likely derived either directly or indirectly from wxCommandEvent)
169will travel up the containment hierarchy from child to parent until the
170maximal propagation level is reached or an event handler is found that
171doesn't call @c event.Skip().
172
173Finally, there is another additional complication (which, in fact, simplifies
174life of wxWidgets programmers significantly): when propagating the command
175events upwards to the parent window, the event propagation stops when it
176reaches the parent dialog, if any. This means that you don't risk to get
177unexpected events from the dialog controls (which might be left unprocessed by
178the dialog itself because it doesn't care about them) when a modal dialog is
179popped up. The events do propagate beyond the frames, however. The rationale
180for this choice is that there are only a few frames in a typical application
181and their parent-child relation are well understood by the programmer while it
182may be very difficult, if not impossible, to track down all the dialogs which
183may be popped up in a complex program (remember that some are created
184automatically by wxWidgets). If you need to specify a different behaviour for
185some reason, you can use wxWindow::SetExtraStyle(wxWS_EX_BLOCK_EVENTS)
186explicitly to prevent the events from being propagated beyond the given window
187or unset this flag for the dialogs which have it on by default.
188
189Typically events that deal with a window as a window (size, motion,
190paint, mouse, keyboard, etc.) are sent only to the window. Events
191that have a higher level of meaning and/or are generated by the window
192itself, (button click, menu select, tree expand, etc.) are command
193events and are sent up to the parent to see if it is interested in the event.
194
195Note that your application may wish to override ProcessEvent to redirect processing of
196events. This is done in the document/view framework, for example, to allow event handlers
197to be defined in the document or view. To test for command events (which will probably
198be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for efficiency,
199instead of using the slower run-time type system.
200
201As mentioned above, only command events are recursively applied to the parents event
202handler in the library itself. As this quite often causes confusion for users,
203here is a list of system events which will NOT get sent to the parent's event handler:
204
205@li wxEvent: The event base class
206@li wxActivateEvent: A window or application activation event
207@li wxCloseEvent: A close window or end session event
208@li wxEraseEvent: An erase background event
209@li wxFocusEvent: A window focus event
210@li wxKeyEvent: A keypress event
211@li wxIdleEvent: An idle event
212@li wxInitDialogEvent: A dialog initialisation event
213@li wxJoystickEvent: A joystick event
214@li wxMenuEvent: A menu event
215@li wxMouseEvent: A mouse event
216@li wxMoveEvent: A move event
217@li wxPaintEvent: A paint event
218@li wxQueryLayoutInfoEvent: Used to query layout information
219@li wxSetCursorEvent: Used for special cursor processing based on current mouse position
220@li wxSizeEvent: A size event
221@li wxScrollWinEvent: A scroll event sent by a scrolled window (not a scroll bar)
222@li wxSysColourChangedEvent: A system colour change event
223
224In some cases, it might be desired by the programmer to get a certain number
225of system events in a parent window, for example all key events sent to, but not
226used by, the native controls in a dialog. In this case, a special event handler
227will have to be written that will override ProcessEvent() in order to pass
228all events (or any selection of them) to the parent window.
229
230
409e6ce4 231@section overview_eventhandling_prog User Generated Events vs Programmatically Generated Events
dc28cdf8
FM
232
233While generically wxEvents can be generated both by user
234actions (e.g. resize of a wxWindow) and by calls to functions
235(e.g. wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived
236events only for the user-generated events. The only @b exceptions to this rule are:
237
238@li wxNotebook::AddPage: No event-free alternatives
239@li wxNotebook::AdvanceSelection: No event-free alternatives
240@li wxNotebook::DeletePage: No event-free alternatives
241@li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as
242 wxNotebook::SetSelection is deprecated
243@li wxTreeCtrl::Delete: No event-free alternatives
244@li wxTreeCtrl::DeleteAllItems: No event-free alternatives
245@li wxTreeCtrl::EditLabel: No event-free alternatives
246@li All wxTextCtrl methods
247
248wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other
249functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free
250equivalents.
251
252
253
409e6ce4 254@section overview_eventhandling_pluggable Pluggable Event Handlers
dc28cdf8
FM
255
256In fact, you don't have to derive a new class from a window class
257if you don't want to. You can derive a new class from wxEvtHandler instead,
258defining the appropriate event table, and then call wxWindow::SetEventHandler
259(or, preferably, wxWindow::PushEventHandler) to make this
260event handler the object that responds to events. This way, you can avoid
261a lot of class derivation, and use instances of the same event handler class (but different
262objects as the same event handler object shouldn't be used more than once) to
263handle events from instances of different widget classes.
264
265If you ever have to call a window's event handler
266manually, use the GetEventHandler function to retrieve the window's event handler and use that
267to call the member function. By default, GetEventHandler returns a pointer to the window itself
268unless an application has redirected event handling using SetEventHandler or PushEventHandler.
269
270One use of PushEventHandler is to temporarily or permanently change the
271behaviour of the GUI. For example, you might want to invoke a dialog editor
272in your application that changes aspects of dialog boxes. You can
273grab all the input for an existing dialog box, and edit it 'in situ',
274before restoring its behaviour to normal. So even if the application
275has derived new classes to customize behaviour, your utility can indulge
276in a spot of body-snatching. It could be a useful technique for on-line
277tutorials, too, where you take a user through a serious of steps and
278don't want them to diverge from the lesson. Here, you can examine the events
279coming from buttons and windows, and if acceptable, pass them through to
280the original event handler. Use PushEventHandler/PopEventHandler
281to form a chain of event handlers, where each handler processes a different
282range of events independently from the other handlers.
283
284
285
409e6ce4 286@section overview_eventhandling_winid Window Identifiers
dc28cdf8
FM
287
288Window identifiers are integers, and are used to
289uniquely determine window identity in the event system (though you can use it
290for other purposes). In fact, identifiers do not need to be unique
291across your entire application just so long as they are unique within a
292particular context you're interested in, such as a frame and its children. You
293may use the @c wxID_OK identifier, for example, on any number of dialogs so
294long as you don't have several within the same dialog.
295
296If you pass @c wxID_ANY to a window constructor, an identifier will be
297generated for you automatically by wxWidgets. This is useful when you don't
298care about the exact identifier either because you're not going to process the
299events from the control being created at all or because you process the events
300from all controls in one place (in which case you should specify @c wxID_ANY
301in the event table or wxEvtHandler::Connect call
302as well. The automatically generated identifiers are always negative and so
303will never conflict with the user-specified identifiers which must be always
304positive.
305
306See @ref page_stdevtid for the list of standard identifiers availabel.
307You can use wxID_HIGHEST to determine the number above which it is safe to
308define your own identifiers. Or, you can use identifiers below wxID_LOWEST.
309Finally, you can allocate identifiers dynamically using wxNewId() function to.
310If you use wxNewId() consistently in your application, you can be sure that
311the your identifiers don't conflict accidentally.
312
313
409e6ce4 314@section overview_eventhandling_custom Custom Event Summary
dc28cdf8
FM
315
316@subsection overview_eventhandling_custom_general General approach
317
318Since version 2.2.x of wxWidgets, each event type is identified by ID which
319is given to the event type @e at runtime which makes it possible to add
320new event types to the library or application without risking ID clashes
321(two different event types mistakingly getting the same event ID). This
322event type ID is stored in a struct of type @b const wxEventType.
323
324In order to define a new event type, there are principally two choices.
325One is to define a entirely new event class (typically deriving from
326wxEvent or wxCommandEvent.
327
328The other is to use the existing event classes and give them an new event
329type. You'll have to define and declare a new event type using either way,
330and this is done using the following macros:
331
332@code
333// in the header of the source file
334BEGIN_DECLARE_EVENT_TYPES()
335DECLARE_EVENT_TYPE(name, value)
336END_DECLARE_EVENT_TYPES()
337
338// in the implementation
339DEFINE_EVENT_TYPE(name)
340@endcode
341
342You can ignore the @e value parameter of the DECLARE_EVENT_TYPE macro
343since it is used only for backwards compatibility with wxWidgets 2.0.x based
344applications where you have to give the event type ID an explicit value.
345See also the @ref page_samples_event for an example of code
346defining and working with the custom event types.
347
348
409e6ce4 349@subsection overview_eventhandling_custom_existing Using Existing Event Classes
dc28cdf8
FM
350
351If you just want to use a wxCommandEvent with
352a new event type, you can then use one of the generic event table macros
353listed below, without having to define a new macro yourself. This also
354has the advantage that you won't have to define a new wxEvent::Clone()
355method for posting events between threads etc. This could look like this
356in your code:
357
358@code
359DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1)
360DEFINE_EVENT_TYPE(wxEVT_MY_EVENT)
361
362// user code intercepting the event
363
364BEGIN_EVENT_TABLE(MyFrame, wxFrame)
365EVT_MENU (wxID_EXIT, MyFrame::OnExit)
366// ....
367EVT_COMMAND (ID_MY_WINDOW, wxEVT_MY_EVENT, MyFrame::OnMyEvent)
368END_EVENT_TABLE()
369
370void MyFrame::OnMyEvent( wxCommandEvent )
371{
372 // do something
373 wxString text = event.GetText();
374}
36c9828f
FM
375
376
dc28cdf8 377// user code sending the event
36c9828f 378
dc28cdf8
FM
379void MyWindow::SendEvent()
380{
381 wxCommandEvent event( wxEVT_MY_EVENT, GetId() );
382 event.SetEventObject( this );
383 // Give it some contents
384 event.SetText( wxT("Hallo") );
385 // Send it
386 GetEventHandler()->ProcessEvent( event );
387}
388@endcode
36c9828f
FM
389
390
409e6ce4 391@subsection overview_eventhandling_custom_generic Generic Event Table Macros
3b88355f 392
dc28cdf8
FM
393@beginTable
394@row2col{EVT_CUSTOM(event\, id\, func),
395 Allows you to add a custom event table
396 entry by specifying the event identifier (such as wxEVT_SIZE),
397 the window identifier, and a member function to call.}
398@row2col{EVT_CUSTOM_RANGE(event\, id1\, id2\, func),
399 The same as EVT_CUSTOM, but responds to a range of window identifiers.}
400@row2col{EVT_COMMAND(id\, event\, func),
401 The same as EVT_CUSTOM, but expects a member function with a
402 wxCommandEvent argument.}
403@row2col{EVT_COMMAND_RANGE(id1\, id2\, event\, func),
404 The same as EVT_CUSTOM_RANGE, but
405 expects a member function with a wxCommandEvent argument.}
406@row2col{EVT_NOTIFY(event\, id\, func),
407 The same as EVT_CUSTOM, but
408 expects a member function with a wxNotifyEvent argument.}
409@row2col{EVT_NOTIFY_RANGE(event\, id1\, id2\, func),
410 The same as EVT_CUSTOM_RANGE, but
411 expects a member function with a wxNotifyEvent argument.}
412@endTable
3b88355f
FM
413
414
409e6ce4 415@subsection overview_eventhandling_custom_ownclass Defining Your Own Event Class
36c9828f 416
dc28cdf8
FM
417Under certain circumstances, it will be required to define your own event
418class e.g. for sending more complex data from one place to another. Apart
419from defining your event class, you will also need to define your own
420event table macro (which is quite long). Watch out to put in enough
421casts to the inherited event function. Here is an example:
36c9828f 422
dc28cdf8
FM
423@code
424// code defining event
36c9828f 425
dc28cdf8
FM
426class wxPlotEvent: public wxNotifyEvent
427{
428public:
429 wxPlotEvent( wxEventType commandType = wxEVT_NULL, int id = 0 );
36c9828f 430
dc28cdf8
FM
431 // accessors
432 wxPlotCurve *GetCurve()
433 { return m_curve; }
36c9828f 434
dc28cdf8
FM
435 // required for sending with wxPostEvent()
436 virtual wxEvent *Clone() const;
36c9828f 437
dc28cdf8
FM
438private:
439 wxPlotCurve *m_curve;
440};
36c9828f 441
dc28cdf8 442DECLARE_EVENT_TYPE( wxEVT_PLOT_ACTION, -1 )
36c9828f 443
dc28cdf8 444typedef void (wxEvtHandler::*wxPlotEventFunction)(wxPlotEvent&);
36c9828f 445
dc28cdf8
FM
446#define EVT_PLOT(id, fn) \
447 DECLARE_EVENT_TABLE_ENTRY( wxEVT_PLOT_ACTION, id, -1, \
448 (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxNotifyEventFunction) \
449 wxStaticCastEvent( wxPlotEventFunction, &fn ), (wxObject *) NULL ),
36c9828f
FM
450
451
dc28cdf8 452// code implementing the event type and the event class
36c9828f 453
dc28cdf8 454DEFINE_EVENT_TYPE( wxEVT_PLOT_ACTION )
36c9828f 455
dc28cdf8 456wxPlotEvent::wxPlotEvent( ...
36c9828f
FM
457
458
dc28cdf8 459// user code intercepting the event
36c9828f 460
dc28cdf8
FM
461BEGIN_EVENT_TABLE(MyFrame, wxFrame)
462EVT_PLOT (ID_MY_WINDOW, MyFrame::OnPlot)
463END_EVENT_TABLE()
36c9828f 464
dc28cdf8
FM
465void MyFrame::OnPlot( wxPlotEvent &event )
466{
467 wxPlotCurve *curve = event.GetCurve();
468}
36c9828f
FM
469
470
dc28cdf8 471// user code sending the event
36c9828f 472
dc28cdf8
FM
473void MyWindow::SendEvent()
474{
475 wxPlotEvent event( wxEVT_PLOT_ACTION, GetId() );
476 event.SetEventObject( this );
477 event.SetCurve( m_curve );
478 GetEventHandler()->ProcessEvent( event );
479}
480@endcode
36c9828f 481
86faa458 482
409e6ce4 483@section overview_eventhandling_macros Event Handling Summary
86faa458 484
dc28cdf8 485For the full list of event classes, please see the
409e6ce4 486@ref group_class_events "event classes group page".
86faa458 487
3b88355f 488*/
36c9828f 489