初探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    - 独轮之月 - 听雨阁

你可能感兴趣的:(MyGui)