]>
Commit | Line | Data |
---|---|---|
a007d249 VZ |
1 | /////////////////////////////////////////////////////////////////////////////\r |
2 | // Name: eventhandling.h\r | |
3 | // Purpose: topic overview\r | |
4 | // Author: wxWidgets team\r | |
5 | // RCS-ID: $Id$\r | |
6 | // Licence: wxWindows license\r | |
7 | /////////////////////////////////////////////////////////////////////////////\r | |
8 | \r | |
9 | /**\r | |
3e083d65 | 10 | @page overview_events Events and Event Handling\r |
a007d249 | 11 | \r |
3e083d65 | 12 | Related classes: wxEvtHandler, wxWindow, wxEvent\r |
a007d249 | 13 | \r |
3e083d65 VZ |
14 | @li @ref overview_events_introduction\r |
15 | @li @ref overview_events_eventhandling\r | |
16 | @li @ref overview_events_processing\r | |
17 | @li @ref overview_events_custom\r | |
18 | @li @ref overview_events_misc\r | |
a007d249 VZ |
19 | \r |
20 | \r | |
21 | <hr>\r | |
22 | \r | |
23 | \r | |
3e083d65 VZ |
24 | @section overview_events_introduction Introduction to Events\r |
25 | \r | |
26 | Like with all the other GUI frameworks, the control of flow in wxWidgets\r | |
27 | applications is event-based: the program normally performs most of its actions\r | |
28 | in response to the events generated by the user. These events can be triggered\r | |
29 | by using the input devices (such as keyboard, mouse, joystick) directly or,\r | |
30 | more commonly, by a standard control which synthesizes such input events into\r | |
31 | higher level events: for example, a wxButton can generate a click event when\r | |
32 | the user presses the left mouse button on it and then releases it without\r | |
33 | pressing @c Esc in the meanwhile. There are also events which don't directly\r | |
34 | correspond to the user actions, such as wxTimerEvent or wxSocketEvent.\r | |
35 | \r | |
36 | But in all cases wxWidgets represents these events in a uniform way and allows\r | |
37 | you to handle them in the same way wherever they originate from. And while the\r | |
38 | events are normally generated by wxWidgets itself, you can also do this, which\r | |
39 | is especially useful when using custom events (see @ref overview_events_custom).\r | |
40 | \r | |
41 | To be more precise, each event is described by:\r | |
42 | - <em>Event type</em>: this is simply a value of type wxEventType which\r | |
43 | uniquely identifies the type of the event. For example, clicking on a button,\r | |
44 | selecting an item from a list box and pressing a key on the keyboard all\r | |
45 | generate events with different event types.\r | |
46 | - <em>Event class</em> carried by the event: each event has some information\r | |
47 | associated with it and this data is represented by an object of a class\r | |
48 | derived from wxEvent. Events of different types can use the same event class,\r | |
49 | for example both button click and listbox selection events use wxCommandEvent\r | |
50 | class (as do all the other simple control events), but the key press event\r | |
51 | uses wxKeyEvent as the information associated with it is different.\r | |
52 | - <em>Event source</em>: wxEvent stores the object which generated the event\r | |
53 | and, for windows, its identifier (see @ref overview_events_winid). As it is\r | |
54 | common to have more than one object generating events of the same type (e.g. a\r | |
55 | typical window contains several buttons, all generating the same button click\r | |
56 | event), checking the event source object or its id allows to distinguish\r | |
57 | between them.\r | |
58 | \r | |
59 | \r | |
60 | @section overview_events_eventhandling Event Handling\r | |
a007d249 VZ |
61 | \r |
62 | There are two principal ways to handle events in wxWidgets. One of them uses\r | |
63 | <em>event table</em> macros and allows you to define the connection between events\r | |
d76259e2 | 64 | and their handlers only statically, i.e., during program compilation. The other\r |
a007d249 | 65 | one uses wxEvtHandler::Connect() call and can be used to connect, and\r |
d76259e2 FM |
66 | disconnect, the handlers dynamically, i.e., during run-time depending on some\r |
67 | conditions. It also allows the direct connection of the events of one object to a\r | |
68 | handler method in another object. The static event tables can only handle\r | |
a007d249 VZ |
69 | events in the object where they are defined so using Connect() is more flexible\r |
70 | than using the event tables. On the other hand, event tables are more succinct\r | |
71 | and centralize all event handlers connection in one place. You can either\r | |
d76259e2 | 72 | choose a single approach that you find preferable or freely combine both\r |
a007d249 VZ |
73 | methods in your program in different classes or even in one and the same class,\r |
74 | although this is probably sufficiently confusing to be a bad idea.\r | |
75 | \r | |
d76259e2 FM |
76 | But before you make this choice, let us discuss these two ways in more\r |
77 | detail. In the next section we provide a short introduction to handling the\r | |
3e083d65 | 78 | events using the event tables. Please see @ref overview_events_connect\r |
a007d249 VZ |
79 | for the discussion of Connect().\r |
80 | \r | |
3e083d65 | 81 | @subsection overview_events_eventtables Event Handling with Event Tables\r |
a007d249 VZ |
82 | \r |
83 | To use an <em>event table</em> you must first decide in which class you wish to\r | |
84 | handle the events. The only requirement imposed by wxWidgets is that this class\r | |
85 | must derive from wxEvtHandler and so, considering that wxWindow derives from\r | |
86 | it, any classes representing windows can handle events. Simple events such as\r | |
87 | menu commands are usually processed at the level of a top-level window\r | |
88 | containing the menu, so let's suppose that you need to handle some events in @c\r | |
89 | MyFrame class deriving from wxFrame.\r | |
90 | \r | |
d76259e2 FM |
91 | First define one or more <em>event handlers</em>. They\r |
92 | are just simple (non-virtual) methods of the class that take as a parameter a\r | |
93 | reference to an object of a wxEvent-derived class and have no return value (any\r | |
a007d249 VZ |
94 | return information is passed via the argument, which is why it is non-const).\r |
95 | You also need to insert a macro\r | |
96 | \r | |
97 | @code\r | |
98 | DECLARE_EVENT_TABLE()\r | |
99 | @endcode\r | |
100 | \r | |
d76259e2 FM |
101 | somewhere in the class declaration. It doesn't matter where it appears but\r |
102 | it's customary to put it at the end because the macro changes the access\r | |
103 | type internally so it's safest if nothing follows it. The\r | |
a007d249 VZ |
104 | full class declaration might look like this:\r |
105 | \r | |
106 | @code\r | |
107 | class MyFrame : public wxFrame\r | |
108 | {\r | |
109 | public:\r | |
110 | MyFrame(...) : wxFrame(...) { }\r | |
111 | \r | |
112 | ...\r | |
113 | \r | |
114 | protected:\r | |
115 | int m_whatever;\r | |
116 | \r | |
117 | private:\r | |
d76259e2 FM |
118 | // Notice that as the event handlers normally are not called from outside\r |
119 | // the class, they normally are private. In particular they don't need\r | |
120 | // to be public.\r | |
a007d249 VZ |
121 | void OnExit(wxCommandEvent& event);\r |
122 | void OnButton1(wxCommandEvent& event);\r | |
123 | void OnSize(wxSizeEvent& event);\r | |
124 | \r | |
125 | // it's common to call the event handlers OnSomething() but there is no\r | |
d76259e2 | 126 | // obligation to do that; this one is an event handler too:\r |
a007d249 VZ |
127 | void DoTest(wxCommandEvent& event);\r |
128 | \r | |
129 | DECLARE_EVENT_TABLE()\r | |
130 | };\r | |
131 | @endcode\r | |
132 | \r | |
d76259e2 FM |
133 | Next the event table must be defined and, as with any definition, it must be\r |
134 | placed in an implementation file. The event table tells wxWidgets how to map\r | |
a007d249 VZ |
135 | events to member functions and in our example it could look like this:\r |
136 | \r | |
137 | @code\r | |
138 | BEGIN_EVENT_TABLE(MyFrame, wxFrame)\r | |
139 | EVT_MENU(wxID_EXIT, MyFrame::OnExit)\r | |
140 | EVT_MENU(DO_TEST, MyFrame::DoTest)\r | |
141 | EVT_SIZE(MyFrame::OnSize)\r | |
142 | EVT_BUTTON(BUTTON1, MyFrame::OnButton1)\r | |
143 | END_EVENT_TABLE()\r | |
144 | @endcode\r | |
145 | \r | |
146 | Notice that you must mention a method you want to use for the event handling in\r | |
d76259e2 | 147 | the event table definition; just defining it in MyFrame class is @e not enough.\r |
a007d249 VZ |
148 | \r |
149 | Let us now look at the details of this definition: the first line means that we\r | |
150 | are defining the event table for MyFrame class and that its base class is\r | |
d76259e2 | 151 | wxFrame, so events not processed by MyFrame will, by default, be handled by\r |
a007d249 VZ |
152 | wxFrame. The next four lines define connections of individual events to their\r |
153 | handlers: the first two of them map menu commands from the items with the\r | |
154 | identifiers specified as the first macro parameter to two different member\r | |
155 | functions. In the next one, @c EVT_SIZE means that any changes in the size of\r | |
156 | the frame will result in calling OnSize() method. Note that this macro doesn't\r | |
157 | need a window identifier, since normally you are only interested in the current\r | |
158 | window's size events.\r | |
159 | \r | |
6496345c | 160 | The @c EVT_BUTTON macro demonstrates that the originating event does not have to\r |
a007d249 VZ |
161 | come from the window class implementing the event table -- if the event source\r |
162 | is a button within a panel within a frame, this will still work, because event\r | |
d76259e2 FM |
163 | tables are searched up through the hierarchy of windows for the command events.\r |
164 | (But only command events, so you can't catch mouse move events in a child\r | |
a007d249 | 165 | control in the parent window in the same way because wxMouseEvent doesn't\r |
d76259e2 | 166 | derive from wxCommandEvent. See below for how you can do it.) In this case, the\r |
a007d249 VZ |
167 | button's event table will be searched, then the parent panel's, then the\r |
168 | frame's.\r | |
169 | \r | |
170 | Finally, you need to implement the event handlers. As mentioned before, all\r | |
171 | event handlers take a wxEvent-derived argument whose exact class differs\r | |
172 | according to the type of event and the class of the originating window. For\r | |
173 | size events, wxSizeEvent is used. For menu commands and most control commands\r | |
d76259e2 | 174 | (such as button presses), wxCommandEvent is used. When controls get more\r |
a007d249 VZ |
175 | complicated, more specific wxCommandEvent-derived event classes providing\r |
176 | additional control-specific information can be used, such as wxTreeEvent for\r | |
177 | events from wxTreeCtrl windows.\r | |
178 | \r | |
179 | In the simplest possible case an event handler may not use the @c event\r | |
d76259e2 | 180 | parameter at all. For example,\r |
a007d249 VZ |
181 | \r |
182 | @code\r | |
d76259e2 | 183 | void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event))\r |
a007d249 VZ |
184 | {\r |
185 | // when the user selects "Exit" from the menu we should close\r | |
186 | Close(true);\r | |
187 | }\r | |
188 | @endcode\r | |
189 | \r | |
190 | In other cases you may need some information carried by the @c event argument,\r | |
191 | as in:\r | |
192 | \r | |
193 | @code\r | |
194 | void MyFrame::OnSize(wxSizeEvent& event)\r | |
195 | {\r | |
196 | wxSize size = event.GetSize();\r | |
197 | \r | |
198 | ... update the frame using the new size ...\r | |
199 | }\r | |
200 | @endcode\r | |
201 | \r | |
202 | You will find the details about the event table macros and the corresponding\r | |
203 | wxEvent-derived classes in the discussion of each control generating these\r | |
204 | events.\r | |
205 | \r | |
206 | \r | |
3e083d65 | 207 | @subsection overview_events_connect Dynamic Event Handling\r |
a007d249 | 208 | \r |
d76259e2 FM |
209 | As with the event tables, decide in which class you intend to\r |
210 | handle the events first and, as before, this class must derive from\r | |
211 | wxEvtHandler (usually indirectly via wxWindow). See the declaration of MyFrame\r | |
a007d249 | 212 | in the previous section. However the similarities end here and both the syntax\r |
d76259e2 | 213 | and the possibilities of handling events in this way are rather different.\r |
2a638719 | 214 | \r |
a007d249 | 215 | Let us start by looking at the syntax: the first obvious difference is that you\r |
7f853dd0 | 216 | need not use DECLARE_EVENT_TABLE() nor BEGIN_EVENT_TABLE() and the\r |
d76259e2 FM |
217 | associated macros. Instead, in any place in your code, but usually in\r |
218 | the code of the class defining the handler itself (and definitely not in the\r | |
219 | global scope as with the event tables), call its Connect() method like this:\r | |
a007d249 VZ |
220 | \r |
221 | @code\r | |
222 | MyFrame::MyFrame(...)\r | |
223 | {\r | |
224 | Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,\r | |
225 | wxCommandEventHandler(MyFrame::OnExit));\r | |
226 | }\r | |
227 | @endcode\r | |
228 | \r | |
229 | This class should be self-explanatory except for wxCommandEventHandler part:\r | |
d76259e2 FM |
230 | this is a macro that ensures that the method is of the correct type by using\r |
231 | static_cast in the same way as the event table macros.\r | |
a007d249 VZ |
232 | \r |
233 | Now let us describe the semantic differences:\r | |
234 | <ul>\r | |
235 | <li>\r | |
d76259e2 FM |
236 | Event handlers can be connected at any moment. For example, it's possible\r |
237 | to do some initialization first and only connect the handlers if and when\r | |
238 | it succeeds. This can avoid the need to test that the object was properly\r | |
239 | initialized in the event handlers themselves. With Connect() they\r | |
240 | simply won't be called if it wasn't correctly initialized.\r | |
a007d249 VZ |
241 | </li>\r |
242 | \r | |
243 | <li>\r | |
244 | As a slight extension of the above, the handlers can also be\r | |
d76259e2 FM |
245 | Disconnect()-ed at any time and maybe later reconnected. Of course,\r |
246 | it's also possible to emulate this behaviour with the classic\r | |
247 | static (i.e., connected via event tables) handlers by using an internal\r | |
a007d249 VZ |
248 | flag indicating whether the handler is currently enabled and returning\r |
249 | from it if it isn't, but using dynamically connected handlers requires\r | |
250 | less code and is also usually more clear.\r | |
251 | </li>\r | |
252 | \r | |
253 | <li>\r | |
254 | Also notice that you must derive a class inherited from, say,\r | |
255 | wxTextCtrl even if you don't want to modify the control behaviour at\r | |
256 | all but just want to handle some of its events. This is especially\r | |
257 | inconvenient when the control is loaded from the XRC. Connecting the\r | |
258 | event handler dynamically bypasses the need for this unwanted\r | |
259 | sub-classing.\r | |
260 | </li>\r | |
261 | \r | |
262 | <li>\r | |
263 | Last but very, very far from least is the possibility to connect an\r | |
264 | event of some object to a method of another object. This is impossible\r | |
d76259e2 | 265 | to do with event tables because it is not possible to specify the\r |
a007d249 VZ |
266 | object to dispatch the event to so it necessarily needs to be sent to\r |
267 | the same object which generated the event. Not so with Connect() which\r | |
d76259e2 | 268 | has an optional @c eventSink parameter that can be used to specify the\r |
a007d249 | 269 | object which will handle the event. Of course, in this case the method\r |
d76259e2 | 270 | being connected must belong to the class that is the type of the\r |
a007d249 VZ |
271 | @c eventSink object! To give a quick example, people often want to catch\r |
272 | mouse movement events happening when the mouse is in one of the frame\r | |
273 | children in the frame itself. Doing it in a naive way doesn't work:\r | |
274 | <ul>\r | |
275 | <li>\r | |
276 | A @c EVT_LEAVE_WINDOW(MyFrame::OnMouseLeave) line in the frame\r | |
277 | event table has no effect as mouse move (including entering and\r | |
d76259e2 | 278 | leaving) events are not propagated up to the parent window\r |
a007d249 VZ |
279 | (at least not by default).\r |
280 | </li>\r | |
281 | \r | |
282 | <li>\r | |
283 | Putting the same line in a child event table will crash during\r | |
284 | run-time because the MyFrame method will be called on a wrong\r | |
285 | object -- it's easy to convince oneself that the only object\r | |
d76259e2 | 286 | that can be used here is the pointer to the child, as\r |
a007d249 VZ |
287 | wxWidgets has nothing else. But calling a frame method with the\r |
288 | child window pointer instead of the pointer to the frame is, of\r | |
289 | course, disastrous.\r | |
290 | </li>\r | |
291 | </ul>\r | |
292 | \r | |
293 | However writing\r | |
294 | @code\r | |
295 | MyFrame::MyFrame(...)\r | |
296 | {\r | |
297 | m_child->Connect(wxID_ANY, wxEVT_LEAVE_WINDOW,\r | |
298 | wxMouseEventHandler(MyFrame::OnMouseLeave),\r | |
299 | NULL, // unused extra data parameter\r | |
300 | this); // this indicates the object to connect to\r | |
301 | }\r | |
4eda9c09 | 302 | @endcode\r |
d76259e2 FM |
303 | will work exactly as expected. Note that you can get the object that\r |
304 | generated the event -- and that is not the same as the frame -- via\r | |
4eda9c09 VZ |
305 | wxEvent::GetEventObject() method of @c event argument passed to the\r |
306 | event handler.\r | |
307 | </li>\r | |
a007d249 VZ |
308 | </ul>\r |
309 | \r | |
310 | To summarize, using Connect() requires slightly more typing but is much more\r | |
311 | flexible than using static event tables so don't hesitate to use it when you\r | |
312 | need this extra power. On the other hand, event tables are still perfectly fine\r | |
313 | in simple situations where this extra flexibility is not needed.\r | |
314 | \r | |
315 | \r | |
3e083d65 | 316 | @section overview_events_processing How Events are Processed\r |
a007d249 | 317 | \r |
8319fb52 | 318 | The previous sections explain how to define event handlers but don't address\r |
d76259e2 FM |
319 | the question of how exactly wxWidgets finds the handler to call for the\r |
320 | given event. This section describes the algorithm used in detail.\r | |
8319fb52 | 321 | \r |
a007d249 | 322 | When an event is received from the windowing system, wxWidgets calls\r |
8319fb52 VZ |
323 | wxEvtHandler::ProcessEvent() on the first event handler object belonging to the\r |
324 | window generating the event. The normal order of event table searching by\r | |
325 | ProcessEvent() is as follows, with the event processing stopping as soon as a\r | |
326 | handler is found (unless the handler calls wxEvent::Skip() in which case it\r | |
4eda9c09 | 327 | doesn't count as having handled the event and the search continues):\r |
8319fb52 VZ |
328 | <ol>\r |
329 | <li value="0">\r | |
330 | Before anything else happens, wxApp::FilterEvent() is called. If it returns\r | |
331 | anything but -1 (default), the event handling stops immediately.\r | |
332 | </li>\r | |
a007d249 | 333 | \r |
8319fb52 VZ |
334 | <li value="1">\r |
335 | If this event handler is disabled via a call to\r | |
336 | wxEvtHandler::SetEvtHandlerEnabled() the next three steps are skipped and\r | |
337 | the event handler resumes at step (5).\r | |
d76259e2 | 338 | </li>\r |
a007d249 | 339 | \r |
8319fb52 VZ |
340 | <li value="2">\r |
341 | If the object is a wxWindow and has an associated validator, wxValidator\r | |
342 | gets a chance to process the event.\r | |
343 | </li>\r | |
a007d249 | 344 | \r |
8319fb52 | 345 | <li value="3">\r |
d76259e2 | 346 | The list of dynamically connected event handlers, i.e., those for which\r |
8319fb52 VZ |
347 | Connect() was called, is consulted. Notice that this is done before\r |
348 | checking the static event table entries, so if both a dynamic and a static\r | |
349 | event handler match the same event, the static one is never going to be\r | |
350 | used.\r | |
351 | </li>\r | |
a007d249 | 352 | \r |
8319fb52 VZ |
353 | <li value="4">\r |
354 | The event table containing all the handlers defined using the event table\r | |
355 | macros in this class and its base classes is examined. Notice that this\r | |
356 | means that any event handler defined in a base class will be executed at\r | |
357 | this step.\r | |
358 | </li>\r | |
a007d249 | 359 | \r |
8319fb52 VZ |
360 | <li value="5">\r |
361 | The event is passed to the next event handler, if any, in the event handler\r | |
d76259e2 | 362 | chain, i.e., the steps (1) to (4) are done for it. This chain can be formed\r |
7f853dd0 | 363 | using wxEvtHandler::SetNextHandler():\r |
3e083d65 | 364 | @image html overview_events_chain.png\r |
7f853dd0 FM |
365 | (referring to the image, if @c A->ProcessEvent is called and it doesn't handle\r |
366 | the event, @c B->ProcessEvent will be called and so on...).\r | |
367 | In the case of wxWindow you can build a stack (implemented using wxEvtHandler\r | |
368 | double-linked list) using wxWindow::PushEventHandler():\r | |
3e083d65 | 369 | @image html overview_events_winstack.png\r |
7f853dd0 FM |
370 | (referring to the image, if @c W->ProcessEvent is called, it immediately calls\r |
371 | @c A->ProcessEvent; if nor @c A nor @c B handle the event, then the wxWindow\r | |
372 | itself is used - i.e. the dynamically connected event handlers and static\r | |
373 | event table entries of wxWindow are looked as the last possibility, after\r | |
374 | all pushed event handlers were tested).\r | |
375 | Note however that usually there are no wxEvtHandler chains nor wxWindows stacks\r | |
376 | so this step will usually do anything.\r | |
8319fb52 | 377 | </li>\r |
a007d249 | 378 | \r |
8319fb52 | 379 | <li value="6">\r |
358e9f2f VZ |
380 | If the object is a wxWindow and the event is set to propagate (by default\r |
381 | only wxCommandEvent-derived events are set to propagate), then the\r | |
8319fb52 | 382 | processing restarts from the step (1) (and excluding the step (7)) for the\r |
358e9f2f VZ |
383 | parent window. If this object is not a window but the next handler exists,\r |
384 | the event is passed to its parent if it is a window. This ensures that in a\r | |
385 | common case of (possibly several) non-window event handlers pushed on top\r | |
386 | of a window, the event eventually reaches the window parent.\r | |
8319fb52 VZ |
387 | </li>\r |
388 | \r | |
389 | <li value="7">\r | |
d76259e2 | 390 | Finally, i.e., if the event is still not processed, the wxApp object itself\r |
7f853dd0 | 391 | (which derives from wxEvtHandler) gets a last chance to process it.\r |
8319fb52 | 392 | </li>\r |
a007d249 | 393 | </ol>\r |
8319fb52 | 394 | \r |
4eda9c09 | 395 | <em>Please pay close attention to step 6!</em> People often overlook or get\r |
8319fb52 | 396 | confused by this powerful feature of the wxWidgets event processing system. The\r |
d76259e2 | 397 | details of event propagation up the window hierarchy are described in the\r |
8319fb52 VZ |
398 | next section.\r |
399 | \r | |
400 | Also please notice that there are additional steps in the event handling for\r | |
d76259e2 | 401 | the windows-making part of wxWidgets document-view framework, i.e.,\r |
8319fb52 | 402 | wxDocParentFrame, wxDocChildFrame and their MDI equivalents wxDocMDIParentFrame\r |
d76259e2 | 403 | and wxDocMDIChildFrame. The parent frame classes modify step (2) above to\r |
8319fb52 VZ |
404 | send the events received by them to wxDocManager object first. This object, in\r |
405 | turn, sends the event to the current view and the view itself lets its\r | |
d76259e2 | 406 | associated document process the event first. The child frame classes send\r |
8319fb52 VZ |
407 | the event directly to the associated view which still forwards it to its\r |
408 | document object. Notice that to avoid remembering the exact order in which the\r | |
409 | events are processed in the document-view frame, the simplest, and recommended,\r | |
d76259e2 | 410 | solution is to only handle the events at the view classes level, and not in the\r |
8319fb52 VZ |
411 | document or document manager classes\r |
412 | \r | |
413 | \r | |
3e083d65 | 414 | @subsection overview_events_propagation How Events Propagate Upwards\r |
8319fb52 | 415 | \r |
3e083d65 VZ |
416 | As mentioned above, the events of the classes deriving from wxCommandEvent are\r |
417 | propagated by default to the parent window if they are not processed in this\r | |
418 | window itself. But although by default only the command events are propagated\r | |
419 | like this, other events can be propagated as well because the event handling\r | |
420 | code uses wxEvent::ShouldPropagate() to check whether an event should be\r | |
421 | propagated. It is also possible to propagate the event only a limited number of\r | |
422 | times and not until it is processed (or a top level parent window is reached).\r | |
a007d249 VZ |
423 | \r |
424 | Finally, there is another additional complication (which, in fact, simplifies\r | |
425 | life of wxWidgets programmers significantly): when propagating the command\r | |
d76259e2 FM |
426 | events up to the parent window, the event propagation stops when it\r |
427 | reaches the parent dialog, if any. This means that you don't risk getting\r | |
a007d249 VZ |
428 | unexpected events from the dialog controls (which might be left unprocessed by\r |
429 | the dialog itself because it doesn't care about them) when a modal dialog is\r | |
430 | popped up. The events do propagate beyond the frames, however. The rationale\r | |
431 | for this choice is that there are only a few frames in a typical application\r | |
432 | and their parent-child relation are well understood by the programmer while it\r | |
d76259e2 | 433 | may be difficult, if not impossible, to track down all the dialogs that\r |
a007d249 VZ |
434 | may be popped up in a complex program (remember that some are created\r |
435 | automatically by wxWidgets). If you need to specify a different behaviour for\r | |
436 | some reason, you can use wxWindow::SetExtraStyle(wxWS_EX_BLOCK_EVENTS)\r | |
437 | explicitly to prevent the events from being propagated beyond the given window\r | |
d76259e2 | 438 | or unset this flag for the dialogs that have it on by default.\r |
a007d249 VZ |
439 | \r |
440 | Typically events that deal with a window as a window (size, motion,\r | |
441 | paint, mouse, keyboard, etc.) are sent only to the window. Events\r | |
d76259e2 | 442 | that have a higher level of meaning or are generated by the window\r |
a007d249 VZ |
443 | itself, (button click, menu select, tree expand, etc.) are command\r |
444 | events and are sent up to the parent to see if it is interested in the event.\r | |
445 | \r | |
8319fb52 VZ |
446 | As mentioned above, only command events are recursively applied to the parents\r |
447 | event handler in the library itself. As this quite often causes confusion for\r | |
d76259e2 | 448 | users, here is a list of system events that will @em not get sent to the\r |
8319fb52 | 449 | parent's event handler:\r |
a007d249 VZ |
450 | \r |
451 | @li wxEvent: The event base class\r | |
452 | @li wxActivateEvent: A window or application activation event\r | |
453 | @li wxCloseEvent: A close window or end session event\r | |
454 | @li wxEraseEvent: An erase background event\r | |
455 | @li wxFocusEvent: A window focus event\r | |
456 | @li wxKeyEvent: A keypress event\r | |
457 | @li wxIdleEvent: An idle event\r | |
458 | @li wxInitDialogEvent: A dialog initialisation event\r | |
459 | @li wxJoystickEvent: A joystick event\r | |
460 | @li wxMenuEvent: A menu event\r | |
461 | @li wxMouseEvent: A mouse event\r | |
462 | @li wxMoveEvent: A move event\r | |
463 | @li wxPaintEvent: A paint event\r | |
464 | @li wxQueryLayoutInfoEvent: Used to query layout information\r | |
465 | @li wxSetCursorEvent: Used for special cursor processing based on current mouse position\r | |
466 | @li wxSizeEvent: A size event\r | |
467 | @li wxScrollWinEvent: A scroll event sent by a scrolled window (not a scroll bar)\r | |
468 | @li wxSysColourChangedEvent: A system colour change event\r | |
469 | \r | |
470 | In some cases, it might be desired by the programmer to get a certain number\r | |
471 | of system events in a parent window, for example all key events sent to, but not\r | |
472 | used by, the native controls in a dialog. In this case, a special event handler\r | |
473 | will have to be written that will override ProcessEvent() in order to pass\r | |
474 | all events (or any selection of them) to the parent window.\r | |
475 | \r | |
476 | \r | |
3e083d65 | 477 | @section overview_events_custom Custom Event Summary\r |
a007d249 | 478 | \r |
3e083d65 | 479 | @subsection overview_events_custom_general General approach\r |
a007d249 | 480 | \r |
4475b410 VZ |
481 | As each event is uniquely defined by its event type, defining a custom event\r |
482 | starts with defining a new event type for it. This is done using\r | |
483 | wxDEFINE_EVENT() macro. As an event type is a variable, it can also be\r | |
484 | declared using wxDECLARE_EVENT() if necessary.\r | |
a007d249 | 485 | \r |
4475b410 VZ |
486 | The next thing to do is to decide whether you need to define a custom event\r |
487 | class for events of this type or if you can reuse an existing class, typically\r | |
488 | either wxEvent (which doesn't provide any extra information) or wxCommandEvent\r | |
489 | (which contains several extra fields and also propagates upwards by default).\r | |
490 | Both strategies are described in details below. See also the @ref\r | |
491 | page_samples_event for a complete example of code defining and working with the\r | |
492 | custom event types.\r | |
a007d249 VZ |
493 | \r |
494 | \r | |
3e083d65 | 495 | @subsection overview_events_custom_existing Using Existing Event Classes\r |
a007d249 | 496 | \r |
4475b410 VZ |
497 | If you just want to use a wxCommandEvent with a new event type, use one of the\r |
498 | generic event table macros listed below, without having to define a new event\r | |
499 | class yourself.\r | |
c53ab026 FM |
500 | \r |
501 | Example:\r | |
a007d249 VZ |
502 | \r |
503 | @code\r | |
4475b410 VZ |
504 | // this is typically in a header: it just declares MY_EVENT event type\r |
505 | wxDECLARE_EVENT(MY_EVENT, wxCommandEvent);\r | |
a007d249 | 506 | \r |
4475b410 VZ |
507 | // this is a definition so can't be in a header\r |
508 | wxDEFINE_EVENT(MY_EVENT, wxCommandEvent);\r | |
a007d249 | 509 | \r |
4475b410 | 510 | // example of code handling the event with event tables\r |
a007d249 | 511 | BEGIN_EVENT_TABLE(MyFrame, wxFrame)\r |
4475b410 VZ |
512 | EVT_MENU (wxID_EXIT, MyFrame::OnExit)\r |
513 | ...\r | |
514 | EVT_COMMAND (ID_MY_WINDOW, MY_EVENT, MyFrame::OnMyEvent)\r | |
a007d249 VZ |
515 | END_EVENT_TABLE()\r |
516 | \r | |
4475b410 | 517 | void MyFrame::OnMyEvent(wxCommandEvent& event)\r |
a007d249 VZ |
518 | {\r |
519 | // do something\r | |
520 | wxString text = event.GetText();\r | |
521 | }\r | |
522 | \r | |
4475b410 VZ |
523 | // example of code handling the event with Connect():\r |
524 | MyFrame::MyFrame()\r | |
525 | {\r | |
526 | Connect(ID_MY_WINDOW, MY_EVENT, &MyFrame::OnMyEvent);\r | |
527 | }\r | |
a007d249 | 528 | \r |
4475b410 | 529 | // example of code generating the event\r |
a007d249 VZ |
530 | void MyWindow::SendEvent()\r |
531 | {\r | |
4475b410 VZ |
532 | wxCommandEvent event(MY_EVENT, GetId());\r |
533 | event.SetEventObject(this);\r | |
c53ab026 | 534 | \r |
a007d249 | 535 | // Give it some contents\r |
4475b410 | 536 | event.SetText("Hello");\r |
c53ab026 | 537 | \r |
4475b410 VZ |
538 | // Do send it\r |
539 | ProcessWindowEvent(event);\r | |
a007d249 VZ |
540 | }\r |
541 | @endcode\r | |
542 | \r | |
543 | \r | |
3e083d65 | 544 | @subsection overview_events_custom_ownclass Defining Your Own Event Class\r |
a007d249 | 545 | \r |
4475b410 VZ |
546 | Under certain circumstances, you must define your own event class e.g., for\r |
547 | sending more complex data from one place to another. Apart from defining your\r | |
548 | event class, you also need to define your own event table macro if you want to\r | |
549 | use event tables for handling events of this type.\r | |
a007d249 | 550 | \r |
4475b410 | 551 | Here is an example:\r |
a007d249 | 552 | \r |
4475b410 VZ |
553 | @code\r |
554 | // define a new event class\r | |
555 | class MyPlotEvent: public wxEvent\r | |
a007d249 VZ |
556 | {\r |
557 | public:\r | |
4475b410 VZ |
558 | MyPlotEvent(wxEventType eventType, int winid, const wxPoint& pos)\r |
559 | : wxEvent(winid, eventType),\r | |
560 | m_pos(pos)\r | |
561 | {\r | |
562 | }\r | |
a007d249 VZ |
563 | \r |
564 | // accessors\r | |
4475b410 | 565 | wxPoint GetPoint() const { return m_pos; }\r |
a007d249 | 566 | \r |
4475b410 VZ |
567 | // implement the base class pure virtual\r |
568 | virtual wxEvent *Clone() const { return new MyPlotEvent(*this); }\r | |
a007d249 VZ |
569 | \r |
570 | private:\r | |
4475b410 | 571 | const wxPoint m_pos;\r |
a007d249 VZ |
572 | };\r |
573 | \r | |
4475b410 VZ |
574 | // we define a single MY_PLOT_CLICKED event type associated with the class\r |
575 | // above but typically you are going to have more than one event type, e.g. you\r | |
576 | // could also have MY_PLOT_ZOOMED or MY_PLOT_PANNED &c -- in which case you\r | |
577 | // would just add more similar lines here\r | |
578 | wxDEFINE_EVENT(MY_PLOT_CLICKED, MyPlotEvent);\r | |
a007d249 VZ |
579 | \r |
580 | \r | |
4475b410 VZ |
581 | // if you want to support old compilers you need to use some ugly macros:\r |
582 | typedef void (wxEvtHandler::*MyPlotEventFunction)(MyPlotEvent&);\r | |
583 | #define MyPlotEventHandler(func) wxEVENT_HANDLER_CAST(MyPlotEventFunction, func)\r | |
a007d249 | 584 | \r |
4475b410 VZ |
585 | // if your code is only built sing reasonably modern compilers, you could just\r |
586 | // do this instead:\r | |
587 | #define MyPlotEventHandler(func) (&func)\r | |
a007d249 | 588 | \r |
4475b410 VZ |
589 | // finally define a macro for creating the event table entries for the new\r |
590 | // event type\r | |
591 | //\r | |
592 | // remember that you don't need this at all if you only use Connect() and that\r | |
593 | // you can replace MyPlotEventHandler(func) with just &func unless you use a\r | |
594 | // really old compiler\r | |
595 | #define MY_EVT_PLOT_CLICK(id, func) \\r | |
596 | wx__DECLARE_EVT1(MY_PLOT_CLICKED, id, MyPlotEventHandler(func))\r | |
a007d249 VZ |
597 | \r |
598 | \r | |
4475b410 VZ |
599 | // example of code handling the event (you will use one of these methods, not\r |
600 | // both, of course):\r | |
a007d249 | 601 | BEGIN_EVENT_TABLE(MyFrame, wxFrame)\r |
4475b410 | 602 | EVT_PLOT(ID_MY_WINDOW, MyFrame::OnPlot)\r |
a007d249 VZ |
603 | END_EVENT_TABLE()\r |
604 | \r | |
4475b410 | 605 | MyFrame::MyFrame()\r |
a007d249 | 606 | {\r |
4475b410 | 607 | Connect(ID_MY_WINDOW, MY_PLOT_CLICKED, &MyFrame::OnPlot);\r |
a007d249 VZ |
608 | }\r |
609 | \r | |
4475b410 VZ |
610 | void MyFrame::OnPlot(MyPlotEvent& event)\r |
611 | {\r | |
612 | ... do something with event.GetPoint() ...\r | |
613 | }\r | |
a007d249 | 614 | \r |
a007d249 | 615 | \r |
4475b410 | 616 | // example of code generating the event:\r |
a007d249 VZ |
617 | void MyWindow::SendEvent()\r |
618 | {\r | |
4475b410 VZ |
619 | MyPlotEvent event(MY_PLOT_CLICKED, GetId(), wxPoint(...));\r |
620 | event.SetEventObject(this);\r | |
621 | ProcessWindowEvent(event);\r | |
a007d249 VZ |
622 | }\r |
623 | @endcode\r | |
624 | \r | |
625 | \r | |
4475b410 | 626 | \r |
3e083d65 VZ |
627 | @section overview_events_misc Miscellaneous Notes\r |
628 | \r | |
629 | @subsection overview_events_virtual Event Handlers vs Virtual Methods\r | |
630 | \r | |
631 | It may be noted that wxWidgets' event processing system implements something\r | |
632 | close to virtual methods in normal C++ in spirit: both of these mechanisms\r | |
633 | allow you to alter the behaviour of the base class by defining the event handling\r | |
634 | functions in the derived classes.\r | |
635 | \r | |
636 | There is however an important difference between the two mechanisms when you\r | |
637 | want to invoke the default behaviour, as implemented by the base class, from a\r | |
638 | derived class handler. With the virtual functions, you need to call the base\r | |
639 | class function directly and you can do it either in the beginning of the\r | |
640 | derived class handler function (to post-process the event) or at its end (to\r | |
641 | pre-process the event). With the event handlers, you only have the option of\r | |
642 | pre-processing the events and in order to still let the default behaviour\r | |
643 | happen you must call wxEvent::Skip() and @em not call the base class event\r | |
644 | handler directly. In fact, the event handler probably doesn't even exist in the\r | |
645 | base class as the default behaviour is often implemented in platform-specific\r | |
646 | code by the underlying toolkit or OS itself. But even if it does exist at\r | |
647 | wxWidgets level, it should never be called directly as the event handlers are\r | |
648 | not part of wxWidgets API and should never be called directly.\r | |
649 | \r | |
650 | Finally, please notice that the event handlers themselves shouldn't be virtual.\r | |
651 | They should always be non-virtual and usually private (as there is no need to\r | |
652 | make them public) methods of a wxEvtHandler-derived class.\r | |
653 | \r | |
654 | \r | |
655 | @subsection overview_events_prog User Generated Events vs Programmatically Generated Events\r | |
656 | \r | |
657 | While generically wxEvents can be generated both by user\r | |
658 | actions (e.g., resize of a wxWindow) and by calls to functions\r | |
659 | (e.g., wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived\r | |
660 | events only for the user-generated events. The only @b exceptions to this rule are:\r | |
661 | \r | |
662 | @li wxNotebook::AddPage: No event-free alternatives\r | |
663 | @li wxNotebook::AdvanceSelection: No event-free alternatives\r | |
664 | @li wxNotebook::DeletePage: No event-free alternatives\r | |
665 | @li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as\r | |
666 | wxNotebook::SetSelection is deprecated\r | |
667 | @li wxTreeCtrl::Delete: No event-free alternatives\r | |
668 | @li wxTreeCtrl::DeleteAllItems: No event-free alternatives\r | |
669 | @li wxTreeCtrl::EditLabel: No event-free alternatives\r | |
670 | @li All wxTextCtrl methods\r | |
671 | \r | |
672 | wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other\r | |
673 | functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free\r | |
674 | equivalents.\r | |
675 | \r | |
676 | \r | |
677 | \r | |
678 | @subsection overview_events_pluggable Pluggable Event Handlers\r | |
679 | \r | |
680 | <em>TODO: Probably deprecated, Connect() provides a better way to do this</em>\r | |
681 | \r | |
682 | In fact, you don't have to derive a new class from a window class\r | |
683 | if you don't want to. You can derive a new class from wxEvtHandler instead,\r | |
684 | defining the appropriate event table, and then call wxWindow::SetEventHandler\r | |
685 | (or, preferably, wxWindow::PushEventHandler) to make this\r | |
686 | event handler the object that responds to events. This way, you can avoid\r | |
687 | a lot of class derivation, and use instances of the same event handler class (but different\r | |
688 | objects as the same event handler object shouldn't be used more than once) to\r | |
689 | handle events from instances of different widget classes.\r | |
690 | \r | |
691 | If you ever have to call a window's event handler\r | |
692 | manually, use the GetEventHandler function to retrieve the window's event handler and use that\r | |
693 | to call the member function. By default, GetEventHandler returns a pointer to the window itself\r | |
694 | unless an application has redirected event handling using SetEventHandler or PushEventHandler.\r | |
695 | \r | |
696 | One use of PushEventHandler is to temporarily or permanently change the\r | |
697 | behaviour of the GUI. For example, you might want to invoke a dialog editor\r | |
698 | in your application that changes aspects of dialog boxes. You can\r | |
699 | grab all the input for an existing dialog box, and edit it 'in situ',\r | |
700 | before restoring its behaviour to normal. So even if the application\r | |
701 | has derived new classes to customize behaviour, your utility can indulge\r | |
702 | in a spot of body-snatching. It could be a useful technique for on-line\r | |
703 | tutorials, too, where you take a user through a serious of steps and\r | |
704 | don't want them to diverge from the lesson. Here, you can examine the events\r | |
705 | coming from buttons and windows, and if acceptable, pass them through to\r | |
706 | the original event handler. Use PushEventHandler/PopEventHandler\r | |
707 | to form a chain of event handlers, where each handler processes a different\r | |
708 | range of events independently from the other handlers.\r | |
709 | \r | |
710 | \r | |
711 | \r | |
712 | @subsection overview_events_winid Window Identifiers\r | |
713 | \r | |
714 | Window identifiers are integers, and are used to\r | |
715 | uniquely determine window identity in the event system (though you can use it\r | |
716 | for other purposes). In fact, identifiers do not need to be unique\r | |
717 | across your entire application as long they are unique within the\r | |
718 | particular context you're interested in, such as a frame and its children. You\r | |
719 | may use the @c wxID_OK identifier, for example, on any number of dialogs\r | |
720 | as long as you don't have several within the same dialog.\r | |
721 | \r | |
722 | If you pass @c wxID_ANY to a window constructor, an identifier will be\r | |
723 | generated for you automatically by wxWidgets. This is useful when you don't\r | |
724 | care about the exact identifier either because you're not going to process the\r | |
725 | events from the control being created or because you process the events\r | |
726 | from all controls in one place (in which case you should specify @c wxID_ANY\r | |
727 | in the event table or wxEvtHandler::Connect call\r | |
728 | as well). The automatically generated identifiers are always negative and so\r | |
729 | will never conflict with the user-specified identifiers which must be always\r | |
730 | positive.\r | |
731 | \r | |
732 | See @ref page_stdevtid for the list of standard identifiers available.\r | |
733 | You can use wxID_HIGHEST to determine the number above which it is safe to\r | |
734 | define your own identifiers. Or, you can use identifiers below wxID_LOWEST.\r | |
735 | Finally, you can allocate identifiers dynamically using wxNewId() function too.\r | |
736 | If you use wxNewId() consistently in your application, you can be sure that\r | |
737 | your identifiers don't conflict accidentally.\r | |
738 | \r | |
739 | \r | |
4475b410 VZ |
740 | @subsection overview_events_custom_generic Generic Event Table Macros\r |
741 | \r | |
742 | @beginTable\r | |
743 | @row2col{EVT_CUSTOM(event\, id\, func),\r | |
744 | Allows you to add a custom event table\r | |
745 | entry by specifying the event identifier (such as wxEVT_SIZE),\r | |
746 | the window identifier, and a member function to call.}\r | |
747 | @row2col{EVT_CUSTOM_RANGE(event\, id1\, id2\, func),\r | |
748 | The same as EVT_CUSTOM, but responds to a range of window identifiers.}\r | |
749 | @row2col{EVT_COMMAND(id\, event\, func),\r | |
750 | The same as EVT_CUSTOM, but expects a member function with a\r | |
751 | wxCommandEvent argument.}\r | |
752 | @row2col{EVT_COMMAND_RANGE(id1\, id2\, event\, func),\r | |
753 | The same as EVT_CUSTOM_RANGE, but\r | |
754 | expects a member function with a wxCommandEvent argument.}\r | |
755 | @row2col{EVT_NOTIFY(event\, id\, func),\r | |
756 | The same as EVT_CUSTOM, but\r | |
757 | expects a member function with a wxNotifyEvent argument.}\r | |
758 | @row2col{EVT_NOTIFY_RANGE(event\, id1\, id2\, func),\r | |
759 | The same as EVT_CUSTOM_RANGE, but\r | |
760 | expects a member function with a wxNotifyEvent argument.}\r | |
761 | @endTable\r | |
762 | \r | |
763 | \r | |
764 | \r | |
3e083d65 | 765 | @subsection overview_events_macros Event Handling Summary\r |
a007d249 VZ |
766 | \r |
767 | For the full list of event classes, please see the\r | |
768 | @ref group_class_events "event classes group page".\r | |
769 | \r | |
770 | \r | |
a007d249 VZ |
771 | */\r |
772 | \r |