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