This is how I'm doing event handling, although it makes heavy use of boost smart pointers.
// in cpp filevoid Window::AddListener(renwin::event_t e, renwin::ALPtr_t a){ actMap[e].push_back(ALWeakPtr_t(a));}void Window::FireEvent(renwin::event_t e){ typedef ALList_t::iterator it_t; ALPtr_t p; for (it_t i=actMap[e].begin();i!=actMap[e].end();i++) { // get shared_ptr to action listener p=i->lock(); // if the object still exists then call it's () operator if (!i->expired()) p->operator ()(); else // else-wise remove it from the action listener map actMap[e].erase(i); }}// in header filenamespace renwin // render window namespace{ class ActionListener { public: virtual ~ActionListener() = 0; // event trigger function, called on firing of event virtual void operator()() = 0; };};// sample action listener for quit messages, sets isAlive to false on messageclass QuitListener : public ActionListener{public: QuitListener() : isAlive(true) {}; ~QuitListener() {}; void operator()() { isAlive=false; }; // returns true if associated message has not yet fired bool IsAlive();private: volatile bool isAlive;};typedef boost::shared_ptr<ActionListener> ALPtr_t; // action listener pointer typetypedef boost::weak_ptr<ActionListener> ALWeakPtr_t; // action listener weak pointer typetypedef std::list<ALWeakPtr_t> ALList_t; // action listener list typetypedef std::vector<ALList_t> ALLstMap_t; // action listener map type// EVENTSenum event_t{ FOCUS=0, BLUR, QUIT, RESIZE, //... NUMBER_OF_EVENTS // number of event types};// inside the Window class definitionclass Window{//... ALLstMap_t actMap; // map of action listeners};
When an event occurs my Window class calls "FireEvent(event)," for example when the quit message occurs it calls "FireEvent(QUIT)."
Action listeners that need to be informed of events being fired are added by calling "Window.AddListener(event,actionListernObjectSharedPoitner)" and they are removed auto-magically by boost shared_ptr when all external references go out of scope. This is because the shared_ptr is reference counted and the weak_ptr becomes null when all shared_ptr's to the same object do. That way I can keep a reference to the action listener and ensure not only that it gets deleted when it goes out of scope, but also ensure that the window's reference automatically becomes null when that happens.
I left out most multi-threading code although I believe that "p=i->lock();" can be replaced with "p=i;" if you don't need thread safety.
I like this approach for the following reasons:
1) The most complex parts are handled by a very stable and proven library, boost.
2) The exposed interface is dead simple
AddListener(event,actionListenerObjectSharedPoitner)
3) Removal of action listerners (you could call them even listeners) is autmatic
4) The user can define how they retrieve notification by the definition of the "()" operator function and the custom actionListener object.
5) NO STRINGS are used anywhere in this system, just define enums. If you need strings for scripts to work, then just make a function that translates the strings into numbers. Numeric ID's are far more efficient than strings.
It does have short comings, namely:
1) Each custom actionListener object must have a thread safe "()" operator (if multi-threading is used)
2) No parameters are passed to the actionListener (this could be changed but my Window class can be queried for all sorts of data, so I didn't bother)
3) Requires boost libraries
4) Depends on dynamically bound polymorphic types
*edit*
I just took the time to look at
boost singals and I think it's a better solution although there still work involved in implementing it in a manner equivalent to my example.
[Edited by - T1Oracle on July 10, 2007 9:44:08 AM]