]>
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 | |
10 | \r | |
11 | @page overview_eventhandling Event Handling\r | |
12 | \r | |
13 | Classes: wxEvtHandler, wxWindow, wxEvent\r | |
14 | \r | |
15 | @li @ref overview_eventhandling_introduction\r | |
16 | @li @ref overview_eventhandling_eventtables\r | |
17 | @li @ref overview_eventhandling_connect\r | |
18 | @li @ref overview_eventhandling_processing\r | |
19 | @li @ref overview_eventhandling_prog\r | |
20 | @li @ref overview_eventhandling_pluggable\r | |
21 | @li @ref overview_eventhandling_winid\r | |
22 | @li @ref overview_eventhandling_custom\r | |
23 | @li @ref overview_eventhandling_macros\r | |
24 | \r | |
25 | \r | |
26 | <hr>\r | |
27 | \r | |
28 | \r | |
29 | @section overview_eventhandling_introduction Introduction\r | |
30 | \r | |
31 | There are two principal ways to handle events in wxWidgets. One of them uses\r | |
32 | <em>event table</em> macros and allows you to define the connection between events\r | |
33 | and their handlers only statically, i.e. during program compilation. The other\r | |
34 | one uses wxEvtHandler::Connect() call and can be used to connect, and\r | |
35 | disconnect, the handlers dynamically, i.e. during run-time depending on some\r | |
36 | conditions. It also allows directly connecting the events of one object to a\r | |
37 | handler method in another object while the static event tables can only handle\r | |
38 | events in the object where they are defined so using Connect() is more flexible\r | |
39 | than using the event tables. On the other hand, event tables are more succinct\r | |
40 | and centralize all event handlers connection in one place. You can either\r | |
41 | choose a single approach which you find preferable or freely combine both\r | |
42 | methods in your program in different classes or even in one and the same class,\r | |
43 | although this is probably sufficiently confusing to be a bad idea.\r | |
44 | \r | |
45 | But before you make this choice, let us discuss these two ways in some more\r | |
46 | details: in the next section we provide a short introduction to handling the\r | |
47 | events using the event tables, please see @ref overview_eventhandling_connect\r | |
48 | for the discussion of Connect().\r | |
49 | \r | |
50 | @section overview_eventhandling_eventtables Event Handling with Event Tables\r | |
51 | \r | |
52 | To use an <em>event table</em> you must first decide in which class you wish to\r | |
53 | handle the events. The only requirement imposed by wxWidgets is that this class\r | |
54 | must derive from wxEvtHandler and so, considering that wxWindow derives from\r | |
55 | it, any classes representing windows can handle events. Simple events such as\r | |
56 | menu commands are usually processed at the level of a top-level window\r | |
57 | containing the menu, so let's suppose that you need to handle some events in @c\r | |
58 | MyFrame class deriving from wxFrame.\r | |
59 | \r | |
60 | First thing to do is to define one or more <em>event handlers</em>. They\r | |
61 | are just simple (non-virtual) methods of the class which take as a parameter a\r | |
62 | reference to an object of wxEvent-derived class and have no return value (any\r | |
63 | return information is passed via the argument, which is why it is non-const).\r | |
64 | You also need to insert a macro\r | |
65 | \r | |
66 | @code\r | |
67 | DECLARE_EVENT_TABLE()\r | |
68 | @endcode\r | |
69 | \r | |
70 | somewhere in the class declaration. It doesn't matter where does it occur but\r | |
71 | it's customary to put it at the end of it because the macro changes the access\r | |
72 | type internally and so it's safest if there is nothing that follows it. So the\r | |
73 | full class declaration might look like this:\r | |
74 | \r | |
75 | @code\r | |
76 | class MyFrame : public wxFrame\r | |
77 | {\r | |
78 | public:\r | |
79 | MyFrame(...) : wxFrame(...) { }\r | |
80 | \r | |
81 | ...\r | |
82 | \r | |
83 | protected:\r | |
84 | int m_whatever;\r | |
85 | \r | |
86 | private:\r | |
87 | // notice that as the event handlers normally are not called from outside\r | |
88 | // the class, they normally be private, in particular they don't need at\r | |
89 | // all to be public\r | |
90 | void OnExit(wxCommandEvent& event);\r | |
91 | void OnButton1(wxCommandEvent& event);\r | |
92 | void OnSize(wxSizeEvent& event);\r | |
93 | \r | |
94 | // it's common to call the event handlers OnSomething() but there is no\r | |
95 | // obligation to it, this one is an event handler too:\r | |
96 | void DoTest(wxCommandEvent& event);\r | |
97 | \r | |
98 | DECLARE_EVENT_TABLE()\r | |
99 | };\r | |
100 | @endcode\r | |
101 | \r | |
102 | Next the event table must be defined and, as any definition, it must be placed\r | |
103 | in an implementation file to tell. The event table tells wxWidgets how to map\r | |
104 | events to member functions and in our example it could look like this:\r | |
105 | \r | |
106 | @code\r | |
107 | BEGIN_EVENT_TABLE(MyFrame, wxFrame)\r | |
108 | EVT_MENU(wxID_EXIT, MyFrame::OnExit)\r | |
109 | EVT_MENU(DO_TEST, MyFrame::DoTest)\r | |
110 | EVT_SIZE(MyFrame::OnSize)\r | |
111 | EVT_BUTTON(BUTTON1, MyFrame::OnButton1)\r | |
112 | END_EVENT_TABLE()\r | |
113 | @endcode\r | |
114 | \r | |
115 | Notice that you must mention a method you want to use for the event handling in\r | |
116 | the event table definition, just defining it in MyFrame class is @e not enough.\r | |
117 | \r | |
118 | Let us now look at the details of this definition: the first line means that we\r | |
119 | are defining the event table for MyFrame class and that its base class is\r | |
120 | wxFrame, so events not processed by MyFrame will, by default, be handled to\r | |
121 | wxFrame. The next four lines define connections of individual events to their\r | |
122 | handlers: the first two of them map menu commands from the items with the\r | |
123 | identifiers specified as the first macro parameter to two different member\r | |
124 | functions. In the next one, @c EVT_SIZE means that any changes in the size of\r | |
125 | the frame will result in calling OnSize() method. Note that this macro doesn't\r | |
126 | need a window identifier, since normally you are only interested in the current\r | |
127 | window's size events.\r | |
128 | \r | |
129 | The EVT_BUTTON macro demonstrates that the originating event does not have to\r | |
130 | come from the window class implementing the event table -- if the event source\r | |
131 | is a button within a panel within a frame, this will still work, because event\r | |
132 | tables are searched up through the hierarchy of windows for the command events\r | |
133 | (but only command events, so you can't catch mouse move events in a child\r | |
134 | control in the parent window in the same way because wxMouseEvent doesn't\r | |
135 | derive from wxCommandEvent, see below for how you can do it). In this case, the\r | |
136 | button's event table will be searched, then the parent panel's, then the\r | |
137 | frame's.\r | |
138 | \r | |
139 | Finally, you need to implement the event handlers. As mentioned before, all\r | |
140 | event handlers take a wxEvent-derived argument whose exact class differs\r | |
141 | according to the type of event and the class of the originating window. For\r | |
142 | size events, wxSizeEvent is used. For menu commands and most control commands\r | |
143 | (such as button presses), wxCommandEvent is used. And when controls get more\r | |
144 | complicated, more specific wxCommandEvent-derived event classes providing\r | |
145 | additional control-specific information can be used, such as wxTreeEvent for\r | |
146 | events from wxTreeCtrl windows.\r | |
147 | \r | |
148 | In the simplest possible case an event handler may not use the @c event\r | |
149 | parameter at all, e.g.\r | |
150 | \r | |
151 | @code\r | |
152 | void MyFrame::OnExit(wxCommandEvent&)\r | |
153 | {\r | |
154 | // when the user selects "Exit" from the menu we should close\r | |
155 | Close(true);\r | |
156 | }\r | |
157 | @endcode\r | |
158 | \r | |
159 | In other cases you may need some information carried by the @c event argument,\r | |
160 | as in:\r | |
161 | \r | |
162 | @code\r | |
163 | void MyFrame::OnSize(wxSizeEvent& event)\r | |
164 | {\r | |
165 | wxSize size = event.GetSize();\r | |
166 | \r | |
167 | ... update the frame using the new size ...\r | |
168 | }\r | |
169 | @endcode\r | |
170 | \r | |
171 | You will find the details about the event table macros and the corresponding\r | |
172 | wxEvent-derived classes in the discussion of each control generating these\r | |
173 | events.\r | |
174 | \r | |
175 | \r | |
176 | @section overview_eventhandling_connect Dynamic Event Handling\r | |
177 | \r | |
178 | As with the event tables, you need to decide in which class do you intend to\r | |
179 | handle the events first and, also as before, this class must still derive from\r | |
180 | wxEvtHandler (usually indirectly via wxWindow), see the declaration of MyFrame\r | |
181 | in the previous section. However the similarities end here and both the syntax\r | |
182 | and the possibilities of this way of handling events in this way are rather\r | |
183 | different.\r | |
184 | \r | |
185 | Let us start by looking at the syntax: the first obvious difference is that you\r | |
186 | don't need to use neither @c DECLARE_EVENT_TABLE() nor @c BEGIN_EVENT_TABLE and \r | |
187 | associated macros any more. Instead, in any place in your code, but usually in\r | |
188 | the code of the class defining the handlers itself (and definitely not in the\r | |
189 | global scope as with the event tables), you should call its Connect() method\r | |
190 | like this:\r | |
191 | \r | |
192 | @code\r | |
193 | MyFrame::MyFrame(...)\r | |
194 | {\r | |
195 | Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,\r | |
196 | wxCommandEventHandler(MyFrame::OnExit));\r | |
197 | }\r | |
198 | @endcode\r | |
199 | \r | |
200 | This class should be self-explanatory except for wxCommandEventHandler part:\r | |
201 | this is a macro which ensures that the method is of correct type by using\r | |
202 | static_cast in the same way as event table macros do it inside them.\r | |
203 | \r | |
204 | Now let us describe the semantic differences:\r | |
205 | <ul>\r | |
206 | <li>\r | |
207 | Event handlers can be connected at any moment, e.g. it's possible to do\r | |
208 | some initialization first and only connect the handlers if and when it\r | |
209 | succeeds. This can avoid the need to test that the object was properly\r | |
210 | initialized in the event handlers themselves: with Connect() they\r | |
211 | simply won't be called at all if it wasn't.\r | |
212 | </li>\r | |
213 | \r | |
214 | <li>\r | |
215 | As a slight extension of the above, the handlers can also be\r | |
216 | Disconnect()-ed at any time. And maybe later reconnected again. Of\r | |
217 | course, it's also possible to emulate this behaviour with the classic\r | |
218 | static (i.e. connected via event tables) handlers by using an internal\r | |
219 | flag indicating whether the handler is currently enabled and returning\r | |
220 | from it if it isn't, but using dynamically connected handlers requires\r | |
221 | less code and is also usually more clear.\r | |
222 | </li>\r | |
223 | \r | |
224 | <li>\r | |
225 | Also notice that you must derive a class inherited from, say,\r | |
226 | wxTextCtrl even if you don't want to modify the control behaviour at\r | |
227 | all but just want to handle some of its events. This is especially\r | |
228 | inconvenient when the control is loaded from the XRC. Connecting the\r | |
229 | event handler dynamically bypasses the need for this unwanted\r | |
230 | sub-classing.\r | |
231 | </li>\r | |
232 | \r | |
233 | <li>\r | |
234 | Last but very, very far from least is the possibility to connect an\r | |
235 | event of some object to a method of another object. This is impossible\r | |
236 | to do with event tables because there is no possibility to specify the\r | |
237 | object to dispatch the event to so it necessarily needs to be sent to\r | |
238 | the same object which generated the event. Not so with Connect() which\r | |
239 | has an optional @c eventSink parameter which can be used to specify the\r | |
240 | object which will handle the event. Of course, in this case the method\r | |
241 | being connected must belong to the class which is the type of the\r | |
242 | @c eventSink object! To give a quick example, people often want to catch\r | |
243 | mouse movement events happening when the mouse is in one of the frame\r | |
244 | children in the frame itself. Doing it in a naive way doesn't work:\r | |
245 | <ul>\r | |
246 | <li>\r | |
247 | A @c EVT_LEAVE_WINDOW(MyFrame::OnMouseLeave) line in the frame\r | |
248 | event table has no effect as mouse move (including entering and\r | |
249 | leaving) events are not propagated upwards to the parent window\r | |
250 | (at least not by default).\r | |
251 | </li>\r | |
252 | \r | |
253 | <li>\r | |
254 | Putting the same line in a child event table will crash during\r | |
255 | run-time because the MyFrame method will be called on a wrong\r | |
256 | object -- it's easy to convince oneself that the only object\r | |
257 | which can be used here is the pointer to the child, as\r | |
258 | wxWidgets has nothing else. But calling a frame method with the\r | |
259 | child window pointer instead of the pointer to the frame is, of\r | |
260 | course, disastrous.\r | |
261 | </li>\r | |
262 | </ul>\r | |
263 | \r | |
264 | However writing\r | |
265 | @code\r | |
266 | MyFrame::MyFrame(...)\r | |
267 | {\r | |
268 | m_child->Connect(wxID_ANY, wxEVT_LEAVE_WINDOW,\r | |
269 | wxMouseEventHandler(MyFrame::OnMouseLeave),\r | |
270 | NULL, // unused extra data parameter\r | |
271 | this); // this indicates the object to connect to\r | |
272 | }\r | |
273 | @endcode\r | |
274 | will work exactly as expected. Note that you can get the object which\r | |
275 | generated the event -- and which is not the same as the frame -- via\r | |
276 | wxEvent::GetEventObject() method of @c event argument passed to the\r | |
277 | event handler.\r | |
278 | <li>\r | |
279 | </ul>\r | |
280 | \r | |
281 | To summarize, using Connect() requires slightly more typing but is much more\r | |
282 | flexible than using static event tables so don't hesitate to use it when you\r | |
283 | need this extra power. On the other hand, event tables are still perfectly fine\r | |
284 | in simple situations where this extra flexibility is not needed.\r | |
285 | \r | |
286 | \r | |
287 | @section overview_eventhandling_processing How Events are Processed\r | |
288 | \r | |
289 | When an event is received from the windowing system, wxWidgets calls\r | |
290 | wxEvtHandler::ProcessEvent on the first\r | |
291 | event handler object belonging to the window generating the event.\r | |
292 | \r | |
293 | It may be noted that wxWidgets' event processing system implements something\r | |
294 | very close to virtual methods in normal C++, i.e. it is possible to alter\r | |
295 | the behaviour of a class by overriding its event handling functions. In\r | |
296 | many cases this works even for changing the behaviour of native controls.\r | |
297 | \r | |
298 | For example it is possible to filter out a number of key events sent by the\r | |
299 | system to a native text control by overriding wxTextCtrl and defining a\r | |
300 | handler for key events using EVT_KEY_DOWN. This would indeed prevent\r | |
301 | any key events from being sent to the native control - which might not be\r | |
302 | what is desired. In this case the event handler function has to call Skip()\r | |
303 | so as to indicate that the search for the event handler should continue.\r | |
304 | \r | |
305 | To summarize, instead of explicitly calling the base class version as you\r | |
306 | would have done with C++ virtual functions (i.e. @e wxTextCtrl::OnChar()),\r | |
307 | you should instead call wxEvent::Skip.\r | |
308 | \r | |
309 | In practice, this would look like this if the derived text control only\r | |
310 | accepts 'a' to 'z' and 'A' to 'Z':\r | |
311 | \r | |
312 | @code\r | |
313 | void MyTextCtrl::OnChar(wxKeyEvent& event)\r | |
314 | {\r | |
315 | if ( isalpha( event.KeyCode() ) )\r | |
316 | {\r | |
317 | // key code is within legal range. we call event.Skip() so the\r | |
318 | // event can be processed either in the base wxWidgets class\r | |
319 | // or the native control.\r | |
320 | \r | |
321 | event.Skip();\r | |
322 | }\r | |
323 | else\r | |
324 | {\r | |
325 | // illegal key hit. we don't call event.Skip() so the\r | |
326 | // event is not processed anywhere else.\r | |
327 | \r | |
328 | wxBell();\r | |
329 | }\r | |
330 | }\r | |
331 | @endcode\r | |
332 | \r | |
333 | The normal order of event table searching by ProcessEvent is as follows:\r | |
334 | <ol>\r | |
335 | <li> If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled)\r | |
336 | the function skips to step (6).\r | |
337 | <li> If the object is a wxWindow, @b ProcessEvent is recursively called on the window's\r | |
338 | wxValidator. If this returns @true, the function exits.\r | |
339 | <li> @b SearchEventTable is called for this event handler. If this fails, the base\r | |
340 | class table is tried, and so on until no more tables exist or an appropriate\r | |
341 | function was found, in which case the function exits.\r | |
342 | <li> The search is applied down the entire chain of event handlers (usually the chain has\r | |
343 | a length of one). If this succeeds, the function exits.\r | |
344 | <li> If the object is a wxWindow and the event is set to set to propagate (in the library only\r | |
345 | wxCommandEvent based events are set to propagate), @b ProcessEvent is recursively applied\r | |
346 | to the parent window's event handler. If this returns @true, the function exits.\r | |
347 | <li> Finally, @b ProcessEvent is called on the wxApp object.\r | |
348 | </ol>\r | |
349 | <b>Pay close attention to Step 5</b>. People often overlook or get\r | |
350 | confused by this powerful feature of the wxWidgets event processing\r | |
351 | system. To put it a different way, events set to propagate\r | |
352 | (see wxEvent::ShouldPropagate)\r | |
353 | (most likely derived either directly or indirectly from wxCommandEvent)\r | |
354 | will travel up the containment hierarchy from child to parent until the\r | |
355 | maximal propagation level is reached or an event handler is found that\r | |
356 | doesn't call @c event.Skip().\r | |
357 | \r | |
358 | Finally, there is another additional complication (which, in fact, simplifies\r | |
359 | life of wxWidgets programmers significantly): when propagating the command\r | |
360 | events upwards to the parent window, the event propagation stops when it\r | |
361 | reaches the parent dialog, if any. This means that you don't risk to get\r | |
362 | unexpected events from the dialog controls (which might be left unprocessed by\r | |
363 | the dialog itself because it doesn't care about them) when a modal dialog is\r | |
364 | popped up. The events do propagate beyond the frames, however. The rationale\r | |
365 | for this choice is that there are only a few frames in a typical application\r | |
366 | and their parent-child relation are well understood by the programmer while it\r | |
367 | may be very difficult, if not impossible, to track down all the dialogs which\r | |
368 | may be popped up in a complex program (remember that some are created\r | |
369 | automatically by wxWidgets). If you need to specify a different behaviour for\r | |
370 | some reason, you can use wxWindow::SetExtraStyle(wxWS_EX_BLOCK_EVENTS)\r | |
371 | explicitly to prevent the events from being propagated beyond the given window\r | |
372 | or unset this flag for the dialogs which have it on by default.\r | |
373 | \r | |
374 | Typically events that deal with a window as a window (size, motion,\r | |
375 | paint, mouse, keyboard, etc.) are sent only to the window. Events\r | |
376 | that have a higher level of meaning and/or are generated by the window\r | |
377 | itself, (button click, menu select, tree expand, etc.) are command\r | |
378 | events and are sent up to the parent to see if it is interested in the event.\r | |
379 | \r | |
380 | Note that your application may wish to override ProcessEvent to redirect processing of\r | |
381 | events. This is done in the document/view framework, for example, to allow event handlers\r | |
382 | to be defined in the document or view. To test for command events (which will probably\r | |
383 | be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for efficiency,\r | |
384 | instead of using the slower run-time type system.\r | |
385 | \r | |
386 | As mentioned above, only command events are recursively applied to the parents event\r | |
387 | handler in the library itself. As this quite often causes confusion for users,\r | |
388 | here is a list of system events which will NOT get sent to the parent's event handler:\r | |
389 | \r | |
390 | @li wxEvent: The event base class\r | |
391 | @li wxActivateEvent: A window or application activation event\r | |
392 | @li wxCloseEvent: A close window or end session event\r | |
393 | @li wxEraseEvent: An erase background event\r | |
394 | @li wxFocusEvent: A window focus event\r | |
395 | @li wxKeyEvent: A keypress event\r | |
396 | @li wxIdleEvent: An idle event\r | |
397 | @li wxInitDialogEvent: A dialog initialisation event\r | |
398 | @li wxJoystickEvent: A joystick event\r | |
399 | @li wxMenuEvent: A menu event\r | |
400 | @li wxMouseEvent: A mouse event\r | |
401 | @li wxMoveEvent: A move event\r | |
402 | @li wxPaintEvent: A paint event\r | |
403 | @li wxQueryLayoutInfoEvent: Used to query layout information\r | |
404 | @li wxSetCursorEvent: Used for special cursor processing based on current mouse position\r | |
405 | @li wxSizeEvent: A size event\r | |
406 | @li wxScrollWinEvent: A scroll event sent by a scrolled window (not a scroll bar)\r | |
407 | @li wxSysColourChangedEvent: A system colour change event\r | |
408 | \r | |
409 | In some cases, it might be desired by the programmer to get a certain number\r | |
410 | of system events in a parent window, for example all key events sent to, but not\r | |
411 | used by, the native controls in a dialog. In this case, a special event handler\r | |
412 | will have to be written that will override ProcessEvent() in order to pass\r | |
413 | all events (or any selection of them) to the parent window.\r | |
414 | \r | |
415 | \r | |
416 | @section overview_eventhandling_prog User Generated Events vs Programmatically Generated Events\r | |
417 | \r | |
418 | While generically wxEvents can be generated both by user\r | |
419 | actions (e.g. resize of a wxWindow) and by calls to functions\r | |
420 | (e.g. wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived\r | |
421 | events only for the user-generated events. The only @b exceptions to this rule are:\r | |
422 | \r | |
423 | @li wxNotebook::AddPage: No event-free alternatives\r | |
424 | @li wxNotebook::AdvanceSelection: No event-free alternatives\r | |
425 | @li wxNotebook::DeletePage: No event-free alternatives\r | |
426 | @li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as\r | |
427 | wxNotebook::SetSelection is deprecated\r | |
428 | @li wxTreeCtrl::Delete: No event-free alternatives\r | |
429 | @li wxTreeCtrl::DeleteAllItems: No event-free alternatives\r | |
430 | @li wxTreeCtrl::EditLabel: No event-free alternatives\r | |
431 | @li All wxTextCtrl methods\r | |
432 | \r | |
433 | wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other\r | |
434 | functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free\r | |
435 | equivalents.\r | |
436 | \r | |
437 | \r | |
438 | \r | |
439 | @section overview_eventhandling_pluggable Pluggable Event Handlers\r | |
440 | \r | |
441 | In fact, you don't have to derive a new class from a window class\r | |
442 | if you don't want to. You can derive a new class from wxEvtHandler instead,\r | |
443 | defining the appropriate event table, and then call wxWindow::SetEventHandler\r | |
444 | (or, preferably, wxWindow::PushEventHandler) to make this\r | |
445 | event handler the object that responds to events. This way, you can avoid\r | |
446 | a lot of class derivation, and use instances of the same event handler class (but different\r | |
447 | objects as the same event handler object shouldn't be used more than once) to\r | |
448 | handle events from instances of different widget classes.\r | |
449 | \r | |
450 | If you ever have to call a window's event handler\r | |
451 | manually, use the GetEventHandler function to retrieve the window's event handler and use that\r | |
452 | to call the member function. By default, GetEventHandler returns a pointer to the window itself\r | |
453 | unless an application has redirected event handling using SetEventHandler or PushEventHandler.\r | |
454 | \r | |
455 | One use of PushEventHandler is to temporarily or permanently change the\r | |
456 | behaviour of the GUI. For example, you might want to invoke a dialog editor\r | |
457 | in your application that changes aspects of dialog boxes. You can\r | |
458 | grab all the input for an existing dialog box, and edit it 'in situ',\r | |
459 | before restoring its behaviour to normal. So even if the application\r | |
460 | has derived new classes to customize behaviour, your utility can indulge\r | |
461 | in a spot of body-snatching. It could be a useful technique for on-line\r | |
462 | tutorials, too, where you take a user through a serious of steps and\r | |
463 | don't want them to diverge from the lesson. Here, you can examine the events\r | |
464 | coming from buttons and windows, and if acceptable, pass them through to\r | |
465 | the original event handler. Use PushEventHandler/PopEventHandler\r | |
466 | to form a chain of event handlers, where each handler processes a different\r | |
467 | range of events independently from the other handlers.\r | |
468 | \r | |
469 | \r | |
470 | \r | |
471 | @section overview_eventhandling_winid Window Identifiers\r | |
472 | \r | |
473 | Window identifiers are integers, and are used to\r | |
474 | uniquely determine window identity in the event system (though you can use it\r | |
475 | for other purposes). In fact, identifiers do not need to be unique\r | |
476 | across your entire application just so long as they are unique within a\r | |
477 | particular context you're interested in, such as a frame and its children. You\r | |
478 | may use the @c wxID_OK identifier, for example, on any number of dialogs so\r | |
479 | long as you don't have several within the same dialog.\r | |
480 | \r | |
481 | If you pass @c wxID_ANY to a window constructor, an identifier will be\r | |
482 | generated for you automatically by wxWidgets. This is useful when you don't\r | |
483 | care about the exact identifier either because you're not going to process the\r | |
484 | events from the control being created at all or because you process the events\r | |
485 | from all controls in one place (in which case you should specify @c wxID_ANY\r | |
486 | in the event table or wxEvtHandler::Connect call\r | |
487 | as well. The automatically generated identifiers are always negative and so\r | |
488 | will never conflict with the user-specified identifiers which must be always\r | |
489 | positive.\r | |
490 | \r | |
491 | See @ref page_stdevtid for the list of standard identifiers available.\r | |
492 | You can use wxID_HIGHEST to determine the number above which it is safe to\r | |
493 | define your own identifiers. Or, you can use identifiers below wxID_LOWEST.\r | |
494 | Finally, you can allocate identifiers dynamically using wxNewId() function to.\r | |
495 | If you use wxNewId() consistently in your application, you can be sure that\r | |
496 | the your identifiers don't conflict accidentally.\r | |
497 | \r | |
498 | \r | |
499 | @section overview_eventhandling_custom Custom Event Summary\r | |
500 | \r | |
501 | @subsection overview_eventhandling_custom_general General approach\r | |
502 | \r | |
503 | Since version 2.2.x of wxWidgets, each event type is identified by ID which\r | |
504 | is given to the event type @e at runtime which makes it possible to add\r | |
505 | new event types to the library or application without risking ID clashes\r | |
506 | (two different event types mistakingly getting the same event ID). This\r | |
507 | event type ID is stored in a struct of type @b const wxEventType.\r | |
508 | \r | |
509 | In order to define a new event type, there are principally two choices.\r | |
510 | One is to define a entirely new event class (typically deriving from\r | |
511 | wxEvent or wxCommandEvent.\r | |
512 | \r | |
513 | The other is to use the existing event classes and give them an new event\r | |
514 | type. You'll have to define and declare a new event type using either way,\r | |
515 | and this is done using the following macros:\r | |
516 | \r | |
517 | @code\r | |
518 | // in the header of the source file\r | |
519 | BEGIN_DECLARE_EVENT_TYPES()\r | |
520 | DECLARE_EVENT_TYPE(name, value)\r | |
521 | END_DECLARE_EVENT_TYPES()\r | |
522 | \r | |
523 | // in the implementation\r | |
524 | DEFINE_EVENT_TYPE(name)\r | |
525 | @endcode\r | |
526 | \r | |
527 | You can ignore the @e value parameter of the DECLARE_EVENT_TYPE macro\r | |
528 | since it is used only for backwards compatibility with wxWidgets 2.0.x based\r | |
529 | applications where you have to give the event type ID an explicit value.\r | |
530 | See also the @ref page_samples_event for an example of code\r | |
531 | defining and working with the custom event types.\r | |
532 | \r | |
533 | \r | |
534 | @subsection overview_eventhandling_custom_existing Using Existing Event Classes\r | |
535 | \r | |
536 | If you just want to use a wxCommandEvent with\r | |
537 | a new event type, you can then use one of the generic event table macros\r | |
538 | listed below, without having to define a new macro yourself. This also\r | |
539 | has the advantage that you won't have to define a new wxEvent::Clone()\r | |
540 | method for posting events between threads etc. This could look like this\r | |
541 | in your code:\r | |
542 | \r | |
543 | @code\r | |
544 | DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1)\r | |
545 | DEFINE_EVENT_TYPE(wxEVT_MY_EVENT)\r | |
546 | \r | |
547 | // user code intercepting the event\r | |
548 | \r | |
549 | BEGIN_EVENT_TABLE(MyFrame, wxFrame)\r | |
550 | EVT_MENU (wxID_EXIT, MyFrame::OnExit)\r | |
551 | // ....\r | |
552 | EVT_COMMAND (ID_MY_WINDOW, wxEVT_MY_EVENT, MyFrame::OnMyEvent)\r | |
553 | END_EVENT_TABLE()\r | |
554 | \r | |
555 | void MyFrame::OnMyEvent( wxCommandEvent )\r | |
556 | {\r | |
557 | // do something\r | |
558 | wxString text = event.GetText();\r | |
559 | }\r | |
560 | \r | |
561 | \r | |
562 | // user code sending the event\r | |
563 | \r | |
564 | void MyWindow::SendEvent()\r | |
565 | {\r | |
566 | wxCommandEvent event( wxEVT_MY_EVENT, GetId() );\r | |
567 | event.SetEventObject( this );\r | |
568 | // Give it some contents\r | |
569 | event.SetText( wxT("Hallo") );\r | |
570 | // Send it\r | |
571 | GetEventHandler()->ProcessEvent( event );\r | |
572 | }\r | |
573 | @endcode\r | |
574 | \r | |
575 | \r | |
576 | @subsection overview_eventhandling_custom_generic Generic Event Table Macros\r | |
577 | \r | |
578 | @beginTable\r | |
579 | @row2col{EVT_CUSTOM(event\, id\, func),\r | |
580 | Allows you to add a custom event table\r | |
581 | entry by specifying the event identifier (such as wxEVT_SIZE),\r | |
582 | the window identifier, and a member function to call.}\r | |
583 | @row2col{EVT_CUSTOM_RANGE(event\, id1\, id2\, func),\r | |
584 | The same as EVT_CUSTOM, but responds to a range of window identifiers.}\r | |
585 | @row2col{EVT_COMMAND(id\, event\, func),\r | |
586 | The same as EVT_CUSTOM, but expects a member function with a\r | |
587 | wxCommandEvent argument.}\r | |
588 | @row2col{EVT_COMMAND_RANGE(id1\, id2\, event\, func),\r | |
589 | The same as EVT_CUSTOM_RANGE, but\r | |
590 | expects a member function with a wxCommandEvent argument.}\r | |
591 | @row2col{EVT_NOTIFY(event\, id\, func),\r | |
592 | The same as EVT_CUSTOM, but\r | |
593 | expects a member function with a wxNotifyEvent argument.}\r | |
594 | @row2col{EVT_NOTIFY_RANGE(event\, id1\, id2\, func),\r | |
595 | The same as EVT_CUSTOM_RANGE, but\r | |
596 | expects a member function with a wxNotifyEvent argument.}\r | |
597 | @endTable\r | |
598 | \r | |
599 | \r | |
600 | @subsection overview_eventhandling_custom_ownclass Defining Your Own Event Class\r | |
601 | \r | |
602 | Under certain circumstances, it will be required to define your own event\r | |
603 | class e.g. for sending more complex data from one place to another. Apart\r | |
604 | from defining your event class, you will also need to define your own\r | |
605 | event table macro (which is quite long). Watch out to put in enough\r | |
606 | casts to the inherited event function. Here is an example:\r | |
607 | \r | |
608 | @code\r | |
609 | // code defining event\r | |
610 | \r | |
611 | class wxPlotEvent: public wxNotifyEvent\r | |
612 | {\r | |
613 | public:\r | |
614 | wxPlotEvent( wxEventType commandType = wxEVT_NULL, int id = 0 );\r | |
615 | \r | |
616 | // accessors\r | |
617 | wxPlotCurve *GetCurve()\r | |
618 | { return m_curve; }\r | |
619 | \r | |
620 | // required for sending with wxPostEvent()\r | |
621 | virtual wxEvent *Clone() const;\r | |
622 | \r | |
623 | private:\r | |
624 | wxPlotCurve *m_curve;\r | |
625 | };\r | |
626 | \r | |
627 | DECLARE_EVENT_TYPE( wxEVT_PLOT_ACTION, -1 )\r | |
628 | \r | |
629 | typedef void (wxEvtHandler::*wxPlotEventFunction)(wxPlotEvent&);\r | |
630 | \r | |
631 | #define EVT_PLOT(id, fn) \\r | |
632 | DECLARE_EVENT_TABLE_ENTRY( wxEVT_PLOT_ACTION, id, -1, \\r | |
633 | (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxNotifyEventFunction) \\r | |
634 | wxStaticCastEvent( wxPlotEventFunction, &fn ), (wxObject *) NULL ),\r | |
635 | \r | |
636 | \r | |
637 | // code implementing the event type and the event class\r | |
638 | \r | |
639 | DEFINE_EVENT_TYPE( wxEVT_PLOT_ACTION )\r | |
640 | \r | |
641 | wxPlotEvent::wxPlotEvent( ...\r | |
642 | \r | |
643 | \r | |
644 | // user code intercepting the event\r | |
645 | \r | |
646 | BEGIN_EVENT_TABLE(MyFrame, wxFrame)\r | |
647 | EVT_PLOT (ID_MY_WINDOW, MyFrame::OnPlot)\r | |
648 | END_EVENT_TABLE()\r | |
649 | \r | |
650 | void MyFrame::OnPlot( wxPlotEvent &event )\r | |
651 | {\r | |
652 | wxPlotCurve *curve = event.GetCurve();\r | |
653 | }\r | |
654 | \r | |
655 | \r | |
656 | // user code sending the event\r | |
657 | \r | |
658 | void MyWindow::SendEvent()\r | |
659 | {\r | |
660 | wxPlotEvent event( wxEVT_PLOT_ACTION, GetId() );\r | |
661 | event.SetEventObject( this );\r | |
662 | event.SetCurve( m_curve );\r | |
663 | GetEventHandler()->ProcessEvent( event );\r | |
664 | }\r | |
665 | @endcode\r | |
666 | \r | |
667 | \r | |
668 | @section overview_eventhandling_macros Event Handling Summary\r | |
669 | \r | |
670 | For the full list of event classes, please see the\r | |
671 | @ref group_class_events "event classes group page".\r | |
672 | \r | |
673 | \r | |
674 | @todo for all controls state clearly when calling a member function results in an \r | |
675 | event being generated and when it doesn't (possibly updating also the \r | |
676 | 'Events generated by the user vs programmatically generated events' paragraph \r | |
677 | of the 'Event handling overview' with the list of the functions which break \r | |
678 | that rule).\r | |
679 | \r | |
680 | */\r | |
681 | \r |