Events

From WxWiki
Jump to: navigation, search

In addition to the material below see the event project in the samples directory and the Event Handling Overview.

Introduction

wxEvent is a class that transfers information around a wx program (the usual information is just "Hey, something happened": for example "the mouse moved inside me").

wxCommandEvent is a subclass that is used for menu events etc. The main difference is that it propagates to parent classes.

So if a mouse movement occurs in a wxTextCtrl, the textctrl will be told about it by a wxMouseEvent. That event will then die: it won't be passed to the textctrl's parent (which might be a wxPanel or wxFrame) because parent classes shouldn't need to know about this sort of event.

If a wxButton is clicked, it sends a wxCommandEvent, because it's quite likely that parent classes are interested in button clicks. So this event does get passed up the chain to the button's parent, grandparent etc. (until one of them handles it and doesn't call Skip()). See the Event-handling Overviewfor more details about propagation.

There are other event classes, often subclasses of wxCommandEvent, which have space for more complex information e.g. which item was selected. You can also make your own custom event subclass, which can contain whatever you wish.

Don't be confused by event type, even though the names are often similar. wxEVT_MOTION is an event-type, which is just an int (actually an entry in an enum). It's used as the parameter when creating a wxMouseEvent, but it's not itself an event.

Event Tables

An event table such as the one below tells wxWidgets how to map events to member functions. It should be defined in the implementation file (.cpp).

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
   EVT_MENU(wxID_EXIT, MyFrame::OnExit)
   EVT_SIZE(MyFrame::OnSize)
   EVT_BUTTON(BUTTON1, MyFrame::OnButton1)
END_EVENT_TABLE()

The above event table tells wxWidgets, when it receives a wxSizeEvent for MyFrame, to call the OnSize member function. The BEGIN_EVENT_TABLE macro declares that MyFrame, which is derived from wxFrame, owns this event table.

The member function that handles an event does not have to be virtual. In fact, the event handler ignores the virtual declaration. These functions have a similar form: the return type is void and they receive an event parameter. The type of this parameter depends on the event. For size events, wxSizeEvent is used. For menu commands and most control commands (e.g. a button), wxCommandEvent is used. When controls get more complicated, they use their own event class.

You must place the DECLARE_EVENT_TABLE macro in the class definition. For an example see The Full Implementation Of The TextFrame Class.

Note that the second argument of macro's (e.g. MyFrame::OnButton1) must always be a member of the class specified in the first argument of BEGIN_EVENT_TABLE.

Identifier Sizes

It is worth noting that (at least on MS Windows) identifiers are 16 bits in size. If you declare your menu identifiers larger than 16 bits, everything will compile fine, but none of your events will work.

wxMenuBar Events

A wxMenuBar doesn't send events to itself, but to its parent frame. This might seem inconsistent, but it's actually convenient in all common situations.

Every event is associated with a wxEvent. Therefore, make sure you ALWAYS define a wxEvent to the function! The following example will crash in Release build (at least on MSW & with wxWidgets 2.4.2)(Edit: >2.4.2 it won't compile anyway):

void MyFrame::OnExit( void )
{
// Do Something
}

This slightly changed example, however, will run just fine:

void MyFrame::OnExit( wxEvent& WXUNUSED(event) )
{
// Do Something
}

Event.Skip and Event.Veto

Taken from a post by Robin Dunn:

>>If the event is derived from a wxCommandEvent and you call
>>event.Skip(TRUE) the event continues up the chain to the top level
>>window. Otherwise the program returns to the function that posted the
>>event.
>
>
> That's exactly what I meant, if do nothing in the handler /and/ I do
> *not* call Skip(), then isn't the final result/effect the same as
> vetoing?

No, there is a big conceptual difference. Some events are so your code can *do* 
something in response to the event. For example, to repaint the window, to layout 
components when the size changes, to do something when an item is activated, etc.
Other events are there simply to *notify* your code that something is about to 
happen and are giving your code a chance to stop it from happening. Under normal 
circumstances you don't need to *do* anything for those events.

The Skip is different. It controls whether the parent class and/or the parent window will also have its event table seached for a handler to be invoked for the event, and eventually (for many event types) whether the default platform level functionality will be invoked or not. Yes, in many cases catching an event and doing nothing will effectivly prevent some functionality from being executed, but it is in the cases where you are expected to *do* something when you catch the event and you don't do it. The notification events are at a high level and are just saying, "Oh, by the way I am about to do such-and-such, is that okay?"

I've never seen it done, but Skip and Veto could be combined. You could catch a notification event, Veto it, then call Skip giving the parent classes or windows a chance to unVeto it.

(It appears in wxWidgets 2.6.1 that calling Skip() after Veto() on an event causes the Veto() to be ignored.)

Inheriting Event Tables (Events in Derived Classes)

Say you made a new class derived from wxWizard, called MyWizardBase and it had an event table. Then you made a derived class of MyWizardBase called MyInstallWizard, and you wanted it to inherit the event table of MyWizardBase also, and perhaps add a few of its own.

To do so, you need the BEGIN_EVENT_TABLE( a, b ) macro, where b is the direct parent of the class a. So for this example it would be BEGIN_EVENT_TABLE( MyInstallWizard, MyWizardBase ).

If you instead wrote BEGIN_EVENT_TABLE( MyInstallWizard, wxWizard ), things would still compile perfectly, but you would be wondering why none of the MyWizardBase events seemed to be working.

Unique ID

If you don't want to specify a unique ID in an EVT_-macro, you can use wxID_ANY (-1).

Using Connect()

Connect() is more flexible - it does the same thing as EVT_, but at run-time instead of compile-time. Don't mess with ProcessEvent(). See the Example Of Using Connect For Events.

This is particularly useful in situations where you would normally have to derive from a wxWidgets class for the sole purpose of adding some event handlers.

One thing to note about calling connect is to use the correct object to call it. For example if you have a Frame class that holds your event function and a button that should call your event function, button.Connect() should not be used, but instead you call this.Connect() or just Connect(), so it is your Frame class that calls Connect(), not a child object such as a button. For more information, see my full exprience here: How to create and use dynamic event handlers in wxWidgets for an array of buttons using the Connect() function? and also the key article that helped me most: In praise of connect

Starting from wxWidgets 2.9, it is highly recommended to use Bind instead of Connect, since it uses templates to perform compile-time checks : https://docs.wxwidgets.org/trunk/classwx_evt_handler.html#84b1e446053bda8f76f13336839e8b64

Documentation

wxEVT_ macros are usually listed under wxEvent Derivatives. However, if in doubt, look in include/wx/event.h

Custom Events

You can create Custom Events.

Short Summary of Events

A list of available events (generated from the XML class information) is available at http://www.bzzt.net/~wxwidgets/xmldocs/applications/eventslist/eventslist.html

Preprocessor Commands in the Event Table

Just a bit of a warning: It appears that you cannot use preprocessor commands inside the Event Table. It will not cause any compiler errors or warnings.

(4/5/04) win32 2.4.2 with #ifdef

  • I've had no problems with this on MSW from about 2.5.1 through 2.6.3 with MSVC++. Were event tables defined significantly different with 2.4.2? --Tierra 08:58, 16 May 2006 (PDT)