向事件系統(tǒng)注冊事件的流程

首先客戶調(diào)用EventSet::subscribeEvent方法,傳入的參數(shù)為參數(shù)名和回調(diào)方法.實(shí)際上第二個(gè)參數(shù)的傳入過程中有一個(gè)創(chuàng)建臨時(shí)變量SubscriberSlot,其實(shí)質(zhì)上是一個(gè)綁定的回調(diào)函數(shù)(函數(shù)指針,成員函數(shù)指針,仿函數(shù)等)的過程,在圖中并沒有表現(xiàn)出來.
接著, EventSet::subscribeEvent方法中會(huì)首先調(diào)用EventSet::getEventObject方法獲取事件,在EventSet::getEventObject中,如果沒有查找到事件,則會(huì)創(chuàng)建之.當(dāng)獲取到事件之后, EventSet::subscribeEvent會(huì)調(diào)用Event::subscribe方法.
在Event::subscribe方法中,會(huì)先創(chuàng)建一個(gè)BoundSlot的實(shí)例,而在BoundSlot的構(gòu)造方法當(dāng)中,它會(huì)創(chuàng)建一個(gè)SubscriberSlot的實(shí)例,并將EventSet::subscribeEvent傳入的第二個(gè)參數(shù)保存到SubscriberSlot的實(shí)例里面去.
事件系統(tǒng)響應(yīng)事件的流程

首先要說明的是,客戶首先必須要從EventSet繼承下來才行,CEGUI里面有System,Renderer,Window,MouseCursor以及GlobalEventSet.其中GlobalEventSet是單件,系統(tǒng)創(chuàng)建以后就要?jiǎng)?chuàng)建它,EventSet對它是有依賴的,由上圖就可以得知.
EventSet是什么呢?EventSet它是一個(gè)事件的容器,它是一個(gè)事件處理中心.可以說是事件系統(tǒng)的接口.
當(dāng)客戶向事件系統(tǒng)發(fā)送了一個(gè)事件之后,即是執(zhí)行EventSet::fireEvent. EventSet::fireEvent首先執(zhí)行了GlobalEventSet:: fireEvent,而后才執(zhí)行其自身的一個(gè)方法EventSet::fireEvent_impl,該方法才是真正進(jìn)行事件處理的方法,由該方法的后綴impl即可得知了. EventSet::fireEvent_impl先是執(zhí)行了getEventObject方法查找到事件,然后調(diào)用該事件Event的仿函數(shù),該仿函數(shù)調(diào)用BoundSlot:: m_pSubscriber的仿函數(shù),它最終將會(huì)調(diào)用到SlotFunctorBase接口的實(shí)現(xiàn)的仿函數(shù),而這個(gè)仿函數(shù)內(nèi)部調(diào)用到的是真正的回調(diào)方法.
SlotFunctorBase這一塊實(shí)際上是Gof模式之一的適配器模式(adapter pattern)的應(yīng)用.
測試代碼:
using namespace CEGUI;


/**//// 事件參數(shù)
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;
}
下面對代碼進(jìn)行講解.
首先,我們需要聲明一個(gè)事件參數(shù),在CEGUI主模塊里面都是一些鍵盤鼠標(biāo)的輸入事件參數(shù).
然后,我們需要聲明一個(gè)事件集,它由EventSet繼承而來.
在測試代碼里面,我們聲明了一個(gè)testClient的類,代表著客戶在里面我們聲明一個(gè)回調(diào)方法:testClient::handleTest.testClient::Init方法作為客戶的初始代碼,在這里面,我們注冊事件.在testClient::exe里面執(zhí)行觸發(fā)事件的代碼.而后,事件將會(huì)被觸發(fā),繼而testClient::handleTest方法將會(huì)被回調(diào)執(zhí)行.