[wx-dev] RFC improved event handling (minor changes)

Brian Vanderburg II BrianVanderburg2 at aim.com
Wed Jul 30 05:11:25 PDT 2008


I've made some minor changes to your code to get a few cases working:

1.  Two different connects for members.  The first one expects the =

handler object to be the same class as the handler function.  The second =

allows the handler object to be derived from the class containing the =

handler function.

2.  Type safety is only guaranteed if a handler object is passed.  If =

you do window.Connect(wxEVT_BLUE, &MyEventHandler::onHandleColor ), type =

casting is done converting 'this' to MyEventHandler but window is only =

wxEvtHandler, so MyEventHandler::onHandleColor will get called with a =

'this' pointer only pointing to wxEvtHandler, not MyEventHandler.

I've attached the changes to this file, with some comments where I've =

made changes.

Brian Vanderburg II


-------------- next part --------------
// Self contained prototype for new/improved event handling
// (c) by Peter Most
//
#include <list>
#include <utility>

using namespace std;


// This is the same function as the one in src/event.cpp:

int wxNewEventType()
{
    static int s_lastUsedEventType =3D 10000;

    return s_lastUsedEventType++;
}



class wxEventType {
    public:
        wxEventType()
        {
            m_value =3D wxNewEventType();
        }

        bool operator =3D=3D ( const wxEventType &other ) const
        {
            return ( m_value =3D=3D other.m_value );
        }

    private:
        int m_value;
};

// The templatized event type:

template < typename Event >
class wxEventTypeTemplate : public wxEventType {
    public:
        typedef Event AssociatedEvent;
};



// The new macro which associates the event type with the event it delivers:

#define DEFINE_NEW_EVENT_TYPE( name, event ) \
    const wxEventTypeTemplate< event > name;


// The 'old' macro for backward compatibility:

#define DEFINE_EVENT_TYPE( name ) \
    DEFINE_NEW_EVENT_TYPE( name, wxEvent )



// Base class for all events from include/wx/event.h:
        =

class wxEvent {
    public:
        wxEvent( wxEventType type )
        {
            m_type =3D type;
        }

        bool operator =3D=3D ( const wxEvent &other ) const
        {
            return ( m_type =3D=3D other.m_type );
        }

    private:
        wxEventType m_type;
};



// A legacy event from include/wx/timer.h:

class wxTimerEvent : public wxEvent {
    public:
        wxTimerEvent( wxEventType eventType )
            : wxEvent( eventType )
        { }
};

DEFINE_EVENT_TYPE( wxEVT_TIMER )
// If the folling line is activated and the line above deactivated, then the
// 'old' way of defining event handler doesn't compile anymore, which IMO i=
s a
// good thing.
//
// DEFINE_NEW_EVENT_TYPE( wxEVT_TIMER, wxTimerEvent )




// A 'new' type event:
    =

class wxColorEvent : public wxEvent {
    public:
        wxColorEvent( wxEventType eventType )
            : wxEvent( eventType )
        { }
};

DEFINE_NEW_EVENT_TYPE( wxEVT_BLUE,  wxColorEvent )
DEFINE_NEW_EVENT_TYPE( wxEVT_WHITE, wxColorEvent )


class wxEvtFunctor {
    public:
        virtual ~wxEvtFunctor()
        { }

        virtual void operator()( wxEvent & ) =3D 0;
};



template < typename EventType >
    class wxEvtFunction : public wxEvtFunctor {
        public:
            wxEvtFunction( void ( *handler )( typename EventType::Associate=
dEvent & ))
            {
                m_handler =3D handler;
            }

            virtual void operator()( wxEvent &event )
            {
                ( *m_handler )( static_cast< typename EventType::Associated=
Event & >( event ));
            }

        private:
            void ( *m_handler )( typename EventType::AssociatedEvent & );
    };

            =


template < typename EventType, typename Class >
    class wxEvtMethod : public wxEvtFunctor {
        public:
            wxEvtMethod( Class *handler, void ( Class::*method )( typename =
EventType::AssociatedEvent & ))
            {
                m_handler =3D handler;
                m_method =3D method;
            }

            virtual void operator()( wxEvent &event )
            {
                ( m_handler->*m_method )( static_cast< typename EventType::=
AssociatedEvent & >( event ));
            }

        private:
            Class *m_handler;
            void ( Class::*m_method )( typename EventType::AssociatedEvent =
& );
    };



class wxEvtHandler {
    public:
        // Connect method for connecting normal functions to an event:

        template < typename EventType >
            void Connect( const EventType &event, void ( *handler )( typena=
me EventType::AssociatedEvent & ))
            {
                wxEvtFunctor *functor =3D new wxEvtFunction< EventType >( h=
andler );
                m_handlers.push_back( make_pair( event, functor ));
            }

        // Connect methods for connecting methods to an event:


        // this method is used if no handler is passed or if the passed han=
dler is of the same type as Class
        template < typename EventType, typename Class >
            void Connect( const EventType &event, void ( Class::*method )( =
typename EventType::AssociatedEvent & ), Class *handler =3D 0 )
            {
                if ( handler =3D=3D 0 )
                    handler =3D static_cast< Class * >( this );

                wxEvtFunctor *functor =3D new wxEvtMethod< EventType, Class=
 >( handler, method );
                m_handlers.push_back( make_pair( event, functor ));
            }

