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