Sign in to follow this  
aaronjbaptiste

Problems with my Event handling

Recommended Posts

aaronjbaptiste    100
Hi all, I have not long got my event system working, it's based on the article: http://www.gamedev.net/reference/programming/features/effeventcpp/ However I have hit a brick wall in relation to hasEventListener and removeEventListener features. Basically any object can extend the EventDispatcher class which gives it the ability to store a multimap of <string eventType> -> <member function>. When you call the method disaptchEvent(Event e) on this object, it does a find in the multi map for all listeners listening for Event e and calls their respective member functions. So far so good. The problem is when you try to query that multi map or remove from it. I want to be able to do something like hasEventListener("mouseOver", PanelClass, &PanelClass::handleEvent), which returns true if that specific element exists within the multi map (both key AND value pair). I also want to do removeEentListener(...same params) which removes a specific key value pair. Ok, so why not iterate through the list (or use find) and check the key and value is equal to parameters..... This is what I thought I would do. However the value is stored as a wrapped up HandlerFunctionBase object, which only knows how to do execute(). There is no getMemberFunction() or getInstanceObject() and I cant add these because the whole point of it being a wrapper is to wrap the specific object types away. Ok enough abstract stuff, ill post the code for a clearer view: Note: Ive removed destructor, constructors, includes and header guards. The commented out code is how I thought about achieving this. However HandlerFunctionBase has no getMemberFunction()... EventDispatcher.h
class EventDispatcher
{
	public:
		template <typename ObjectT, typename EventT>
		void addEventListener(std::string a_EventType, ObjectT* a_Instance, void (ObjectT::*a_pMemberFunction)(const EventT*))
		{
			m_Listeners.insert(std::pair<std::string,HandlerFunctionBase*>(a_EventType,new MemberFunctionHandler<ObjectT, const EventT>(a_Instance, a_pMemberFunction)));
		}

		template <typename ObjectT, typename EventT>
		void removeEventListener(std::string a_EventType, ObjectT* a_Instance, void (ObjectT::*a_pMemberFunction)(const EventT*))
		{
			/*std::pair<std::multimap<std::string, HandlerFunctionBase*>::const_iterator, std::multimap<std::string, HandlerFunctionBase*>::const_iterator> bound = m_Listeners.equal_range(a_EventType);
			std::multimap<std::string, HandlerFunctionBase*>::const_iterator it;

			for (it=bound.first; it!=bound.second; ++it)
			{
				if((*it).second->getMemberFunction() == a_pMemberFunction)
				{
					m_Listeners.erase(it);
					bound = m_Listeners.equal_range(a_EventType);
				}
			}*/
		}

		template <typename ObjectT, typename EventT>
		bool hasEventListener(std::string a_EventType, ObjectT* a_Instance, void (ObjectT::*a_pMemberFunction)(const EventT*))
		{
			bool hasListener = false;
			/*std::pair<std::multimap<std::string, HandlerFunctionBase*>::const_iterator, std::multimap<std::string, HandlerFunctionBase*>::const_iterator> bound = m_Listeners.equal_range(a_EventType);
			std::multimap<std::string, HandlerFunctionBase*>::const_iterator it;

			for (it=bound.first; it!=bound.second; ++it)
			{
				if((*it).second->getMemberFunction() == a_pMemberFunction)
				{
					hasListener = true;
					break;
				}
			}*/

			return hasListener;
		}

		virtual void dispatchEvent(Event* a_Event);

	private:
		std::multimap<std::string, HandlerFunctionBase*> m_Listeners;
};



EventDispatcher.cpp

void EventDispatcher::dispatchEvent(Event* a_Event)
{

	std::string eventType = a_Event->getType();
	std::pair<std::multimap<std::string, HandlerFunctionBase*>::const_iterator, std::multimap<std::string, HandlerFunctionBase*>::const_iterator> bound = m_Listeners.equal_range(eventType);
	std::multimap<std::string, HandlerFunctionBase*>::const_iterator it;

	for (it=bound.first; it!=bound.second; ++it)
	{
		(*it).second->execute(a_Event);
		bound = m_Listeners.equal_range(eventType);
	}
}



HandlerFunctionBase.h
class HandlerFunctionBase
{
	public:

		void execute(const Event* a_Event) 
		{
			call(a_Event);
		}
	private:
		virtual void call(const Event* a_Event) = 0;
};



MemberFunctionHandler.h
template <typename ObjectT, typename EventT>
class MemberFunctionHandler : public HandlerFunctionBase
{
	public:
		typedef void (ObjectT::*MemberFunction)(const EventT*);

		MemberFunctionHandler(ObjectT* a_Instance, MemberFunction a_MemberFunction): 
		m_Instance(a_Instance), m_MemberFunction(a_MemberFunction) {};

		void call(const Event* a_Event)
		{
			(m_Instance->*m_MemberFunction)(static_cast<EventT*>(a_Event));
		}

	private:
		ObjectT* m_Instance;
		MemberFunction m_MemberFunction;
};



Should I just dynamic cast the HandlerFunctionBase to MemberFunctionHandler and add the getMemberFunction() to that? Or is there a better solution? Also feel free to critique the code/style/my life in general. Thanks! Aaron

Share this post


Link to post
Share on other sites
aaronjbaptiste    100
No ideas?

Am I going about this the wrong way?

A solution that doesn't involve casting could be to use covariants. So in the base class I could add:

HandlerFunctionBase.h

virtual HandlerFunctionBase* getFunctionHandler() = 0;



MemberFunctionHandler.h

virtual MemberFunctionHandler* getFunctionHandler() {return this;}
MemberFunction getMemberFunction() {return m_MemberFunction;}



So to get the wrapped up member function I could use:


MemberFunctionHandler* mfh = (*it).second->getMemberFunctionHandler();



Is covariants ok to use in this situation? Or should I go with dynamic_cast? Or does anybody want to step up to the plate and lay down a better solution?

Thanks

Aaron

Share this post


Link to post
Share on other sites
aaronjbaptiste    100
The above didn't work out too well, because of the templates things started getting a bit messy.

So ive got it working using dynamic_cast:


MemberFunctionHandler<ObjectT, const EventT>* mfh = dynamic_cast<MemberFunctionHandler<ObjectT, const EventT>*>((*it).second);



Its only called when querying for an event listener or removing one, I dont think that would be very often so I'm ok with the performance loss. Is there any other reason I shouldn't be doing the dynamic_cast? Could I possibly make that a static_cast instead?

Feel free to comment on the design

Thanks

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this