Original Post
Comments for the article Simple Event Handling
/*! \class CEvent * \brief The Basic EventNotifier class, all other events must be derived from it * \date April-2004 * \version 0.1Beta * \code * //example use * class CPlayer : public ReCore::CEvent{ * public: * INT iFile; * CPlayer(){iFile = 0;}; * bool CanRemoveEvent(){return true;}; * INT NotifyEvent(INT iReason,void *data,INT iDataLen); * }; * INT CPlayer::NotifyEvent(INT,void*,INT){ * ............ * ............ * return 1; * } * \endcode */ class CEvent{ public: /*! \brief Notifier function * \param iReason why is the event signaled * \param pData a pointer for any data being passed to the event * \param iDataLen the lenght of the data being passed * \return a positive int on success */ virtual int NotifyEvent(int iReason, void *pData, int iDataLen)=0; //! \brief This is for event lists/quiees, usually returns true virtual bool CanRemoveEvent()=0; //! \brief Function operator, allows an easier execution of the event INT operator () () { return this->NotifyEvent(EventTriggered,NULL,0); }; /*! \brief An enum of the most basic event reasons * \note * Any custom reasons must be greater than the * highest value in this list or smaller than * the smallest value */ enum EReason{ EventTriggered = 1, EventDestroy = 2, EventImpossible = 3, EventOnError = 4, EventOnWarning = 5, EventOnStop = 6, EventOnStart = 7, EventOnFail = 8, EventOnPlay = 9, EventOnPause =10, EventOnResume =11, EventOnOpen =12, EventOnClose =13, EventOnDestroy =14, EventOnDone =15, EventOnMouseMove =16, EventOnLClick =17, EventOnRClick =18, EventOnMClick =19, EventOnMouseWheel =20, EventOnKeyDown =21, EventOnKeyUp =22, EventOnNetConnect =23, EventOnNetDisconnect=24, EventOnNetRecieve =25, EventOnNetError =26, EventOnNetPacketLost=27, }; }; const int CEventFirst= CEvent::EReason::EventTriggered; const int CEventLast = CEvent::EReason::EventOnNetPacketLost;Quote:
There are certain performance issues to consider when using this system. Spending too much time in the EventHandler methods basically slows down the overall event dispatching.
class EventDispatcher{...stuff struct node { IEventHandler *handler; node *next; } *head;...more stuff};#pragma once//Purpose://if any of ur class wanna respond to ur global custom event,make it derived from this class//and overload the virtual function ProcessEvent() to process ur event//call XEventHandler::Dispatch() whenever u wanna dispatch an event//Extention://u can add event type in enum EVENT_TYPE of this class and define it's relative arg,context in ur docs//Remarks://I name the class which derived from this class "device",it means device can respond to eventsclass XEventHandler{ static XEventHandler* m_pDeviceList; XEventHandler* m_pNext;public: struct EVENT { DWORD dwEventType; DWORD dwArg; LPVOID pContext; EVENT(); EVENT(DWORD eventType, DWORD arg, LPVOID context) { dwEventType=eventType; dwArg=arg; pContext=context; } }; enum EVENT_TYPE { };public: XEventHandler(void); ~XEventHandler(void); static void Dispatch(DWORD eventType, DWORD arg=0, LPVOID context=NULL);protected: static void AddDevice(XEventHandler* pDevice); static void RemoveDevice(XEventHandler* pDevice); virtual void ProcessEvent(EVENT event)=0;};#include "StdAfx.h"#include ".\xeventhandler.h"XEventHandler* XEventHandler::m_pDeviceList;XEventHandler::XEventHandler(void){ m_pNext=NULL; AddDevice(this);}XEventHandler::~XEventHandler(void){ RemoveDevice(this);}void XEventHandler::Dispatch(DWORD eventType, DWORD arg, LPVOID context){ EVENT event(eventType,arg,context); for(XEventHandler* p=m_pDeviceList; p; p=p->m_pNext) p->ProcessEvent(event);}void XEventHandler::AddDevice(XEventHandler* pDevice){ if(m_pDeviceList) { XEventHandler* pre=m_pDeviceList; for(XEventHandler* p=m_pDeviceList; p; p=p->m_pNext) pre=p; pre->m_pNext=pDevice; } else { m_pDeviceList=pDevice; }}void XEventHandler::RemoveDevice(XEventHandler* pDevice){ XEventHandler* pre=NULL; for(XEventHandler* p=m_pDeviceList; p;) { if(p == pDevice) { if(p == m_pDeviceList) { m_pDeviceList=m_pDeviceList->m_pNext; p=m_pDeviceList; pre=p; } else { pre->m_pNext=p->m_pNext; p=p->m_pNext; } } else { pre=p; p=p->m_pNext; } }}//event.cpp#include <string>#include <iostream>struct Event;struct EventMouseLeftButtonPress;struct EventMouseLeftButtonRelease;struct EventNewGameEasy;//etcstruct EventHandlerImpl { virtual void OnHandle(Event&) { std::cout << "EventHandlerImpl::Event: do nothing" << std::endl; } virtual void OnHandle(EventMouseLeftButtonPress&) { std::cout << "EventHandlerImpl::EventMouseLeftButtonPress: do nothing" << std::endl; } virtual void OnHandle(EventMouseLeftButtonRelease&) { std::cout << "EventHandlerImpl::EventMouseLeftButtonRelease: do nothing" << std::endl; } virtual void OnHandle(EventNewGameEasy&) { std::cout << "EventHandlerImpl::EventNewGameEasy: do nothing" << std::endl; } //etc.};struct EventHandler { EventHandler(EventHandlerImpl* pImpl) : m_pImpl(pImpl) { } void Handle(Event& event) { m_pImpl->OnHandle(event); } void Handle(EventMouseLeftButtonPress& event) { m_pImpl->OnHandle(event); } void Handle(EventMouseLeftButtonRelease& event) { m_pImpl->OnHandle(event); } void Handle(EventNewGameEasy& event) { m_pImpl->OnHandle(event); } //etc.private: EventHandlerImpl* m_pImpl; EventHandler(const EventHandler&); EventHandler& operator=(const EventHandler&);};struct Event { virtual void Accept(EventHandler& handler) { handler.Handle(*this); }};struct EventMouseLeftButtonPress : Event { EventMouseLeftButtonPress(int x, int y) : m_x(x), m_y(y) { } void Accept(EventHandler& handler) { handler.Handle(*this); } int m_x, m_y;};struct EventMouseLeftButtonRelease : Event { EventMouseLeftButtonRelease(int x, int y) : m_x(x), m_y(y) { } void Accept(EventHandler& handler) { handler.Handle(*this); } int m_x, m_y;};struct EventNewGameEasy : Event { EventNewGameEasy(const std::string& name) : m_name(name) { } void Accept(EventHandler& handler) { handler.Handle(*this); } std::string m_name;};struct EventHandlerA : EventHandlerImpl { virtual void OnHandle(EventMouseLeftButtonPress& event) { std::cout << "mouse left button down at " << event.m_x << " " << event.m_y << std::endl; } virtual void OnHandle(EventMouseLeftButtonRelease& event) { std::cout << "mouse left button up at " << event.m_x << " " << event.m_y << std::endl; }};struct EventHandlerB : EventHandlerImpl { virtual void OnHandle(EventNewGameEasy& event) { std::cout << "new game easy setting, player name: " << event.m_name << std::endl; }};int main() { EventHandler a(new EventHandlerA); EventHandler b(new EventHandlerB); EventMouseLeftButtonPress e1(30, 17); EventNewGameEasy e2("quorn"); EventMouseLeftButtonRelease e3(50, 29); a.Handle(e1); b.Handle(e1); a.Handle(e2); b.Handle(e2); a.Handle(e3); b.Handle(e3); return 0;}
Every class that wants to listen to events needs to inherent from IEventHandler, and needs to implement the EventHandler virtual function. A typical implementation of this method will have a switch statement (switching on the Event.Type variable), and will have a case statement for any events the class wants to handle. Here's a short example:
void Foo::EventHandler(const Event &e) {
switch (e.Type) {
case E_NEWGAMEEASY:
// handle creating a new easy game.
break;
case E_MOUSELEFTBUTTONPRESS:
// handle mouse button being pressed
break;
default:
break;
}
}
Note that function pointers will do a better job here than a switch-case block.
See the following articles for a quick rundown on function pointers:
http://www.newty.de/fpt/intro.html#what
http://www.gamedev.net/reference/articles/article2116.asp
This topic has been locked by a moderator. New replies are not allowed.
With your permission, GameDev.net uses analytics cookies to understand how people use the platform. You can accept analytics or continue with necessary cookies only. Learn more