• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴(yán)以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            CEGUI的事件系統(tǒng)分析

            作者: 楊粼波
            Email: tx7do@yahoo.com.cn


            什么是GUI?

                   GUI就是圖形用戶界面(Graphics User Interface),是指采用圖形方式顯示的計(jì)算機(jī)操作用戶接口.

             

             什么是GUI的事件?

                   所謂事件就是指發(fā)送給GUI系統(tǒng)的消息,該消息通知GUI系統(tǒng)某種事情已發(fā)生,要求作出響應(yīng).簡言之就是:用戶將自己的一個(gè)或多個(gè)回調(diào)函數(shù)掛鉤到某個(gè)“事件”上,一旦“事件”被觸發(fā),所有掛鉤的函數(shù)都被調(diào)用。

                  顯然,事件機(jī)制是一個(gè)非常有用的并且常用的機(jī)制,C#已經(jīng)將之在語言層面進(jìn)行了實(shí)現(xiàn),但是C++并無實(shí)現(xiàn).不過很多庫都有實(shí)現(xiàn)比如:boost::signal. 

             

            CEGUI的事件機(jī)制是什么?

                   CEGUI的事件機(jī)制采用的是觀察者模式(Observer pattern)的一種實(shí)現(xiàn).很有點(diǎn)像QtSignal/Slot機(jī)制,但是又沒有那么復(fù)雜.

            對事件的封裝上雖然用到了仿函數(shù),但其實(shí)卻是為了統(tǒng)一接口,其實(shí)質(zhì)可以是回調(diào)函數(shù)也可以是仿函數(shù).


            CEGUI事件系統(tǒng)的靜態(tài)類圖



            向事件系統(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í)行.


            代碼下載:
            testEventSystem.rar
            需要注意的是,這份代碼里面的事件系統(tǒng)不是原汁原味的CEGUI的事件系統(tǒng),是經(jīng)過我略加修改之后的東西.


            文檔和圖片下載:
            CEGUI事件系統(tǒng)分析.rar
            靜態(tài)類圖貌似過大了,上傳到博客上面它自動(dòng)給我縮小了--!那根本就看不清楚,Word和PDF文檔里面也勉強(qiáng)能看清楚,沒辦法只好都打包進(jìn)去了.


            參考資料

            1.       圖形用戶界面 http://zh.wikipedia.org/zh-cn/GUI

            2.       GUI系統(tǒng)的事件機(jī)制 http://wenku.baidu.com/view/a07ea19951e79b896802260d.html

            posted on 2010-06-02 00:58 楊粼波 閱讀(4325) 評論(3)  編輯 收藏 引用

            評論

            # re: CEGUI的事件系統(tǒng)分析 2010-06-02 10:48 Any

            可否告訴我文中的圖用什么畫的?  回復(fù)  更多評論   

            # re: CEGUI的事件系統(tǒng)分析 2010-06-02 10:53 楊粼波

            用EA(Enterprise Architect 7.5)畫的.  回復(fù)  更多評論   

            # re: CEGUI的事件系統(tǒng)分析 2011-04-15 12:36 liigo

            我(liigo)認(rèn)為CEGUI使用的這套事件處理機(jī)制挺漂亮的,簡單實(shí)用。基本上由EventSet管理:它維護(hù)著一個(gè)string為key,鏈表為value的哈希表;每個(gè)string就對應(yīng)一個(gè)事件名稱,鏈表里則存儲(chǔ)著用于接收這個(gè)事件的用戶處理代碼的抽象(仿函數(shù),由subscribeEvent提供)。注冊一個(gè)事件處理函數(shù)(也可以是任意對象方法或仿函數(shù)),就是往哈希表中事件名稱對應(yīng)的鏈表中添加一個(gè)項(xiàng);觸發(fā)事件處理函數(shù)呢,就是循環(huán)調(diào)用指定事件名稱對應(yīng)的鏈表中的每一個(gè)仿函數(shù)。  回復(fù)  更多評論   


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久国产精品77777| 久久久久亚洲AV无码专区桃色| 性高湖久久久久久久久AAAAA| 久久久噜噜噜久久中文字幕色伊伊| 亚洲?V乱码久久精品蜜桃| 亚洲中文字幕无码久久综合网| 久久精品国产免费一区| 久久国产综合精品五月天| 一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 精品国产综合区久久久久久| 久久综合久久伊人| 精品一区二区久久久久久久网站| 久久人妻少妇嫩草AV无码蜜桃| 久久久精品人妻一区二区三区四 | 国产精品久久久久aaaa| 欧美精品福利视频一区二区三区久久久精品| 久久笫一福利免费导航 | 久久精品国产亚洲AV无码偷窥 | 青青草原精品99久久精品66| 日韩精品久久久久久| 人妻无码αv中文字幕久久琪琪布| 9191精品国产免费久久| 久久亚洲精品无码AV红樱桃| 国产精品乱码久久久久久软件| 99久久精品免费国产大片| 久久久精品国产sm调教网站| 99久久综合国产精品免费| 久久强奷乱码老熟女网站| 久久久久噜噜噜亚洲熟女综合| 久久夜色精品国产亚洲| AV狠狠色丁香婷婷综合久久| 日韩人妻无码精品久久久不卡| 亚州日韩精品专区久久久| 亚洲国产日韩欧美久久| 婷婷久久综合九色综合绿巨人| 久久久人妻精品无码一区| 久久伊人精品青青草原日本| 亚洲精品乱码久久久久久蜜桃| 综合久久精品色| 99久久精品国产一区二区 | 久久久久亚洲爆乳少妇无|