CEGUI中的事件系统

时间:2022-10-09 23:43:32

     在CEGUI中,要让一个对像能响应事件那么他必须继承EventSet类。EventSet是该对象所被注册的事件集。

    与事件相关的类型:

    EventSet:Event的一个集合,管理event对象,拥有一个 std::map<String, Event*, String::FastLessCompare>  的event集合,那么当产生一个事件的时候,我们就可以通过名字去掉用到对应的处理函数。

    Event:一个slot的集合,管理他自己的slot(SubscriberSlot), 用std::multimap<group, Connection>来存储slot   Connection 是BoundSlot实例化RefCounted类的的typedef

他可以被普通函数,成员函数,函数对象订阅(要求是:他们的函数形式必须是bool functionName(const EventArgs& args))。

    BoundSlot/Connection:维护一个SubscriberSlot(订阅者)和一个Event对象的关系。

    SubscriberSlot/Subscriber:一个各种functor的包装类, functor类比较简单,就是一个类似函数的功能。

 

    事件注册过程:

    在EventSet中有个virtual Event::Connetction subscribeEvet 函数参数:const String, EVent::Group, Event::Subscriber 意义是eventName, groupID, subscriber

    EventSet中的注册函数先在evetn map中通过名字找到event对象(如果不存在则会添加一个pair), 然后调用event的subscribe(以subscriber为参数)

    在Event中的subscribe函数中以传进来的subscriber groupID *this作为参数new出一个BoundSlot对象,再以该对象去初始化模板类的一个变量,之后再把该变量插入到slot multimap中。到此就完成了一个事件的注册过程

  注意的几个问题: 在调用EventSet的subscribeEvent时传进来的subscriber在new BoundSlot的时候,BoundSlot才用它作为参数调用subscriber的copy constructor 来new出一个subscriber给BoundSlot自己用。

 在注册过程中注册函数都有重载,一个有groupID参数一个没有。但在最后插入到Event的slot 集合中时,如果没有groupID则默认为-1。

一个event对象他可以对应多个处理函数,当我们给某个对象注册一个事件的时候,如果该事件对象已经存在,那么我们就在该事件对象的处理函数列表中添加该处理函数就可以了,如果不存在该名字的事件对象那么我们就需要先创建该事件对象再把相应的处理函数加入其中。当有相应的事件发生了的时候,如果再某个对象的事件集中不存在对应的时间对象,那他直接返回什么也不做。

 

简单代码描述

BoundSlot: Group d_group; SubscriberSlot* d_subscriber; Event* d_event;  //构造函数也以这三个类型作为参数  他只是简单的维护一个订阅者与事件之间的那层关系

BoundSlot::connnect: d_subscriber->connected(); //查看该订阅者是否有相应的响应事件

BoundSlot::disconnected: if connected then d_subscriber->cleanup; if d_event then d_event->unsubscribe(*this);  //清楚订阅者的相应事件, 并在event中去掉该订阅

注意上面unsubscribe是Event的私有函数,这里之所以能通过event对象调用该函数是因为在Event中申明了BoundSlot::disconnetct为friend

 

SubscriberSlot: SlotFunctorBase* d_functor_impl;                            //

SubscriberSlot::operator()(const EventArgs& args): renturn (*d_functor_impl)(args);  //这是个需函数

SubscriberSlot::connected: return d_functor_impl != 0;

SubscriberSlot::cleanup: delete d_functor_impl; d_functor_impl = 0;

对于订阅者来说他所绑定到的函数对象有5种:FreeFunctionSlot; FunctorCopySlot;FunctorPointerSlot;FunctorReferenceSlot;MemberFunctionSlot

 

Event: typedef RefCounted<BoundSlot> Connection; typedef CEGUI::SubscriberSlot Subscriber; multimap<Group, Connection> d_slots; String d_name

Event::subscribe(const Subscriber& slot): return subscribe(static_cast<Group>(-1), slot);

Event::subscribe(Group group, const Subscriber slot): Connection c(new BoundSlot(group, slot, *this)); d_slots.insert(pair<Group, Connetction>(group, c); return c;

Event::unsubscribe(const BoundSlot& slot): find(slot); d_slots.erase(curr);

Event::operator()(EventArgs& args): 对于每个connection 执行 c->d_subscriber(args)

 

EventSet: map<String, Event*, String::FastLessCompare> d_events;      //事件一个对象所能相应的事件集合

EventSet::addEvent(name): if not isEventPresent(name) then d_event[name] = new Event(name);

EventSet::removeEvent(name): if found(name) then delete pos->second; d_events.erase(pos);

EventSet::subscribeEvent(name, subscriber): return getEventObject(name, true)->subscribe(subscriber);

EventSet::fireEvent(name, group, eventNameSpace): GlobalEventSet::getSingleton().fireEvent(name, args, eventNamespace); fireEvent_impl(name, args);

EventSet::fireEvent_impl(name, args): getEventObject->(args);