        // this method is used if the passed handler is derived from Class
        template < typename EventType, typename Class, typename Derived >
            void Connect( const EventType &event, void ( Class::*method )( =
typename EventType::AssociatedEvent & ), Derived *handler )
            {
                wxEvtFunctor *functor =3D new wxEvtMethod< EventType, Class=
 >( handler, method );
                m_handlers.push_back( make_pair( event, functor ));
            }

        bool ProcessEvent( wxEvent& event )
        {
            for ( Handlers::iterator handler =3D m_handlers.begin(); handle=
r !=3D m_handlers.end(); ++handler ) {
                // Is this a handler for the event (first=3DwxEventType, se=
cond=3DwxEvtFunctor)
                if ( event =3D=3D handler->first )
                    ( *handler->second )( event );
            }
        }

    private:
        typedef list< pair< wxEventType, wxEvtFunctor * > > Handlers;
        Handlers m_handlers;
};


// Duplicated typedefs from include/wx/event.h and include/wx/timer.h

typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&);
typedef wxEventFunction wxObjectEventFunction;
typedef void (wxEvtHandler::*wxTimerEventFunction)(wxTimerEvent&);

#define wxTimerEventHandler(func) \
    (wxObjectEventFunction)(wxEventFunction)static_cast< wxTimerEventFuncti=
on >( &func )

void handleColorEvent( wxColorEvent &event )
{
}



void handleTimerEvent( wxTimerEvent &event )
{
}



class MyEventHandler : public wxEvtHandler {
    public:
        MyEventHandler()
        {
            Connect( wxEVT_BLUE, &MyEventHandler::handleColorEvent );
            Connect( wxEVT_WHITE, &MyEventHandler::handleColorEvent );

            Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::hand=
leTimerEvent ));

            // If wxEVT_TIMER becomes a 'new' event, then this line has to =
be used:
            // Connect( wxEVT_TIMER, &MyEventHandler::handleTimerEvent );
        }

        void handleColorEvent( wxColorEvent &event )
        {
        }

        void handleTimerEvent( wxTimerEvent &event )
        {
        }

};

class DerivedEventHandler : public MyEventHandler
{
public:
    void handleRealColorEvent( wxColorEvent& evt )
    {
    }
};



int main( void )
{
    //
    // should compile:
    //
    wxEvtHandler window;
    window.Connect( wxEVT_WHITE, &handleColorEvent );
    window.Connect( wxEVT_BLUE,  &handleColorEvent );

    window.Connect( wxEVT_TIMER, reinterpret_cast< void ( * )( wxEvent & ) =
>( &handleTimerEvent ));
    //
    // Would be nice if these would compile, but don't see how, without sac=
rificing type safety:
    //
    // window.Connect( wxEVT_TIMER, &handleTimerEvent );
    // window.Connect( wxEVT_TIMER, &MyEventHandler::handleTimerEvent, &rec=
eiver );

    MyEventHandler receiver;
    window.Connect( wxEVT_BLUE,  &MyEventHandler::handleColorEvent, &receiv=
er );
    window.Connect( wxEVT_WHITE, &MyEventHandler::handleColorEvent, &receiv=
er );

    window.Connect( wxEVT_TIMER, reinterpret_cast< void ( MyEventHandler::*=
 )( wxEvent & ) >( &MyEventHandler::handleTimerEvent ), &receiver );

    // This line doesn't compile, probably because it tries to cast to wxEv=
tHandler
    // It doesn't compile because no template matches.  It expects Class to=
 be wxEvtHandler, but
    // receiver is MyEventHandler so the first Connect for members does not=
 match.
    // Change: This line now compiles because of the second Connect for mem=
bers
    window.Connect( wxEVT_TIMER, wxTimerEventHandler( MyEventHandler::handl=
eTimerEvent ), &receiver );

    //
    // must not compile:
    //
    =

    // window.Connect( wxEVT_TIMER, &handleColorEvent );
    // window.Connect( wxEVT_TIMER, &MyEventHandler::handleColorEvent, &rec=
eiver );

    //
    // Send an event:
    //
    wxColorEvent colorEvent( wxEVT_BLUE );
    window.ProcessEvent( colorEvent );


    // This originally will not compile without the second Connect for memb=
ers
    DerivedEventHandler receiver2;
    window.Connect( wxEVT_BLUE, &MyEventHandler::handleColorEvent, &receive=
r2 );


    // other tests
    window.Connect( wxEVT_BLUE, &DerivedEventHandler::handleRealColorEvent,=
 &receiver2 );
    receiver2.Connect( wxEVT_BLUE, &DerivedEventHandler::handleRealColorEve=
nt );
    receiver2.Connect( wxEVT_BLUE, &MyEventHandler::handleColorEvent );

    // type safety test
    // Problem: casting wxEvtHandler to DerivedEventHandler
    // this is pointer to wxEvtHandler but cast converts to DerivedEventHan=
dler so
    // DerivedEventHandler::handleRealColorEvent will get a 'this' pointer =
to
    // a wxEvtHandler object
    window.Connect( wxEVT_BLUE, &DerivedEventHandler::handleRealColorEvent =
);
    receiver.Connect( wxEVT_BLUE, &DerivedEventHandler::handleRealColorEven=
t );
    // Should be written as
    window.Connect( wxEVT_BLUE, &DerivedEventHandler::handleRealColorEvent,=
 &receiver2 );
    receiver.Connect( wxEVT_BLUE, &DerivedEventHandler::handleRealColorEven=
t, &receiver2 );    =



}




More information about the wx-dev mailing list