向事件系统注册事件的流程

首先客户调用EventSet::subscribeEvent方法,传入的参数为参数名和回调方法.实际上第二个参数的传入过程中有一个创建临时变量SubscriberSlot,其实质上是一个绑定的回调函数(函数指针,成员函数指针,仿函数等)的过程,在图中并没有表现出来.
接着, EventSet::subscribeEvent方法中会首先调用EventSet::getEventObject方法获取事件,在EventSet::getEventObject中,如果没有查找到事件,则会创建之.当获取到事件之后, EventSet::subscribeEvent会调用Event::subscribe方法.
在Event::subscribe方法中,会先创建一个BoundSlot的实例,而在BoundSlot的构造方法当中,它会创建一个SubscriberSlot的实例,并将EventSet::subscribeEvent传入的第二个参数保存到SubscriberSlot的实例里面去.
事件系统响应事件的流程

首先要说明的是,客户首先必须要从EventSet继承下来才行,CEGUI里面有System,Renderer,Window,MouseCursor以及GlobalEventSet.其中GlobalEventSet是单件,系统创建以后就要创建它,EventSet对它是有依赖的,由上图就可以得知.
EventSet是什么呢?EventSet它是一个事件的容器,它是一个事件处理中心.可以说是事件系统的接口.
当客户向事件系统发送了一个事件之后,即是执行EventSet::fireEvent. EventSet::fireEvent首先执行了GlobalEventSet:: fireEvent,而后才执行其自身的一个方法EventSet::fireEvent_impl,该方法才是真正进行事件处理的方法,由该方法的后缀impl即可得知了. EventSet::fireEvent_impl先是执行了getEventObject方法查找到事件,然后调用该事件Event的仿函数,该仿函数调用BoundSlot:: m_pSubscriber的仿函数,它最终将会调用到SlotFunctorBase接口的实现的仿函数,而这个仿函数内部调用到的是真正的回调方法.
SlotFunctorBase这一块实际上是Gof模式之一的适配器模式(adapter pattern)的应用.
测试代码:
using namespace CEGUI;


/**//// 事件参数
class TestEventArgs : public EventArgs


{
public:

TestEventArgs(const int& _n) : n(_n)
{}

int n;
};


/**//// 事件
class testEvent : public EventSet


{
public:

testEvent()
{}

static const String EventNamespace;
static const String EventTest;

void injectTest(int n)

{
TestEventArgs e(n);
fireEvent(EventTest, e, EventNamespace);
}
};
const String testEvent::EventTest("test");
const String testEvent::EventNamespace("testEvent");


/**//// 客户
class testClient


{
public:
testClient()

{
Init();
}

void Init()

{
new GlobalEventSet();
mEvent.subscribeEvent(testEvent::EventTest, Event::Subscriber(&testClient::handleTest, this) );
}

bool handleTest(const CEGUI::EventArgs& e)

{
int val = static_cast<const TestEventArgs&>(e).n;
std::cout << val << std::endl;
return true;
}

void exe()

{
mEvent.injectTest(99);
mEvent.injectTest(5555);
}

private:
testEvent mEvent;
};

int main()


{
testClient client;
client.exe();

system("pause");
return 0;
}
下面对代码进行讲解.
首先,我们需要声明一个事件参数,在CEGUI主模块里面都是一些键盘鼠标的输入事件参数.
然后,我们需要声明一个事件集,它由EventSet继承而来.
在测试代码里面,我们声明了一个testClient的类,代表着客户在里面我们声明一个回调方法:testClient::handleTest.testClient::Init方法作为客户的初始代码,在这里面,我们注册事件.在testClient::exe里面执行触发事件的代码.而后,事件将会被触发,继而testClient::handleTest方法将会被回调执行.