Development: Event Handling Improvements
Introduction
This page describes what changes have to be made to the current event handling system to get it type safe. It currently serves as a kind of blackboard, so that participating developer don't have to wade through the complete discussion to see what has already been solved/decided.
Some issues I omitted from this code, because I think they are quite easily solvable or are already solved in the original code:
- Disconnecting an event handler.
Because this code serves as a kind of prototype, unnecessary parameters have been omitted to keep the 'noise' down and the signatures short.
Desired use cases
// A new/typesafe wxWidgets event:
class wxTimerEvent : public wxEvent
{
public:
wxTimerEvent( wxEventType eventType )
: wxEvent( eventType )
{ }
};
// The timer event handler without any casts:
#define wxTimerEventHandler( func ) ( &func )
extern const wxTypedEventType< wxTimerEvent > wxEVT_TIMER;
const wxTypedEventType< wxTimerEvent > wxEVT_TIMER( wxNewEventType() );
// An old/user defined event type:
class wxColorEvent : public wxEvent
{
public:
wxColorEvent( wxEventType eventType )
: wxEvent( eventType )
{ }
};
// Two possible ways how the event can be declared:
extern const wxEventType wxEVT_BLUE;
DECLARE_EVENT_TYPE( wxEVT_BLUE, 0 )
DEFINE_EVENT_TYPE( wxEVT_BLUE )
// The color event handler with a lot of casts:
typedef void (wxEvtHandler::*wxColorEventFunction)(wxColorEvent&);
typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&);
typedef wxEventFunction wxObjectEventFunction;
#define wxColorEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)static_cast< wxColorEventFunction >( &func )
// Some functions as event handlers:
void handleTimerEventFunction( wxTimerEvent &event )
{
printf( "::handleTimerEventFunction( wxTimerEvent & )\n" );
}
void handleColorEventFunction( wxColorEvent &event )
{
printf( "::handleColorEventFunction( wxColorEvent & )\n" );
}
// An event handler which uses it's own methods as handlers:
class MyEventHandler : public wxEvtHandler
{
public:
MyEventHandler()
{
Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handleTimerEventMethod ));
Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleColorEventMethod ));
}
void handleTimerEventMethod( wxTimerEvent &event )
{
printf( "MyEventHandler::handleTimerEventMethod( wxTimerEvent & )\n" );
}
void handleColorEventMethod( wxColorEvent &event )
{
printf( "MyEventHandler::handleColorEventMethod( wxColorEvent & )\n" );
}
};
// Another event handler which uses the base class methods as handlers:
class MyDerivedEventHandler : public MyEventHandler
{
public:
MyDerivedEventHandler()
{
Connect( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod ));
Connect( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod ));
}
};
wxEventTableEntry sm_staticEventHandlers[] =
{
DECLARE_EVENT_TABLE_ENTRY( wxEVT_TIMER, &handleTimerEventFunction ),
DECLARE_EVENT_TABLE_ENTRY( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod )),
DECLARE_EVENT_TABLE_ENTRY( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod )),
// Must not compile
// DECLARE_EVENT_TABLE_ENTRY( wxEVT_BLUE, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod )),
// Mark the end of the table ie: END_EVENT_TABLE()
wxEventTableEntry( wxEVT_NULL, NULL )
};
int main( void )
{
//
// should compile:
//
wxEvtHandler eventProvider;
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( handleTimerEventFunction ));
MyEventHandler eventHandler;
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handleTimerEventMethod ));
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handleTimerEventMethod ), &eventHandler);
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleColorEventMethod ));
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleColorEventMethod ), &eventHandler );
MyDerivedEventHandler derivedEventHandler;
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod ));
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod ), &derivedEventHandler );
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod ));
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod ), &derivedEventHandler );
// Must not compile:
// eventProvider.Connect( wxEVT_BLUE, &handleTimerEventFunction );
// eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleTimerEventMethod ));
// Send an event:
wxTimerEvent timerEvent( wxEVT_TIMER );
eventProvider.ProcessEvent( timerEvent );
// Send an illegal event (leads to an ASSERT in wxEvtFunction<Event>::Relay):
wxColorEvent colorEvent( wxEVT_TIMER );
eventProvider.ProcessEvent( colorEvent );
return ( 0 );
}
Provide a template which associates the event type with the correct event
template < typename Event >
class wxTypedEventType
{
public:
typedef Event AssociatedEvent;
wxTypedEventType( wxEventType type )
{
m_type = type;
}
// Will be needed for the static event tables:
operator const wxEventType &() const
{
return ( m_type );
}
private:
wxEventType m_type;
};
Modify all event handler macros and remove the (now unnecessary) castings to wxEvtHandler
Old definition:
#define wxTimerEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxTimerEventFunction, &func)
New definition:
#define wxTimerEventHandler( func ) \
( &func )
Modify all event type definitions/declarations to make them type safe
Old definiton:
const wxEventType wxEVT_TIMER = wxNewEventType();
New definition:
const wxTypedEventType< wxTimerEvent > wxEVT_TIMER( wxNewEventType() );
Provide wxEvtFunctor, wxEvtMethod and wxEvtFunction to serve as a kind of command pattern to be stored in the dynamic and static event tables
class wxEvtHandler;
// The functor which will be stored in the static/dynamic tables:
class wxEvtFunctor
{
public:
virtual ~wxEvtFunctor()
{ }
virtual void Relay( wxEvtHandler *handler, wxEvent & ) = 0;
};
template < typename Event >
class wxEvtFunction : public wxEvtFunctor
{
public:
wxEvtFunction( void ( *handler )( Event & ))
{
m_handler = handler;
}
virtual void Relay( wxEvtHandler *, wxEvent &event )
{
// Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT):
wxASSERT( dynamic_cast< Event * >( &event ) != NULL );
// Will throw a std::bad_cast exception in release build:
( *m_handler )( dynamic_cast< Event & >( event ));
}
private:
void ( *m_handler )( Event & );
};
template < typename Event, typename Class >
class wxEvtMethod : public wxEvtFunctor
{
public:
wxEvtMethod( void ( Class::*method )( Event & ), wxEvtHandler *handler )
{
m_handler = handler;
m_method = static_cast< void ( wxEvtHandler::* )( Event & ) >( method );
}
virtual void Relay( wxEvtHandler *handler, wxEvent &event )
{
if ( m_handler != NULL )
handler = m_handler;
// Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT):
wxASSERT( dynamic_cast< Event * >( &event ) != NULL );
// Will throw a std::bad_cast exception in release build:
( handler->*m_method )( dynamic_cast< Event & >( event ));
}
private:
wxEvtHandler *m_handler;
void ( wxEvtHandler::*m_method )( Event & );
};
// Wrap and unify the creation of the correct functor mainly for the DECLARE_EVENT_TABLE_ENTRY
// but we also can reuse it for the Connect-methods from wxEvtHandler.
// NB: As long as typeof() is not available, we need the unused EventType parameter to deduce
// the correct type and access the associated event):
// Create a functor for the legacy events:
wxEvtFunctor *wxNewEvtFunctor( wxEventType, void ( *function )( wxEvent & ))
{
return ( new wxEvtFunction< wxEvent >( function ));
}
wxEvtFunctor *wxNewEvtFunctor( wxEventType, void ( wxEvtHandler::*method )( wxEvent & ), wxEvtHandler *handler = NULL )
{
return ( new wxEvtMethod< wxEvent, wxEvtHandler >( method, handler ));
}
// Create a functor for the correctly typed events:
template < typename EventType >
wxEvtFunctor *wxNewEvtFunctor( const EventType &, void ( *function )( typename EventType::AssociatedEvent & ))
{
return ( new wxEvtFunction< typename EventType::AssociatedEvent >( function ));
}
template < typename EventType, typename Class >
wxEvtFunctor *wxNewEvtFunctor( const EventType &, void ( Class::*method )( typename EventType::AssociatedEvent & ), wxEvtHandler *handler = NULL )
{
return ( new wxEvtMethod< typename EventType::AssociatedEvent, Class >( method, handler ));
}
Change the wxEventTableEntry to accept a functor as the event handler
If a memory tracer is reporting memory leaks 'before' the destructors for static instances have been executed, then the m_functor will be reported as a memory leak.
struct wxEventTableEntry
{
wxEventTableEntry( const wxEventType &eventType, wxEvtFunctor *functor )
: m_eventType( eventType ), m_functor( functor )
{
}
~wxEventTableEntry()
{
delete m_functor; // Or use auto_ptr<>
}
void Relay( wxEvtHandler *handler, wxEvent &event )
{
m_functor->Relay( handler, event );
}
const wxEventType &m_eventType;
wxEvtFunctor *m_functor;
};
#define DECLARE_EVENT_TABLE_ENTRY(type, fn) \
wxEventTableEntry(type, wxNewEvtFunctor( type, fn ))
Provide new Connect-methods in wxEvtHandler to allow connecting function/methods as event handlers
class wxEvtHandler
{
public:
virtual ~wxEvtHandler()
{
}
// Connect methods to connect functions/methods to an event (if the overhead for the unused eventType is to be
// avoided, then we have to instantiate the wEvtFunction/wxEvtMethod directly):
// Connect legacy event handlers:
void Connect( wxEventType eventType, void ( *function )( wxEvent & ))
{
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, function );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
void Connect( wxEventType eventType, void ( wxEvtHandler::*method )( wxEvent & ), wxEvtHandler *handler = NULL )
{
if ( handler == NULL )
handler = this;
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, method, handler );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
// Connect correctly typed event handlers:
template < typename EventType >
void Connect( const EventType &eventType, void ( *function )( typename EventType::AssociatedEvent & ))
{
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, function );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
template < typename EventType, typename Class >
void Connect( const EventType &eventType, void ( Class::*method )( typename EventType::AssociatedEvent & ), wxEvtHandler *handler = NULL )
{
if ( handler == NULL )
handler = this;
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, method, handler );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
bool ProcessEvent( wxEvent& event )
{
// Relay the event to the 'dynamic' handlers:
for ( Handlers::iterator handler = m_dynamicEventHandlers.begin(); handler != m_dynamicEventHandlers.end(); ++handler ) {
// Is this a handler for the event (first=wxEventType, second=wxEvtFunction)
if ( event == handler->first )
handler->second->Relay( this, event );
}
// Relay the event to the 'static' handlers:
extern wxEventTableEntry sm_staticEventHandlers[];
for ( size_t i = 0; sm_staticEventHandlers[ i ].m_functor != NULL; ++i )
{
if ( event == sm_staticEventHandlers[ i ].m_eventType )
sm_staticEventHandlers[ i ].Relay( this, event );
}
return ( true );
}
private:
typedef list< pair< wxEventType, wxEvtFunctor * > > Handlers;
Handlers m_dynamicEventHandlers;
};
Question/Comments/Suggestions
Please feel free to comment and/or ask questions in this section!
- Missing: Allow boost::function< void (wxTimerEvent & ) > as event handlers.
- <Question>
Complete (GCC-4.2.3 compilable) source code
// Self contained prototype for new/improved event handling
// (c) by Peter Most
//
#include <list>
#include <utility>
#include <cassert>
using namespace std;
#define wxASSERT assert
// The 'legacy' event type:
typedef int wxEventType;
// This is basically the same function as the one in src/event.cpp:
wxEventType wxNewEventType()
{
static int s_lastUsedEventType = 10000;
return ( wxEventType( s_lastUsedEventType++ ));
}
// Template which associates the event type with the correct event:
template < typename Event >
class wxTypedEventType
{
public:
typedef Event AssociatedEvent;
wxTypedEventType( wxEventType type )
{
m_type = type;
}
// Will be needed for the static event tables:
operator const wxEventType &() const
{
return ( m_type );
}
private:
wxEventType m_type;
};
// Legacy event declaration/definition from include/wx/event.h:
#define DECLARE_EVENT_TYPE( name, value ) \
extern const wxEventType name;
// src/event.cpp:
#define DEFINE_EVENT_TYPE( name ) \
const wxEventType name = wxNewEventType();
// Base class for all events from include/wx/event.h:
class wxEvent
{
public:
virtual ~wxEvent()
{
}
wxEvent( wxEventType type )
{
m_type = type;
}
bool operator == ( const wxEvent &other ) const
{
return ( m_type == other.m_type );
}
private:
wxEventType m_type;
};
class wxEvtHandler;
// The functor which will be stored in the static/dynamic tables:
class wxEvtFunctor
{
public:
virtual ~wxEvtFunctor()
{ }
virtual void Relay( wxEvtHandler *handler, wxEvent & ) = 0;
};
template < typename Event >
class wxEvtFunction : public wxEvtFunctor
{
public:
wxEvtFunction( void ( *handler )( Event & ))
{
m_handler = handler;
}
virtual void Relay( wxEvtHandler *, wxEvent &event )
{
// Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT):
wxASSERT( dynamic_cast< Event * >( &event ) != NULL );
// Will throw a std::bad_cast exception in release build:
( *m_handler )( dynamic_cast< Event & >( event ));
}
private:
void ( *m_handler )( Event & );
};
template < typename Event, typename Class >
class wxEvtMethod : public wxEvtFunctor
{
public:
wxEvtMethod( void ( Class::*method )( Event & ), wxEvtHandler *handler )
{
m_handler = handler;
m_method = static_cast< void ( wxEvtHandler::* )( Event & ) >( method );
}
virtual void Relay( wxEvtHandler *handler, wxEvent &event )
{
if ( m_handler != NULL )
handler = m_handler;
// Protect against wrong event i.e. wxMouseEvent evt(wxEVT_PAINT):
wxASSERT( dynamic_cast< Event * >( &event ) != NULL );
// Will throw a std::bad_cast exception in release build:
( handler->*m_method )( dynamic_cast< Event & >( event ));
}
private:
wxEvtHandler *m_handler;
void ( wxEvtHandler::*m_method )( Event & );
};
// Wrap and unify the creation of the correct functor mainly for the DECLARE_EVENT_TABLE_ENTRY
// but we also can reuse it for the Connect-methods from wxEvtHandler.
// NB: As long as typeof() is not available, we need the unused EventType parameter to deduce
// the correct type and access the associated event):
// Create a functor for the legacy events:
wxEvtFunctor *wxNewEvtFunctor( wxEventType, void ( *function )( wxEvent & ))
{
return ( new wxEvtFunction< wxEvent >( function ));
}
wxEvtFunctor *wxNewEvtFunctor( wxEventType, void ( wxEvtHandler::*method )( wxEvent & ), wxEvtHandler *handler = NULL )
{
return ( new wxEvtMethod< wxEvent, wxEvtHandler >( method, handler ));
}
// Create a functor for the correctly typed events:
template < typename EventType >
wxEvtFunctor *wxNewEvtFunctor( const EventType &, void ( *function )( typename EventType::AssociatedEvent & ))
{
return ( new wxEvtFunction< typename EventType::AssociatedEvent >( function ));
}
template < typename EventType, typename Class >
wxEvtFunctor *wxNewEvtFunctor( const EventType &, void ( Class::*method )( typename EventType::AssociatedEvent & ), wxEvtHandler *handler = NULL )
{
return ( new wxEvtMethod< typename EventType::AssociatedEvent, Class >( method, handler ));
}
struct wxEventTableEntry
{
wxEventTableEntry( const wxEventType &eventType, wxEvtFunctor *functor )
: m_eventType( eventType ), m_functor( functor )
{
}
void Relay( wxEvtHandler *handler, wxEvent &event )
{
m_functor->Relay( handler, event );
}
const wxEventType &m_eventType;
wxEvtFunctor *m_functor;
};
#define DECLARE_EVENT_TABLE_ENTRY(type, fn) \
wxEventTableEntry(type, wxNewEvtFunctor( type, fn ))
class wxEvtHandler
{
public:
virtual ~wxEvtHandler()
{
}
// Connect methods to connect functions/methods to an event (if the overhead for the unused eventType is to be
// avoided, then we have to instantiate the wEvtFunction/wxEvtMethod directly):
// Connect legacy event handlers:
void Connect( wxEventType eventType, void ( *function )( wxEvent & ))
{
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, function );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
void Connect( wxEventType eventType, void ( wxEvtHandler::*method )( wxEvent & ), wxEvtHandler *handler = NULL )
{
if ( handler == NULL )
handler = this;
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, method, handler );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
// Connect correctly typed event handlers:
template < typename EventType >
void Connect( const EventType &eventType, void ( *function )( typename EventType::AssociatedEvent & ))
{
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, function );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
template < typename EventType, typename Class >
void Connect( const EventType &eventType, void ( Class::*method )( typename EventType::AssociatedEvent & ), wxEvtHandler *handler = NULL )
{
if ( handler == NULL )
handler = this;
wxEvtFunctor *functor = wxNewEvtFunctor( eventType, method, handler );
m_dynamicEventHandlers.push_back( make_pair( eventType, functor ));
}
bool ProcessEvent( wxEvent& event )
{
// Relay the event to the 'dynamic' handlers:
for ( Handlers::iterator handler = m_dynamicEventHandlers.begin(); handler != m_dynamicEventHandlers.end(); ++handler ) {
// Is this a handler for the event (first=wxEventType, second=wxEvtFunction)
if ( event == handler->first )
handler->second->Relay( this, event );
}
// Relay the event to the 'static' handlers:
extern wxEventTableEntry sm_staticEventHandlers[];
for ( size_t i = 0; sm_staticEventHandlers[ i ].m_functor != NULL; ++i )
{
if ( event == sm_staticEventHandlers[ i ].m_eventType )
sm_staticEventHandlers[ i ].Relay( this, event );
}
return ( true );
}
private:
typedef list< pair< wxEventType, wxEvtFunctor * > > Handlers;
Handlers m_dynamicEventHandlers;
};
extern const wxTypedEventType< wxEvent > wxEVT_NULL;
const wxTypedEventType< wxEvent > wxEVT_NULL( 0 );
// A new/typesafe wxWidgets event:
class wxTimerEvent : public wxEvent
{
public:
wxTimerEvent( wxEventType eventType )
: wxEvent( eventType )
{ }
};
// The timer event handler without any casts:
#define wxTimerEventHandler( func ) ( &func )
extern const wxTypedEventType< wxTimerEvent > wxEVT_TIMER;
const wxTypedEventType< wxTimerEvent > wxEVT_TIMER( wxNewEventType() );
// An old/user defined event type:
class wxColorEvent : public wxEvent
{
public:
wxColorEvent( wxEventType eventType )
: wxEvent( eventType )
{ }
};
// Two possible ways how the event can be declared:
extern const wxEventType wxEVT_BLUE;
DECLARE_EVENT_TYPE( wxEVT_BLUE, 0 )
DEFINE_EVENT_TYPE( wxEVT_BLUE )
// The color event handler with a lot of casts:
typedef void (wxEvtHandler::*wxColorEventFunction)(wxColorEvent&);
typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&);
typedef wxEventFunction wxObjectEventFunction;
#define wxColorEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)static_cast< wxColorEventFunction >( &func )
// Some functions as event handlers:
void handleTimerEventFunction( wxTimerEvent &event )
{
printf( "::handleTimerEventFunction( wxTimerEvent & )\n" );
}
void handleColorEventFunction( wxColorEvent &event )
{
printf( "::handleColorEventFunction( wxColorEvent & )\n" );
}
// An event handler which uses it's own methods as handlers:
class MyEventHandler : public wxEvtHandler
{
public:
MyEventHandler()
{
Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handleTimerEventMethod ));
Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleColorEventMethod ));
}
void handleTimerEventMethod( wxTimerEvent &event )
{
printf( "MyEventHandler::handleTimerEventMethod( wxTimerEvent & )\n" );
}
void handleColorEventMethod( wxColorEvent &event )
{
printf( "MyEventHandler::handleColorEventMethod( wxColorEvent & )\n" );
}
};
// Another event handler which uses the base class methods as handlers:
class MyDerivedEventHandler : public MyEventHandler
{
public:
MyDerivedEventHandler()
{
Connect( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod ));
Connect( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod ));
}
};
wxEventTableEntry sm_staticEventHandlers[] =
{
DECLARE_EVENT_TABLE_ENTRY( wxEVT_TIMER, &handleTimerEventFunction ),
DECLARE_EVENT_TABLE_ENTRY( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod )),
DECLARE_EVENT_TABLE_ENTRY( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod )),
// Must not compile
// DECLARE_EVENT_TABLE_ENTRY( wxEVT_BLUE, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod )),
// Mark the end of the table ie: END_EVENT_TABLE()
wxEventTableEntry( wxEVT_NULL, NULL )
};
int main( void )
{
//
// should compile:
//
wxEvtHandler eventProvider;
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( handleTimerEventFunction ));
MyEventHandler eventHandler;
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handleTimerEventMethod ));
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handleTimerEventMethod ), &eventHandler);
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleColorEventMethod ));
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleColorEventMethod ), &eventHandler );
MyDerivedEventHandler derivedEventHandler;
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod ));
eventProvider.Connect( wxEVT_TIMER, wxTimerEventHandler( MyDerivedEventHandler::handleTimerEventMethod ), &derivedEventHandler );
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod ));
eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyDerivedEventHandler::handleColorEventMethod ), &derivedEventHandler );
// Must not compile:
// eventProvider.Connect( wxEVT_BLUE, &handleTimerEventFunction );
// eventProvider.Connect( wxEVT_BLUE, wxColorEventHandler( MyEventHandler::handleTimerEventMethod ));
// Send an event:
wxTimerEvent timerEvent( wxEVT_TIMER );
eventProvider.ProcessEvent( timerEvent );
// Send an illegal event (leads to an ASSERT in wxEvtFunction<Event>::Relay):
wxColorEvent colorEvent( wxEVT_TIMER );
eventProvider.ProcessEvent( colorEvent );
return ( 0 );
}