Difference between revisions of "Custom Events in wx2.8 and earlier"

From WxWiki
Jump to navigation Jump to search
m (→‎Note about wxPostEvent()...: clarity, formatting)
Line 71: Line 71:
 
   DEFINE_LOCAL_EVENT_TYPE(myEVT_SOMETHINGHAPPENED)
 
   DEFINE_LOCAL_EVENT_TYPE(myEVT_SOMETHINGHAPPENED)
  
The event type isn't used by the macro. (7777 appears to be an ad-hoc standard: any value works but unique is "better".  My spurious wxNewEventType() argument is almost certainly ''incorrect'' because it's in the declaraion not the definition. In my code the declaration is only hit once, so that's okay.)
+
The event type isn't used by the macro. (7777 appears to be an ad-hoc standard: any value works but unique is "better".  My spurious wxNewEventType() argument is almost certainly ''incorrect'' because it's in the declaration not the definition. In my code the declaration is only hit once, so that's okay.)
  
 
Then in your event table (in this case, based on a wxControl)...
 
Then in your event table (in this case, based on a wxControl)...

Revision as of 15:09, 18 May 2006

Custom Events

HopeSeekr of xMule has composed a tutorial: http://www.xmule.ws/phpnuke/modules.php?name=News&file=article&sid=76 old link.

See the Event handling overview in the official docs.

EVT_FOO(-1, SomeClass::SomeFunc) is a purely passive declaration. It says, "If a FOO happens to come my way, let me know about it." It doesn't tell any particular FOO-generating class to notify this class about FOO events. But without this, it will not respond to FOO events at all, even if explicitly sent to an object of this class.

wxButton events seem to work automatically because the EVT_BUTTON is generated in the wxButton itself, and since it's a command event it propogates to its parents automatically. Thus, no call to SetEventHandler() or similar is necessary.

wxSocket events do not exist in a chain of parents, so SetEventHandler() is necessary. This establishes the connection between an event and a particular instance of an object.

Note that there are other strategies for the event dispatching as well, except the first 2 already mentioned above and which I'm going to repeat for completeness:

  • send the event to oneself (possibly relying on it to be propagated to the parent)
  • send the event to another event handler explicitly associated with us
  • send the event to all top level windows (possibly relying on them to propagate the event *downwards* to their children recursively; example: EVT_IDLE)
  • send the event to wxTheApp only

In subclassing wxEvent, remember to associate your event (wxFooEvent) to your event type (wxEVT_FOO) in the constructor:


 wxFooEvent(int id=0)
    : wxEvent (id, wxEVT_FOO)
 {
    ...
 }


To get a unique wxEVT_FOO, use wxEVT_FOO = wxNewEventType();

Creating a custom event (with the new method)

Example of custom event creation managing a click (by Marco Cavallini)

 // Myclass.h
 const newEVT_MYCLASS_FIRST = wxEVT_FIRST + 5400;
 
 const wxEventType newEVT_MYCLASS_CLICK	= newEVT_MYCLASS_FIRST + 1;
 
 #define EVT_MYCLASS_CLICK(id, fn)	\
 	DECLARE_EVENT_TABLE_ENTRY(newEVT_MYCLASS_CLICK, id, -1, \
 	(wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction)&fn, \
 	(wxObject*)NULL ),

In the class you have to manage the event as you like and send your custom one to the event table

 // Myclass.h
 
 void Myclass::OnMouse(wxMouseEvent& event)
 {
   if (event.LeftIsDown())
   {
      wxCommandEvent event(kwxEVT_BITBUTTON_CLICK, GetId());
      event.SetEventObject(this);
      ProcessCommand(event);
   }
 }

Quick & dirty custom events

This was tested under wxWidgets 2.4.2 (GTK) and seems to be less complicated than the other methods here. It was derived from the event.cpp example, and uses a wxCommandEvent to pass data.

First, the declaration (needed to scope the event) and then the definition:

 BEGIN_DECLARE_EVENT_TYPES()
 DECLARE_LOCAL_EVENT_TYPE(myEVT_SOMETHINGHAPPENED,wxNewEventType())
 END_DECLARE_EVENT_TYPES()
 
 DEFINE_LOCAL_EVENT_TYPE(myEVT_SOMETHINGHAPPENED)

The event type isn't used by the macro. (7777 appears to be an ad-hoc standard: any value works but unique is "better". My spurious wxNewEventType() argument is almost certainly incorrect because it's in the declaration not the definition. In my code the declaration is only hit once, so that's okay.)

