初探MyGUI

  一說起GUI,可能大家都會想到大名鼎鼎的CEGUI了。Crazy Eddie's Gui System,確實瘋狂。包括仙劍四、天龍八部、火炬之光等等一大批遊戲均使用CEGUI,瘋狂程序可見一般。但CEGUI並不完美,它同樣擁有諸多缺點:
         1. 效率不高。CEGUI是可以用DX,OPENGL或者遊戲引擎來渲染的,相當的龐大,這就導致了效率不高。
          2.功能不完善。在CEGUI的Edit控件中,插入符是不會閃動的,包括火炬之光中的插入符也是沒有閃動的。在Edit控件中,沒有實現剪切、複製、粘貼和返回的功能。

          於是,我拋開了CEGUI,學習MyGUI。MyGUI是專爲Ogre引擎設計的,它是一套簡單、高效、功能強大的GUI函數庫,它的渲染是由Ogre來完成的。MyGUI實現了輸入時的光標閃動,實現了Ctrl + C、V、Z、X等功能。最新版本是2.2.3,可以在
http://www.ogre3d.org/wiki/index.php/MyGUI這裏找到關於它的信息。MyGUI的Demo是自已創建的框架,一時還不好完全看明白。下面來說說在ogre的示例框架下使用MyGUI(Ogre1.6.4+MyGUI2.2.3):

          使用之前:首先編譯MyGUI,編譯過程很簡單,VS2005、VS2008的工程都有(MyGUI2.2.3需要Ogre1.6+和freetype235_D.lib,freetype在ogre的Dependencies裏面有)。編譯完成後,MyGUI的頭文件在..\MyGUI2.2.3_source\MyGUIEngine\include裏面,lib和dll在..\MyGUI2.2.3_source\MyGUIEngine\lib裏面。include和lib添加到工程裏面去,方法和Ogre一樣。

          1.創建MyGUI。創建很簡單,直接new一個就行了。例:mGui = new MyGUI::Gui();   但這並沒有完,你還得初始化它,像這樣:mGui->initialise(mWindow); // mWindow是什麼呢?它是Ogre裏面的RenderWindow。接下來,你需要加載Theme和Skin,在CEGUI裏面要設置默認鼠標、字體等,在這裏用不着了。 
        mGui->load("core_theme.xml");          // 加載Theme
        mGui->load("colour_slider_skin.xml");// 加載Skin

           2. 加載layout。在MyGUI中加載layout是使用LayoutManager類進行加載的。用MyGUI::LayoutManager::getInstance()來獲取LayoutManager的實例,getInstance像不像Ogre裏面的getSingleton方法? 對,LayoutManager還有一個getInstancePtr方法來獲取實例指針。加載layout有二個函數:load和loadLayout,它們的區別在於:loadLayout加載時,會把每個一控件的名字前加上一個你指定的前綴,來防止重名的情況。例:MyGUI::VectorWidgetPtr widgetVector= MyGUI::LayoutManager::getInstance().load("ColourPanel.layout");   返回值是一個vector,它保存的是在這個layout中所有沒有父窗口的窗口。 那麼,怎麼去獲取layout裏面的控件呢? 實際上,Demo裏面用的方法是:遍歷這個vector,然後查找它的子窗口,再把這個子窗口轉換成你所想要存儲的窗口指針。如:
template <typename T>
void findWidget(T * &_widget,const std::string &_name,MyGUI::VectorWidgetPtr &widgetVector)
{   // 遍歷vector
    for (MyGUI::VectorWidgetPtr::iterator iterWidget = widgetVector.begin();iterWidget!=widgetVector.end();iterWidget++)
    {
        MyGUI::WidgetPtr widget = (*iterWidget)->findWidget(_name);   // 查找窗口
        T *cast = widget->castType<T>(true);  // 轉換成你想要的窗口類型
        if (cast)
            _widget = cast;   // 保存窗口指針
    }
使用的時候:
        MyGUI::StaticImagePtr mColourRect;
        findWidget(mColourRect,"widget_ColourRect",widgetVector);

        當然,用這種方法去獲取窗口確實有點麻煩。更簡單的方法是:使用MyGUI::Gui裏面的findWidget和findWidgetT二個函數,或者是MyGUI::WidgetManager裏面的findWidget和findWidgetT函數。用法也比較簡單,例:MyGUI::ButtonPtr mButtonOK = MyGUI::Gui::getInstance().findWidget<MyGUI::Button>("button_OK",false);,後面那個參數是“是否拋出異常”,如果爲true,那麼找不到這個窗口時將拋異常,如果爲false,那麼找不到這個窗口將返回nullptr。

        3. 註冊窗口事件。 如:mColourRect->eventMouseButtonPressed = MyGUI::newDelegate(this,&Application::notifyMouseButtonPressed);就是註冊鼠標按下事件。當然,你可以很快地找到其它對應的事件名。  newDelegate重載了二種方法,一種只有一個參數(只能註冊類中的靜態函數或全局函數),另一種就是上面這樣可以註冊類中的普通函數。在這裏需要說明一下的是關於自定義函數notifyMouseButtonPressed的參數設置是因消息的不同而不同的。在頭文件<mygui_widgetevent.h>裏面可以找到相應的函數參數類型(在那些綠色被註解了的英文中)。例如,在這裏的鼠標按下函數原型是void notifyMouseButtonPressed(MyGUI::WidgetPtr _sender,int _left,int _top,MyGUI::MouseButton _id);

         4.注入鼠標、鍵盤消息。這一點和CEGUI有些相似,只是注入的參數不同,MyGUI不用把OIS的鼠標轉換成GUI的鼠標。如注入鼠標按下事件:
    bool mousePressed(const OIS::MouseEvent &arg,OIS::MouseButtonID id)
    {
            mGui->injectMousePress(arg,id);
            return true;
    }
在MyGUI中,你還應該注入一個幀開始事件,在渲染一幀時使用mGui->injectFrameEntered(evt.timeSinceLastFrame);以確保MyGUI能自己更新,比如插入符的閃動。

          MyGUI現在就能基本使用了。聽起來MyGUI很不錯嘛?!但它也有自身的缺點,由於MyGUI是一個俄羅斯人所寫的,所以在註解中有一些是俄語(還有一部分是英語)。還有就是MyGUI的資料很少,教程不好找。

MyGUI的Demo界面:
初探MyGUI    - 獨輪之月 - 聽雨閣初探MyGUI    - 獨輪之月 - 聽雨閣
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章