X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/722f74cec895bbc284ba7b7a7213ee5cf2a1ab95..fbfe2d4e7caa118e1b609151bc72e7e5c7ac0f32:/docs/doxygen/overviews/eventhandling.h diff --git a/docs/doxygen/overviews/eventhandling.h b/docs/doxygen/overviews/eventhandling.h index 9f94ba6c43..c656c1bc11 100644 --- a/docs/doxygen/overviews/eventhandling.h +++ b/docs/doxygen/overviews/eventhandling.h @@ -1,681 +1,681 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: eventhandling.h -// Purpose: topic overview -// Author: wxWidgets team -// RCS-ID: $Id$ -// Licence: wxWindows license -///////////////////////////////////////////////////////////////////////////// - -/** - -@page overview_eventhandling Event Handling - -Classes: wxEvtHandler, wxWindow, wxEvent - -@li @ref overview_eventhandling_introduction -@li @ref overview_eventhandling_eventtables -@li @ref overview_eventhandling_connect -@li @ref overview_eventhandling_processing -@li @ref overview_eventhandling_prog -@li @ref overview_eventhandling_pluggable -@li @ref overview_eventhandling_winid -@li @ref overview_eventhandling_custom -@li @ref overview_eventhandling_macros - - -
- - -@section overview_eventhandling_introduction Introduction - -There are two principal ways to handle events in wxWidgets. One of them uses -event table macros and allows to define the connection between events -and their handlers only statically, i.e. during program compilation. The other -one uses wxEvtHandler::Connect() call and can be used to connect, and -disconnect, the handlers dynamically, i.e. during run-time depending on some -conditions. It also allows directly connecting the events of one object to a -handler method in another object while the static event tables can only handle -events in the object where they are defined so using Connect() is more flexible -than using the event tables. On the other hand, event tables are more succinct -and centralize all event handlers connection in one place. You can either -choose a single approach which you find preferable or freely combine both -methods in your program in different classes or even in one and the same class, -although this is probably sufficiently confusing to be a bad idea. - -But before you make this choice, let us discuss these two ways in some more -details: in the next section we provide a short introduction to handling the -events using the event tables, please see @ref overview_eventhandling_connect -for the discussion of Connect(). - -@section overview_eventhandling_eventtables Event Handling with Event Tables - -To use an event table you must first decide in which class you wish to -handle the events. The only requirement imposed by wxWidgets is that this class -must derive from wxEvtHandler and so, considering that wxWindow derives from -it, any classes representing windows can handle events. Simple events such as -menu commands are usually processed at the level of a top-level window -containing the menu, so let's suppose that you need to handle some events in @c -MyFrame class deriving from wxFrame. - -First thing to do is to define one or more event handlers. They -are just simple (non-virtual) methods of the class which take as a parameter a -reference to an object of wxEvent-derived class and have no return value (any -return information is passed via the argument, which is why it is non-const). -You also need to insert a macro - -@code -DECLARE_EVENT_TABLE() -@endcode - -somewhere in the class declaration. It doesn't matter where does it occur but -it's customary to put it at the end of it because the macro changes the access -type internally and so it's safest if there is nothing that follows it. So the -full class declaration might look like this: - -@code -class MyFrame : public wxFrame -{ -public: - MyFrame(...) : wxFrame(...) { } - - ... - -protected: - int m_whatever; - -private: - // notice that as the event handlers normally are not called from outside - // the class, they normally be private, in particular they don't need at - // all to be public - void OnExit(wxCommandEvent& event); - void OnButton1(wxCommandEvent& event); - void OnSize(wxSizeEvent& event); - - // it's common to call the event handlers OnSomething() but there is no - // obligation to it, this one is an event handler too: - void DoTest(wxCommandEvent& event); - - DECLARE_EVENT_TABLE() -}; -@endcode - -Next the event table must be defined and, as any definition, it must be placed -in an implementation file to tell. The event table tells wxWidgets how to map -events to member functions and in our example it could look like this: - -@code -BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(wxID_EXIT, MyFrame::OnExit) - EVT_MENU(DO_TEST, MyFrame::DoTest) - EVT_SIZE(MyFrame::OnSize) - EVT_BUTTON(BUTTON1, MyFrame::OnButton1) -END_EVENT_TABLE() -@endcode - -Notice that you must mention a method you want to use for the event handling in -the event table definition, just defining it in MyFrame class is @e not enough. - -Let us now look at the details of this definition: the first line means that we -are defining the event table for MyFrame class and that its base class is -wxFrame, so events not processed by MyFrame will, by default, be handled to -wxFrame. The next four lines define connections of individual events to their -handlers: the first two of them map menu commands from the items with the -identifiers specified as the first macro parameter to two different member -functions. In the next one, @c EVT_SIZE means that any changes in the size of -the frame will result in calling OnSize() method. Note that this macro doesn't -need a window identifier, since normally you are only interested in the current -window's size events. - -The EVT_BUTTON macro demonstrates that the originating event does not have to -come from the window class implementing the event table -- if the event source -is a button within a panel within a frame, this will still work, because event -tables are searched up through the hierarchy of windows for the command events -(but only command events, so you can't catch mouse move events in a child -control in the parent window in the same way because wxMouseEvent doesn't -derive from wxCommandEvent, see below for how you can do it). In this case, the -button's event table will be searched, then the parent panel's, then the -frame's. - -Finally, you need to implement the event handlers. As mentioned before, all -event handlers take a wxEvent-derived argument whose exact class differs -according to the type of event and the class of the originating window. For -size events, wxSizeEvent is used. For menu commands and most control commands -(such as button presses), wxCommandEvent is used. And when controls get more -complicated, more specific wxCommandEvent-derived event classes providing -additional control-specific information can be used, such as wxTreeEvent for -events from wxTreeCtrl windows. - -In the simplest possible case an event handler may not use the @c event -parameter at all, e.g. - -@code -void MyFrame::OnExit(wxCommandEvent&) -{ - // when the user selects "Exit" from the menu we should close - Close(true); -} -@endcode - -In other cases you may need some information carried by the @c event argument, -as in: - -@code -void MyFrame::OnSize(wxSizeEvent& event) -{ - wxSize size = event.GetSize(); - - ... update the frame using the new size ... -} -@endcode - -You will find the details about the event table macros and the corresponding -wxEvent-derived classes in the discussion of each control generating these -events. - - -@section overview_eventhandling_connect Dynamic Event Handling - -As with the event tables, you need to decide in which class do you intend to -handle the events first and, also as before, this class must still derive from -wxEvtHandler (usually indirectly via wxWindow), see the declaration of MyFrame -in the previous section. However the similarities end here and both the syntax -and the possibilities of this way of handling events in this way are rather -different. - -Let us start by looking at the syntax: the first obvious difference is that you -don't need to use neither @c DECLARE_EVENT_TABLE() nor @c BEGIN_EVENT_TABLE and -associated macros any more. Instead, in any place in your code, but usually in -the code of the class defining the handlers itself (and definitely not in the -global scope as with the event tables), you should call its Connect() method -like this: - -@code -MyFrame::MyFrame(...) -{ - Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, - wxCommandEventHandler(MyFrame::OnExit)); -} -@endcode - -This class should be self-explanatory except for wxCommandEventHandler part: -this is a macro which ensures that the method is of correct type by using -static_cast in the same way as event table macros do it inside them. - -Now let us describe the semantic differences: - - -To summarize, using Connect() requires slightly more typing but is much more -flexible than using static event tables so don't hesitate to use it when you -need this extra power. On the other hand, event tables are still perfectly fine -in simple situations where this extra flexibility is not needed. - - -@section overview_eventhandling_processing How Events are Processed - -When an event is received from the windowing system, wxWidgets calls -wxEvtHandler::ProcessEvent on the first -event handler object belonging to the window generating the event. - -It may be noted that wxWidgets' event processing system implements something -very close to virtual methods in normal C++, i.e. it is possible to alter -the behaviour of a class by overriding its event handling functions. In -many cases this works even for changing the behaviour of native controls. - -For example it is possible to filter out a number of key events sent by the -system to a native text control by overriding wxTextCtrl and defining a -handler for key events using EVT_KEY_DOWN. This would indeed prevent -any key events from being sent to the native control - which might not be -what is desired. In this case the event handler function has to call Skip() -so as to indicate that the search for the event handler should continue. - -To summarize, instead of explicitly calling the base class version as you -would have done with C++ virtual functions (i.e. @e wxTextCtrl::OnChar()), -you should instead call wxEvent::Skip. - -In practice, this would look like this if the derived text control only -accepts 'a' to 'z' and 'A' to 'Z': - -@code -void MyTextCtrl::OnChar(wxKeyEvent& event) -{ - if ( isalpha( event.KeyCode() ) ) - { - // key code is within legal range. we call event.Skip() so the - // event can be processed either in the base wxWidgets class - // or the native control. - - event.Skip(); - } - else - { - // illegal key hit. we don't call event.Skip() so the - // event is not processed anywhere else. - - wxBell(); - } -} -@endcode - -The normal order of event table searching by ProcessEvent is as follows: - -@li If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled) - the function skips to step (6). -@li If the object is a wxWindow, @b ProcessEvent is recursively called on the window's - wxValidator. If this returns @true, the function exits. -@li @b SearchEventTable is called for this event handler. If this fails, the base - class table is tried, and so on until no more tables exist or an appropriate - function was found, in which case the function exits. -@li The search is applied down the entire chain of event handlers (usually the chain has - a length of one). If this succeeds, the function exits. -@li If the object is a wxWindow and the event is set to set to propagate (in the library only - wxCommandEvent based events are set to propagate), @b ProcessEvent is recursively applied - to the parent window's event handler. If this returns @true, the function exits. -@li Finally, @b ProcessEvent is called on the wxApp object. - -Pay close attention to Step 5. People often overlook or get -confused by this powerful feature of the wxWidgets event processing -system. To put it a different way, events set to propagate -(see wxEvent::ShouldPropagate) -(most likely derived either directly or indirectly from wxCommandEvent) -will travel up the containment hierarchy from child to parent until the -maximal propagation level is reached or an event handler is found that -doesn't call @c event.Skip(). - -Finally, there is another additional complication (which, in fact, simplifies -life of wxWidgets programmers significantly): when propagating the command -events upwards to the parent window, the event propagation stops when it -reaches the parent dialog, if any. This means that you don't risk to get -unexpected events from the dialog controls (which might be left unprocessed by -the dialog itself because it doesn't care about them) when a modal dialog is -popped up. The events do propagate beyond the frames, however. The rationale -for this choice is that there are only a few frames in a typical application -and their parent-child relation are well understood by the programmer while it -may be very difficult, if not impossible, to track down all the dialogs which -may be popped up in a complex program (remember that some are created -automatically by wxWidgets). If you need to specify a different behaviour for -some reason, you can use wxWindow::SetExtraStyle(wxWS_EX_BLOCK_EVENTS) -explicitly to prevent the events from being propagated beyond the given window -or unset this flag for the dialogs which have it on by default. - -Typically events that deal with a window as a window (size, motion, -paint, mouse, keyboard, etc.) are sent only to the window. Events -that have a higher level of meaning and/or are generated by the window -itself, (button click, menu select, tree expand, etc.) are command -events and are sent up to the parent to see if it is interested in the event. - -Note that your application may wish to override ProcessEvent to redirect processing of -events. This is done in the document/view framework, for example, to allow event handlers -to be defined in the document or view. To test for command events (which will probably -be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for efficiency, -instead of using the slower run-time type system. - -As mentioned above, only command events are recursively applied to the parents event -handler in the library itself. As this quite often causes confusion for users, -here is a list of system events which will NOT get sent to the parent's event handler: - -@li wxEvent: The event base class -@li wxActivateEvent: A window or application activation event -@li wxCloseEvent: A close window or end session event -@li wxEraseEvent: An erase background event -@li wxFocusEvent: A window focus event -@li wxKeyEvent: A keypress event -@li wxIdleEvent: An idle event -@li wxInitDialogEvent: A dialog initialisation event -@li wxJoystickEvent: A joystick event -@li wxMenuEvent: A menu event -@li wxMouseEvent: A mouse event -@li wxMoveEvent: A move event -@li wxPaintEvent: A paint event -@li wxQueryLayoutInfoEvent: Used to query layout information -@li wxSetCursorEvent: Used for special cursor processing based on current mouse position -@li wxSizeEvent: A size event -@li wxScrollWinEvent: A scroll event sent by a scrolled window (not a scroll bar) -@li wxSysColourChangedEvent: A system colour change event - -In some cases, it might be desired by the programmer to get a certain number -of system events in a parent window, for example all key events sent to, but not -used by, the native controls in a dialog. In this case, a special event handler -will have to be written that will override ProcessEvent() in order to pass -all events (or any selection of them) to the parent window. - - -@section overview_eventhandling_prog User Generated Events vs Programmatically Generated Events - -While generically wxEvents can be generated both by user -actions (e.g. resize of a wxWindow) and by calls to functions -(e.g. wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived -events only for the user-generated events. The only @b exceptions to this rule are: - -@li wxNotebook::AddPage: No event-free alternatives -@li wxNotebook::AdvanceSelection: No event-free alternatives -@li wxNotebook::DeletePage: No event-free alternatives -@li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as - wxNotebook::SetSelection is deprecated -@li wxTreeCtrl::Delete: No event-free alternatives -@li wxTreeCtrl::DeleteAllItems: No event-free alternatives -@li wxTreeCtrl::EditLabel: No event-free alternatives -@li All wxTextCtrl methods - -wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other -functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free -equivalents. - - - -@section overview_eventhandling_pluggable Pluggable Event Handlers - -In fact, you don't have to derive a new class from a window class -if you don't want to. You can derive a new class from wxEvtHandler instead, -defining the appropriate event table, and then call wxWindow::SetEventHandler -(or, preferably, wxWindow::PushEventHandler) to make this -event handler the object that responds to events. This way, you can avoid -a lot of class derivation, and use instances of the same event handler class (but different -objects as the same event handler object shouldn't be used more than once) to -handle events from instances of different widget classes. - -If you ever have to call a window's event handler -manually, use the GetEventHandler function to retrieve the window's event handler and use that -to call the member function. By default, GetEventHandler returns a pointer to the window itself -unless an application has redirected event handling using SetEventHandler or PushEventHandler. - -One use of PushEventHandler is to temporarily or permanently change the -behaviour of the GUI. For example, you might want to invoke a dialog editor -in your application that changes aspects of dialog boxes. You can -grab all the input for an existing dialog box, and edit it 'in situ', -before restoring its behaviour to normal. So even if the application -has derived new classes to customize behaviour, your utility can indulge -in a spot of body-snatching. It could be a useful technique for on-line -tutorials, too, where you take a user through a serious of steps and -don't want them to diverge from the lesson. Here, you can examine the events -coming from buttons and windows, and if acceptable, pass them through to -the original event handler. Use PushEventHandler/PopEventHandler -to form a chain of event handlers, where each handler processes a different -range of events independently from the other handlers. - - - -@section overview_eventhandling_winid Window Identifiers - -Window identifiers are integers, and are used to -uniquely determine window identity in the event system (though you can use it -for other purposes). In fact, identifiers do not need to be unique -across your entire application just so long as they are unique within a -particular context you're interested in, such as a frame and its children. You -may use the @c wxID_OK identifier, for example, on any number of dialogs so -long as you don't have several within the same dialog. - -If you pass @c wxID_ANY to a window constructor, an identifier will be -generated for you automatically by wxWidgets. This is useful when you don't -care about the exact identifier either because you're not going to process the -events from the control being created at all or because you process the events -from all controls in one place (in which case you should specify @c wxID_ANY -in the event table or wxEvtHandler::Connect call -as well. The automatically generated identifiers are always negative and so -will never conflict with the user-specified identifiers which must be always -positive. - -See @ref page_stdevtid for the list of standard identifiers availabel. -You can use wxID_HIGHEST to determine the number above which it is safe to -define your own identifiers. Or, you can use identifiers below wxID_LOWEST. -Finally, you can allocate identifiers dynamically using wxNewId() function to. -If you use wxNewId() consistently in your application, you can be sure that -the your identifiers don't conflict accidentally. - - -@section overview_eventhandling_custom Custom Event Summary - -@subsection overview_eventhandling_custom_general General approach - -Since version 2.2.x of wxWidgets, each event type is identified by ID which -is given to the event type @e at runtime which makes it possible to add -new event types to the library or application without risking ID clashes -(two different event types mistakingly getting the same event ID). This -event type ID is stored in a struct of type @b const wxEventType. - -In order to define a new event type, there are principally two choices. -One is to define a entirely new event class (typically deriving from -wxEvent or wxCommandEvent. - -The other is to use the existing event classes and give them an new event -type. You'll have to define and declare a new event type using either way, -and this is done using the following macros: - -@code -// in the header of the source file -BEGIN_DECLARE_EVENT_TYPES() -DECLARE_EVENT_TYPE(name, value) -END_DECLARE_EVENT_TYPES() - -// in the implementation -DEFINE_EVENT_TYPE(name) -@endcode - -You can ignore the @e value parameter of the DECLARE_EVENT_TYPE macro -since it is used only for backwards compatibility with wxWidgets 2.0.x based -applications where you have to give the event type ID an explicit value. -See also the @ref page_samples_event for an example of code -defining and working with the custom event types. - - -@subsection overview_eventhandling_custom_existing Using Existing Event Classes - -If you just want to use a wxCommandEvent with -a new event type, you can then use one of the generic event table macros -listed below, without having to define a new macro yourself. This also -has the advantage that you won't have to define a new wxEvent::Clone() -method for posting events between threads etc. This could look like this -in your code: - -@code -DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1) -DEFINE_EVENT_TYPE(wxEVT_MY_EVENT) - -// user code intercepting the event - -BEGIN_EVENT_TABLE(MyFrame, wxFrame) -EVT_MENU (wxID_EXIT, MyFrame::OnExit) -// .... -EVT_COMMAND (ID_MY_WINDOW, wxEVT_MY_EVENT, MyFrame::OnMyEvent) -END_EVENT_TABLE() - -void MyFrame::OnMyEvent( wxCommandEvent ) -{ - // do something - wxString text = event.GetText(); -} - - -// user code sending the event - -void MyWindow::SendEvent() -{ - wxCommandEvent event( wxEVT_MY_EVENT, GetId() ); - event.SetEventObject( this ); - // Give it some contents - event.SetText( wxT("Hallo") ); - // Send it - GetEventHandler()->ProcessEvent( event ); -} -@endcode - - -@subsection overview_eventhandling_custom_generic Generic Event Table Macros - -@beginTable -@row2col{EVT_CUSTOM(event\, id\, func), - Allows you to add a custom event table - entry by specifying the event identifier (such as wxEVT_SIZE), - the window identifier, and a member function to call.} -@row2col{EVT_CUSTOM_RANGE(event\, id1\, id2\, func), - The same as EVT_CUSTOM, but responds to a range of window identifiers.} -@row2col{EVT_COMMAND(id\, event\, func), - The same as EVT_CUSTOM, but expects a member function with a - wxCommandEvent argument.} -@row2col{EVT_COMMAND_RANGE(id1\, id2\, event\, func), - The same as EVT_CUSTOM_RANGE, but - expects a member function with a wxCommandEvent argument.} -@row2col{EVT_NOTIFY(event\, id\, func), - The same as EVT_CUSTOM, but - expects a member function with a wxNotifyEvent argument.} -@row2col{EVT_NOTIFY_RANGE(event\, id1\, id2\, func), - The same as EVT_CUSTOM_RANGE, but - expects a member function with a wxNotifyEvent argument.} -@endTable - - -@subsection overview_eventhandling_custom_ownclass Defining Your Own Event Class - -Under certain circumstances, it will be required to define your own event -class e.g. for sending more complex data from one place to another. Apart -from defining your event class, you will also need to define your own -event table macro (which is quite long). Watch out to put in enough -casts to the inherited event function. Here is an example: - -@code -// code defining event - -class wxPlotEvent: public wxNotifyEvent -{ -public: - wxPlotEvent( wxEventType commandType = wxEVT_NULL, int id = 0 ); - - // accessors - wxPlotCurve *GetCurve() - { return m_curve; } - - // required for sending with wxPostEvent() - virtual wxEvent *Clone() const; - -private: - wxPlotCurve *m_curve; -}; - -DECLARE_EVENT_TYPE( wxEVT_PLOT_ACTION, -1 ) - -typedef void (wxEvtHandler::*wxPlotEventFunction)(wxPlotEvent&); - -#define EVT_PLOT(id, fn) \ - DECLARE_EVENT_TABLE_ENTRY( wxEVT_PLOT_ACTION, id, -1, \ - (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxNotifyEventFunction) \ - wxStaticCastEvent( wxPlotEventFunction, &fn ), (wxObject *) NULL ), - - -// code implementing the event type and the event class - -DEFINE_EVENT_TYPE( wxEVT_PLOT_ACTION ) - -wxPlotEvent::wxPlotEvent( ... - - -// user code intercepting the event - -BEGIN_EVENT_TABLE(MyFrame, wxFrame) -EVT_PLOT (ID_MY_WINDOW, MyFrame::OnPlot) -END_EVENT_TABLE() - -void MyFrame::OnPlot( wxPlotEvent &event ) -{ - wxPlotCurve *curve = event.GetCurve(); -} - - -// user code sending the event - -void MyWindow::SendEvent() -{ - wxPlotEvent event( wxEVT_PLOT_ACTION, GetId() ); - event.SetEventObject( this ); - event.SetCurve( m_curve ); - GetEventHandler()->ProcessEvent( event ); -} -@endcode - - -@section overview_eventhandling_macros Event Handling Summary - -For the full list of event classes, please see the -@ref group_class_events "event classes group page". - - -@todo for all controls state clearly when calling a member function results in an - event being generated and when it doesn't (possibly updating also the - 'Events generated by the user vs programmatically generated events' paragraph - of the 'Event handling overview' with the list of the functions which break - that rule). - -*/ - +///////////////////////////////////////////////////////////////////////////// +// Name: eventhandling.h +// Purpose: topic overview +// Author: wxWidgets team +// RCS-ID: $Id$ +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +/** + +@page overview_eventhandling Event Handling + +Classes: wxEvtHandler, wxWindow, wxEvent + +@li @ref overview_eventhandling_introduction +@li @ref overview_eventhandling_eventtables +@li @ref overview_eventhandling_connect +@li @ref overview_eventhandling_processing +@li @ref overview_eventhandling_prog +@li @ref overview_eventhandling_pluggable +@li @ref overview_eventhandling_winid +@li @ref overview_eventhandling_custom +@li @ref overview_eventhandling_macros + + +
+ + +@section overview_eventhandling_introduction Introduction + +There are two principal ways to handle events in wxWidgets. One of them uses +event table macros and allows you to define the connection between events +and their handlers only statically, i.e. during program compilation. The other +one uses wxEvtHandler::Connect() call and can be used to connect, and +disconnect, the handlers dynamically, i.e. during run-time depending on some +conditions. It also allows directly connecting the events of one object to a +handler method in another object while the static event tables can only handle +events in the object where they are defined so using Connect() is more flexible +than using the event tables. On the other hand, event tables are more succinct +and centralize all event handlers connection in one place. You can either +choose a single approach which you find preferable or freely combine both +methods in your program in different classes or even in one and the same class, +although this is probably sufficiently confusing to be a bad idea. + +But before you make this choice, let us discuss these two ways in some more +details: in the next section we provide a short introduction to handling the +events using the event tables, please see @ref overview_eventhandling_connect +for the discussion of Connect(). + +@section overview_eventhandling_eventtables Event Handling with Event Tables + +To use an event table you must first decide in which class you wish to +handle the events. The only requirement imposed by wxWidgets is that this class +must derive from wxEvtHandler and so, considering that wxWindow derives from +it, any classes representing windows can handle events. Simple events such as +menu commands are usually processed at the level of a top-level window +containing the menu, so let's suppose that you need to handle some events in @c +MyFrame class deriving from wxFrame. + +First thing to do is to define one or more event handlers. They +are just simple (non-virtual) methods of the class which take as a parameter a +reference to an object of wxEvent-derived class and have no return value (any +return information is passed via the argument, which is why it is non-const). +You also need to insert a macro + +@code +DECLARE_EVENT_TABLE() +@endcode + +somewhere in the class declaration. It doesn't matter where does it occur but +it's customary to put it at the end of it because the macro changes the access +type internally and so it's safest if there is nothing that follows it. So the +full class declaration might look like this: + +@code +class MyFrame : public wxFrame +{ +public: + MyFrame(...) : wxFrame(...) { } + + ... + +protected: + int m_whatever; + +private: + // notice that as the event handlers normally are not called from outside + // the class, they normally be private, in particular they don't need at + // all to be public + void OnExit(wxCommandEvent& event); + void OnButton1(wxCommandEvent& event); + void OnSize(wxSizeEvent& event); + + // it's common to call the event handlers OnSomething() but there is no + // obligation to it, this one is an event handler too: + void DoTest(wxCommandEvent& event); + + DECLARE_EVENT_TABLE() +}; +@endcode + +Next the event table must be defined and, as any definition, it must be placed +in an implementation file to tell. The event table tells wxWidgets how to map +events to member functions and in our example it could look like this: + +@code +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) + EVT_MENU(DO_TEST, MyFrame::DoTest) + EVT_SIZE(MyFrame::OnSize) + EVT_BUTTON(BUTTON1, MyFrame::OnButton1) +END_EVENT_TABLE() +@endcode + +Notice that you must mention a method you want to use for the event handling in +the event table definition, just defining it in MyFrame class is @e not enough. + +Let us now look at the details of this definition: the first line means that we +are defining the event table for MyFrame class and that its base class is +wxFrame, so events not processed by MyFrame will, by default, be handled to +wxFrame. The next four lines define connections of individual events to their +handlers: the first two of them map menu commands from the items with the +identifiers specified as the first macro parameter to two different member +functions. In the next one, @c EVT_SIZE means that any changes in the size of +the frame will result in calling OnSize() method. Note that this macro doesn't +need a window identifier, since normally you are only interested in the current +window's size events. + +The EVT_BUTTON macro demonstrates that the originating event does not have to +come from the window class implementing the event table -- if the event source +is a button within a panel within a frame, this will still work, because event +tables are searched up through the hierarchy of windows for the command events +(but only command events, so you can't catch mouse move events in a child +control in the parent window in the same way because wxMouseEvent doesn't +derive from wxCommandEvent, see below for how you can do it). In this case, the +button's event table will be searched, then the parent panel's, then the +frame's. + +Finally, you need to implement the event handlers. As mentioned before, all +event handlers take a wxEvent-derived argument whose exact class differs +according to the type of event and the class of the originating window. For +size events, wxSizeEvent is used. For menu commands and most control commands +(such as button presses), wxCommandEvent is used. And when controls get more +complicated, more specific wxCommandEvent-derived event classes providing +additional control-specific information can be used, such as wxTreeEvent for +events from wxTreeCtrl windows. + +In the simplest possible case an event handler may not use the @c event +parameter at all, e.g. + +@code +void MyFrame::OnExit(wxCommandEvent&) +{ + // when the user selects "Exit" from the menu we should close + Close(true); +} +@endcode + +In other cases you may need some information carried by the @c event argument, +as in: + +@code +void MyFrame::OnSize(wxSizeEvent& event) +{ + wxSize size = event.GetSize(); + + ... update the frame using the new size ... +} +@endcode + +You will find the details about the event table macros and the corresponding +wxEvent-derived classes in the discussion of each control generating these +events. + + +@section overview_eventhandling_connect Dynamic Event Handling + +As with the event tables, you need to decide in which class do you intend to +handle the events first and, also as before, this class must still derive from +wxEvtHandler (usually indirectly via wxWindow), see the declaration of MyFrame +in the previous section. However the similarities end here and both the syntax +and the possibilities of this way of handling events in this way are rather +different. + +Let us start by looking at the syntax: the first obvious difference is that you +don't need to use neither @c DECLARE_EVENT_TABLE() nor @c BEGIN_EVENT_TABLE and +associated macros any more. Instead, in any place in your code, but usually in +the code of the class defining the handlers itself (and definitely not in the +global scope as with the event tables), you should call its Connect() method +like this: + +@code +MyFrame::MyFrame(...) +{ + Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(MyFrame::OnExit)); +} +@endcode + +This class should be self-explanatory except for wxCommandEventHandler part: +this is a macro which ensures that the method is of correct type by using +static_cast in the same way as event table macros do it inside them. + +Now let us describe the semantic differences: + + +To summarize, using Connect() requires slightly more typing but is much more +flexible than using static event tables so don't hesitate to use it when you +need this extra power. On the other hand, event tables are still perfectly fine +in simple situations where this extra flexibility is not needed. + + +@section overview_eventhandling_processing How Events are Processed + +When an event is received from the windowing system, wxWidgets calls +wxEvtHandler::ProcessEvent on the first +event handler object belonging to the window generating the event. + +It may be noted that wxWidgets' event processing system implements something +very close to virtual methods in normal C++, i.e. it is possible to alter +the behaviour of a class by overriding its event handling functions. In +many cases this works even for changing the behaviour of native controls. + +For example it is possible to filter out a number of key events sent by the +system to a native text control by overriding wxTextCtrl and defining a +handler for key events using EVT_KEY_DOWN. This would indeed prevent +any key events from being sent to the native control - which might not be +what is desired. In this case the event handler function has to call Skip() +so as to indicate that the search for the event handler should continue. + +To summarize, instead of explicitly calling the base class version as you +would have done with C++ virtual functions (i.e. @e wxTextCtrl::OnChar()), +you should instead call wxEvent::Skip. + +In practice, this would look like this if the derived text control only +accepts 'a' to 'z' and 'A' to 'Z': + +@code +void MyTextCtrl::OnChar(wxKeyEvent& event) +{ + if ( isalpha( event.KeyCode() ) ) + { + // key code is within legal range. we call event.Skip() so the + // event can be processed either in the base wxWidgets class + // or the native control. + + event.Skip(); + } + else + { + // illegal key hit. we don't call event.Skip() so the + // event is not processed anywhere else. + + wxBell(); + } +} +@endcode + +The normal order of event table searching by ProcessEvent is as follows: +
    +
  1. If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled) + the function skips to step (6). +
  2. If the object is a wxWindow, @b ProcessEvent is recursively called on the window's + wxValidator. If this returns @true, the function exits. +
  3. @b SearchEventTable is called for this event handler. If this fails, the base + class table is tried, and so on until no more tables exist or an appropriate + function was found, in which case the function exits. +
  4. The search is applied down the entire chain of event handlers (usually the chain has + a length of one). If this succeeds, the function exits. +
  5. If the object is a wxWindow and the event is set to set to propagate (in the library only + wxCommandEvent based events are set to propagate), @b ProcessEvent is recursively applied + to the parent window's event handler. If this returns @true, the function exits. +
  6. Finally, @b ProcessEvent is called on the wxApp object. +
+Pay close attention to Step 5. People often overlook or get +confused by this powerful feature of the wxWidgets event processing +system. To put it a different way, events set to propagate +(see wxEvent::ShouldPropagate) +(most likely derived either directly or indirectly from wxCommandEvent) +will travel up the containment hierarchy from child to parent until the +maximal propagation level is reached or an event handler is found that +doesn't call @c event.Skip(). + +Finally, there is another additional complication (which, in fact, simplifies +life of wxWidgets programmers significantly): when propagating the command +events upwards to the parent window, the event propagation stops when it +reaches the parent dialog, if any. This means that you don't risk to get +unexpected events from the dialog controls (which might be left unprocessed by +the dialog itself because it doesn't care about them) when a modal dialog is +popped up. The events do propagate beyond the frames, however. The rationale +for this choice is that there are only a few frames in a typical application +and their parent-child relation are well understood by the programmer while it +may be very difficult, if not impossible, to track down all the dialogs which +may be popped up in a complex program (remember that some are created +automatically by wxWidgets). If you need to specify a different behaviour for +some reason, you can use wxWindow::SetExtraStyle(wxWS_EX_BLOCK_EVENTS) +explicitly to prevent the events from being propagated beyond the given window +or unset this flag for the dialogs which have it on by default. + +Typically events that deal with a window as a window (size, motion, +paint, mouse, keyboard, etc.) are sent only to the window. Events +that have a higher level of meaning and/or are generated by the window +itself, (button click, menu select, tree expand, etc.) are command +events and are sent up to the parent to see if it is interested in the event. + +Note that your application may wish to override ProcessEvent to redirect processing of +events. This is done in the document/view framework, for example, to allow event handlers +to be defined in the document or view. To test for command events (which will probably +be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for efficiency, +instead of using the slower run-time type system. + +As mentioned above, only command events are recursively applied to the parents event +handler in the library itself. As this quite often causes confusion for users, +here is a list of system events which will NOT get sent to the parent's event handler: + +@li wxEvent: The event base class +@li wxActivateEvent: A window or application activation event +@li wxCloseEvent: A close window or end session event +@li wxEraseEvent: An erase background event +@li wxFocusEvent: A window focus event +@li wxKeyEvent: A keypress event +@li wxIdleEvent: An idle event +@li wxInitDialogEvent: A dialog initialisation event +@li wxJoystickEvent: A joystick event +@li wxMenuEvent: A menu event +@li wxMouseEvent: A mouse event +@li wxMoveEvent: A move event +@li wxPaintEvent: A paint event +@li wxQueryLayoutInfoEvent: Used to query layout information +@li wxSetCursorEvent: Used for special cursor processing based on current mouse position +@li wxSizeEvent: A size event +@li wxScrollWinEvent: A scroll event sent by a scrolled window (not a scroll bar) +@li wxSysColourChangedEvent: A system colour change event + +In some cases, it might be desired by the programmer to get a certain number +of system events in a parent window, for example all key events sent to, but not +used by, the native controls in a dialog. In this case, a special event handler +will have to be written that will override ProcessEvent() in order to pass +all events (or any selection of them) to the parent window. + + +@section overview_eventhandling_prog User Generated Events vs Programmatically Generated Events + +While generically wxEvents can be generated both by user +actions (e.g. resize of a wxWindow) and by calls to functions +(e.g. wxWindow::SetSize), wxWidgets controls normally send wxCommandEvent-derived +events only for the user-generated events. The only @b exceptions to this rule are: + +@li wxNotebook::AddPage: No event-free alternatives +@li wxNotebook::AdvanceSelection: No event-free alternatives +@li wxNotebook::DeletePage: No event-free alternatives +@li wxNotebook::SetSelection: Use wxNotebook::ChangeSelection instead, as + wxNotebook::SetSelection is deprecated +@li wxTreeCtrl::Delete: No event-free alternatives +@li wxTreeCtrl::DeleteAllItems: No event-free alternatives +@li wxTreeCtrl::EditLabel: No event-free alternatives +@li All wxTextCtrl methods + +wxTextCtrl::ChangeValue can be used instead of wxTextCtrl::SetValue but the other +functions, such as wxTextCtrl::Replace or wxTextCtrl::WriteText don't have event-free +equivalents. + + + +@section overview_eventhandling_pluggable Pluggable Event Handlers + +In fact, you don't have to derive a new class from a window class +if you don't want to. You can derive a new class from wxEvtHandler instead, +defining the appropriate event table, and then call wxWindow::SetEventHandler +(or, preferably, wxWindow::PushEventHandler) to make this +event handler the object that responds to events. This way, you can avoid +a lot of class derivation, and use instances of the same event handler class (but different +objects as the same event handler object shouldn't be used more than once) to +handle events from instances of different widget classes. + +If you ever have to call a window's event handler +manually, use the GetEventHandler function to retrieve the window's event handler and use that +to call the member function. By default, GetEventHandler returns a pointer to the window itself +unless an application has redirected event handling using SetEventHandler or PushEventHandler. + +One use of PushEventHandler is to temporarily or permanently change the +behaviour of the GUI. For example, you might want to invoke a dialog editor +in your application that changes aspects of dialog boxes. You can +grab all the input for an existing dialog box, and edit it 'in situ', +before restoring its behaviour to normal. So even if the application +has derived new classes to customize behaviour, your utility can indulge +in a spot of body-snatching. It could be a useful technique for on-line +tutorials, too, where you take a user through a serious of steps and +don't want them to diverge from the lesson. Here, you can examine the events +coming from buttons and windows, and if acceptable, pass them through to +the original event handler. Use PushEventHandler/PopEventHandler +to form a chain of event handlers, where each handler processes a different +range of events independently from the other handlers. + + + +@section overview_eventhandling_winid Window Identifiers + +Window identifiers are integers, and are used to +uniquely determine window identity in the event system (though you can use it +for other purposes). In fact, identifiers do not need to be unique +across your entire application just so long as they are unique within a +particular context you're interested in, such as a frame and its children. You +may use the @c wxID_OK identifier, for example, on any number of dialogs so +long as you don't have several within the same dialog. + +If you pass @c wxID_ANY to a window constructor, an identifier will be +generated for you automatically by wxWidgets. This is useful when you don't +care about the exact identifier either because you're not going to process the +events from the control being created at all or because you process the events +from all controls in one place (in which case you should specify @c wxID_ANY +in the event table or wxEvtHandler::Connect call +as well. The automatically generated identifiers are always negative and so +will never conflict with the user-specified identifiers which must be always +positive. + +See @ref page_stdevtid for the list of standard identifiers available. +You can use wxID_HIGHEST to determine the number above which it is safe to +define your own identifiers. Or, you can use identifiers below wxID_LOWEST. +Finally, you can allocate identifiers dynamically using wxNewId() function to. +If you use wxNewId() consistently in your application, you can be sure that +the your identifiers don't conflict accidentally. + + +@section overview_eventhandling_custom Custom Event Summary + +@subsection overview_eventhandling_custom_general General approach + +Since version 2.2.x of wxWidgets, each event type is identified by ID which +is given to the event type @e at runtime which makes it possible to add +new event types to the library or application without risking ID clashes +(two different event types mistakingly getting the same event ID). This +event type ID is stored in a struct of type @b const wxEventType. + +In order to define a new event type, there are principally two choices. +One is to define a entirely new event class (typically deriving from +wxEvent or wxCommandEvent. + +The other is to use the existing event classes and give them an new event +type. You'll have to define and declare a new event type using either way, +and this is done using the following macros: + +@code +// in the header of the source file +BEGIN_DECLARE_EVENT_TYPES() +DECLARE_EVENT_TYPE(name, value) +END_DECLARE_EVENT_TYPES() + +// in the implementation +DEFINE_EVENT_TYPE(name) +@endcode + +You can ignore the @e value parameter of the DECLARE_EVENT_TYPE macro +since it is used only for backwards compatibility with wxWidgets 2.0.x based +applications where you have to give the event type ID an explicit value. +See also the @ref page_samples_event for an example of code +defining and working with the custom event types. + + +@subsection overview_eventhandling_custom_existing Using Existing Event Classes + +If you just want to use a wxCommandEvent with +a new event type, you can then use one of the generic event table macros +listed below, without having to define a new macro yourself. This also +has the advantage that you won't have to define a new wxEvent::Clone() +method for posting events between threads etc. This could look like this +in your code: + +@code +DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1) +DEFINE_EVENT_TYPE(wxEVT_MY_EVENT) + +// user code intercepting the event + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) +EVT_MENU (wxID_EXIT, MyFrame::OnExit) +// .... +EVT_COMMAND (ID_MY_WINDOW, wxEVT_MY_EVENT, MyFrame::OnMyEvent) +END_EVENT_TABLE() + +void MyFrame::OnMyEvent( wxCommandEvent ) +{ + // do something + wxString text = event.GetText(); +} + + +// user code sending the event + +void MyWindow::SendEvent() +{ + wxCommandEvent event( wxEVT_MY_EVENT, GetId() ); + event.SetEventObject( this ); + // Give it some contents + event.SetText( wxT("Hallo") ); + // Send it + GetEventHandler()->ProcessEvent( event ); +} +@endcode + + +@subsection overview_eventhandling_custom_generic Generic Event Table Macros + +@beginTable +@row2col{EVT_CUSTOM(event\, id\, func), + Allows you to add a custom event table + entry by specifying the event identifier (such as wxEVT_SIZE), + the window identifier, and a member function to call.} +@row2col{EVT_CUSTOM_RANGE(event\, id1\, id2\, func), + The same as EVT_CUSTOM, but responds to a range of window identifiers.} +@row2col{EVT_COMMAND(id\, event\, func), + The same as EVT_CUSTOM, but expects a member function with a + wxCommandEvent argument.} +@row2col{EVT_COMMAND_RANGE(id1\, id2\, event\, func), + The same as EVT_CUSTOM_RANGE, but + expects a member function with a wxCommandEvent argument.} +@row2col{EVT_NOTIFY(event\, id\, func), + The same as EVT_CUSTOM, but + expects a member function with a wxNotifyEvent argument.} +@row2col{EVT_NOTIFY_RANGE(event\, id1\, id2\, func), + The same as EVT_CUSTOM_RANGE, but + expects a member function with a wxNotifyEvent argument.} +@endTable + + +@subsection overview_eventhandling_custom_ownclass Defining Your Own Event Class + +Under certain circumstances, it will be required to define your own event +class e.g. for sending more complex data from one place to another. Apart +from defining your event class, you will also need to define your own +event table macro (which is quite long). Watch out to put in enough +casts to the inherited event function. Here is an example: + +@code +// code defining event + +class wxPlotEvent: public wxNotifyEvent +{ +public: + wxPlotEvent( wxEventType commandType = wxEVT_NULL, int id = 0 ); + + // accessors + wxPlotCurve *GetCurve() + { return m_curve; } + + // required for sending with wxPostEvent() + virtual wxEvent *Clone() const; + +private: + wxPlotCurve *m_curve; +}; + +DECLARE_EVENT_TYPE( wxEVT_PLOT_ACTION, -1 ) + +typedef void (wxEvtHandler::*wxPlotEventFunction)(wxPlotEvent&); + +#define EVT_PLOT(id, fn) \ + DECLARE_EVENT_TABLE_ENTRY( wxEVT_PLOT_ACTION, id, -1, \ + (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxNotifyEventFunction) \ + wxStaticCastEvent( wxPlotEventFunction, &fn ), (wxObject *) NULL ), + + +// code implementing the event type and the event class + +DEFINE_EVENT_TYPE( wxEVT_PLOT_ACTION ) + +wxPlotEvent::wxPlotEvent( ... + + +// user code intercepting the event + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) +EVT_PLOT (ID_MY_WINDOW, MyFrame::OnPlot) +END_EVENT_TABLE() + +void MyFrame::OnPlot( wxPlotEvent &event ) +{ + wxPlotCurve *curve = event.GetCurve(); +} + + +// user code sending the event + +void MyWindow::SendEvent() +{ + wxPlotEvent event( wxEVT_PLOT_ACTION, GetId() ); + event.SetEventObject( this ); + event.SetCurve( m_curve ); + GetEventHandler()->ProcessEvent( event ); +} +@endcode + + +@section overview_eventhandling_macros Event Handling Summary + +For the full list of event classes, please see the +@ref group_class_events "event classes group page". + + +@todo for all controls state clearly when calling a member function results in an + event being generated and when it doesn't (possibly updating also the + 'Events generated by the user vs programmatically generated events' paragraph + of the 'Event handling overview' with the list of the functions which break + that rule). + +*/ +