Then in your event table (in this case, based on a wxControl)...

 BEGIN_EVENT_TABLE(myFunkyObject,wxControl)
 EVT_BUTTON(...)
 ...
 EVT_CUSTOM(myEVT_SOMETHINGHAPPENED,wxID_ANY,myFunkyObject::OnSomethingHappened)
 END_EVENT_TABLE()
 
 myFunkyObject::OnSomethingHappened(wxCommandEvent &event) {thing=event.GetInt();}

I'm not sure what the id field in EVT_CUSTOM is for (it's the starting id number) but -1 (wxID_ANY) seems to work fine.

Then, to make something happen with your event from another object, do this:

 myDifferentObject::makesomethinghappen(int what) {
     wxCommandEvent event(myEVT_SOMETHINGHAPPENED);
     event.SetInt(what);
     wxPostEvent(ptr_to_a_myFunkyObject_chain,event);
     }

(D.F. Smith, Aug2004)

Note about wxPostEvent() vs. wxEvtHandler::ProcessEvent()

Both can be used when the event handler object is known at compile time.

wxEvtHandler::ProcessEvent(wxEvent& event)

ProcessEvent will call the event handler directly and the event will be processed serially like a function call.

wxPostEvent(wxEvtHandler *evtHandler, wxEvent& event)

wxPostEvent will put the event in the event queue of the wxEvtHandler object but the event will not be processed immediately. Note that the event queue can be flushed by calling wxApp::Yield or wxYieldIfNeeded.

Creating a custom event (with the ugly macro stuff)

You need to declare your event type first:

 DECLARE_EVENT_TYPE(wxCUSTOM_EVENT, 7777)
 DEFINE_EVENT_TYPE(wxCUSTOM_EVENT)

The second argument to DECLARE_EVENT_TYPE is only needed in wxWidgets < 2.4.0, and it's your event id there. Must be unique. As of 2.4.0, event ID's are dynamically allocated at runtime so theres no conflicts.

Next, you'll want an event table macro for your event. This one can be pretty funky.

 #define EVT_CUSTOM_EVENT(fn) &#92;
     DECLARE_EVENT_TABLE_ENTRY( &#92;
 	wxCUSTOM_EVENT, wxID_ANY, wxID_ANY, &#92;
 	(wxObjectEventFunction)(wxEventFunction)&fn, &#92;
 	(wxObject *) NULL &#92;
   ),

This is a declaration that doesn't want an id, and it's for wxEvent-derived events. You'll need to add a cast to wxCommandEvent for command events, and add arguments for events that have IDs.

TODO: provide an example

Finally, implement your event itself. The things to remember are:

  • Set the m_eventType param with your new event type in the constructor
  • Implement a virtual Clone() method:
virtual wxEvent *Clone() const {return new wxCustomEvent(*this);}
  • Implement a copy constructor
  • Be sure to use the DECLARE_DYNAMIC_CLASS and IMPLEMENT_DYNAMIC_CLASS macros

A quick custom event example:

customevent.h:

 DECLARE_EVENT_TYPE(wxCUSTOM_EVENT, 7777)
 #define EVT_CUSTOM_EVENT(fn) &#92;
     DECLARE_EVENT_TABLE_ENTRY( &#92;
 	wxCUSTOM_EVENT, wxID_ANY, wxID_ANY, &#92;
 	(wxObjectEventFunction)(wxEventFunction)&fn, &#92;
 	(wxObject *) NULL &#92;
     ),
 class wxCustomEvent : public wxEvent {
     wxCustomEvent();
     wxCustomEvent(const wxCustomEvent &event);
     virtual wxEvent *Clone() const {return new wxCustomEvent(*this);};
     DECLARE_DYNAMIC_CLASS(wxCustomEvent)
 };

customevent.cpp:

 DEFINE_EVENT_TYPE(wxCUSTOM_EVENT);
 IMPLEMENT_DYNAMIC_CLASS(wxCustomEvent, wxEvent)
 wxCustomEvent::wxCustomEvent():m_eventType(wxCUSTOM_EVENT) {
 }
 wxCustomEvent::wxCustomEvent(const wxCustomEvent &event) {
   this->m_eventType = event.m_eventType;  //not really needed in this sample, but it's boring to have it empty
 }


Using your new class:

 DECLARE_EVENT_TABLE(myForm, wxForm)
     EVT_CUSTOM_EVENT(myForm::HandleCustomEvent)
 END_EVENT_TABLE()

See also

by Markus Neifer: [1]. Unfortunately outdated.

It is a Very Good Idea to look at the events sample, which has a custom event (even though there is some ugly macro stuff going on).