Event Tables and Handlers

team bbl


The wxWidgets event processing system is a more flexible mechanism than virtual functions, allowing us to avoid declaring all possible event handlers in a base class, which would be totally impractical as well as inefficient.

Every class that derives from wxEvtHandler, including frames, buttons, menus, and even documents, can contain an event table to tell wxWidgets how events are routed to handler functions. All window classes (derived from wxWindow), and the application class, are derived from wxEvtHandler.

To create a static event table (one that's created at compile time), you need to

  1. Declare a new class that is derived directly or indirectly from wxEvtHandler.

  2. Add a member function for each event that must be handled.

  3. Declare the event table in the class with DECLARE_EVENT_TABLE.

  4. Implement the event table in the source file with BEGIN_EVENT_TABLE... END_EVENT_TABLE.

  5. Add event table entries to the table (such as EVT_BUTTON), mapping each event to the appropriate member function.

All event handler functions have the same formtheir return type is void, they are not virtual, and they take a single event object argument. (If you're familiar with MFC, this will come as a relief, because there is no standard signature for message handlers in MFC.) The type of this argument changes according to the type of event being handled; for example, simple control commands and menu commands share the wxCommandEvent class. A size event (caused by a window being resized either by the program or by the user) is represented by the wxSizeEvent class. Each event type has different accessors that you can use to learn about the cause of the event or the resulting UI change, such as a change in the value of a text control. In simple cases (such as a button press), you can often ignore the event object.

Expanding on the example from the previous chapter, let's add a handler for frame sizing, plus an OK button. A simple class declaration for an event-handling class looks like this:

 // Declare our main frame class class MyFrame : public wxFrame { public:     // Constructor     MyFrame(const wxString& title);     // Event handlers     void OnQuit(wxCommandEvent& event);     void OnAbout(wxCommandEvent& event);     void OnSize(wxSizeEvent& event);     void OnButtonOK(wxCommandEvent& event); private:     // This class handles events     DECLARE_EVENT_TABLE() }; 

The code to add menu items will be similar to the code in the previous chapter, while code to add an OK button might look like this, in the frame constructor:

 wxButton* button = new wxButton(this, wxID_OK, wxT("OK"),                                    wxPoint(200, 200)); 

Here's the event table, allowing the frame to handle menu, button, and size events.

 // Event table for MyFrame BEGIN_EVENT_TABLE(MyFrame, wxFrame)     EVT_MENU     (wxID_ABOUT,     MyFrame::OnAbout)     EVT_MENU     (wxID_EXIT,      MyFrame::OnQuit)     EVT_SIZE     (                MyFrame::OnSize)     EVT_BUTTON   (wxID_OK,        MyFrame::OnButtonOK) END_EVENT_TABLE() 

When the user clicks on the About or Quit menu items, the event is sent to the frame, and MyFrame's event table tells wxWidgets that a menu event with identifier wxID_ABOUT should be sent to MyFrame::OnAbout, and a menu event with identifier wxID_EXIT should be sent to MyFrame::OnQuit. In other words, these functions will be called with a single argument (in this case, wxCommandEvent) when the event loop processes the events.

The EVT_SIZE macro does not take an identifier argument because a size event can only be handled by the object that generated it.

The EVT_BUTTON entry will cause OnButtonOK to be called when a button in the frame's window hierarchy with identifier wxID_OK is pressed. This example shows that the event can be processed by a window other than the source of the event. Let's assume the button is a child of MyFrame. When the button is pressed, wxWidgets will check the wxButton class for a suitable handler. When one is not found, it checks the parent of the buttonin this case, a MyFrame instance. The event matches an entry in the event table, so MyFrame::OnButtonOK is called. This search of the window component hierarchy, as well as the inheritance hierarchy, means that you can choose where you handle events. For example, if you are designing a dialog class that must respond to commands such as wxID_OK, but you need to leave the creation of the actual controls to other programmers using your code, you can still define default behavior for the controls as long as they have the expected identifiers.

The generation of a button click event and its subsequent matching against an appropriate event table entry is illustrated in Figure 3-1. Two class hierarchies are shown, for wxButton and MyFrame. Each class has its own event table that potentially contains the entry that will match the event. When the user clicks on the OK button, a new wxCommandEvent object is created that contains the identifier (wxID_OK) and the type of event (wxEVT_COMMAND_BUTTON_ CLICKED). Now the event tables are searched using wxEvtHandler::ProcessEvent; all of the wxButton's event table events are tried, then wxControl's, then wxWindow's. If no appropriate entry is found that matches against the event type and identifier, wxWidgets tries the parent of the button and starts searching its event table. It has a matching entry:

 EVT_BUTTON(wxID_OK,MyFrame::OnButtonOK) 

Figure 3-1. Processing a button click event


so MyFrame::OnButtonOK is called.

Note that only command events (whose event classes are based directly or indirectly on wxCommandEvent) are recursively applied to the window parent's event handler. As this quite often causes confusion for users, here is a list of system events that will not get sent to the parent's event handler: wxActivate Event, wxCloseEvent, wxEraseEvent, wxFocusEvent, wxKeyEvent, wxIdleEvent, wxInitDialogEvent, wxJoystickEvent, wxMenuEvent, wxMouseEvent, wxMoveEvent, wxPaintEvent, wxQueryLayoutInfoEvent, wxSizeEvent, wxScrollWinEvent, and wxSysColourChangedEvent.

These events do not propagate because they are meant for a particular window, and sending a child's paint event to its parent, for example, does not make sense.

    team bbl



    Cross-Platform GUI Programming with wxWidgets
    Cross-Platform GUI Programming with wxWidgets
    ISBN: 0131473816
    EAN: 2147483647
    Year: 2005
    Pages: 262

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net