CEGUI自定义控件的几个关键步骤
来源:互联网 发布:win10怎么还原网络设置 编辑:程序博客网 时间:2024/05/09 18:13
接触cegui也不算太长的时间,后来特别想了解一下原理,以及弄懂为什么设计,读了 <<CEGUI深入详解>>这本书,受益颇多,但是也遇到了版本不一致导致的各种问题,尤其是当设计到自定义控件这种实际性的检验学习成果的时候
1.版本差别,该书作者使用的是0.6.x 我用的是 0.8.x,具体的小版本已经不记得了,本篇文章的目的并不是为了实现一个多么强大的控件,更多的是把我遇到的一些坑给大家讲解一下,大家一定要注意的是我实现的自定义控件并不编译到cegui库中,也就是只有我自己的exe能够用
2.首先我们用0.6来实现一下,这个 cegui深入详解已经讲得很明白了,不过难免令粘贴党感觉到有语焉不详的地方,我把完整的代码
//TimeWindow.h
namespace CEGUI{class TimeWindow:public Window{public://! Namespace for global eventsstatic const String EventNamespace;//! Window factory namestatic const String WidgetTypeName;TimeWindow(const String& type, const String& name);~TimeWindow(void);void setLastTime( float f ) ;float getLastTime( ) const ;protected:float d_lastTime; //定时器设置的时间,倒计时持续多久的属性变量};CEGUI_DECLARE_WINDOW_FACTORY(TimeWindow);}
//TimeWindow.cpp
namespace CEGUI{//CEGUI_DEFINE_WINDOW_FACTORY(TimeWindow) ;const String TimeWindow::WidgetTypeName = "CEGUI/TimeWindow";const String TimeWindow::EventNamespace = "TimeWindow";TimeWindow::TimeWindow(const String& type, const String& name):Window( type , name ){ const String& propertyOrigin = WidgetTypeName;CEGUI_DEFINE_PROPERTY(TimeWindow, float,"LastTime","Property to get/set the read-only setting for the Editbox. Value is either \"true\" or \"false\".",&TimeWindow::setLastTime, &TimeWindow::getLastTime, 0.0f);}TimeWindow::~TimeWindow(void){}void TimeWindow::setLastTime( float f ){d_lastTime = f ;}float TimeWindow::getLastTime() const{return d_lastTime ;}}
以上是渲染类,大家请注意我为了省事,我是直接粘贴的自己的源代码,d_lastTime并没有任何作用,因为我开始是照着书本弄得,但是后来发现连基本流程都走不通,索性就实现一个绘制图片的按钮
//下面我们把渲染类实现出来
//FalgardTimerWindow.h
namespace CEGUI{class FalgardTimerWindow:public WindowRenderer{public:static const String TypeName; //!< type name for this widget.FalgardTimerWindow(const String& type);~FalgardTimerWindow(void);void render();};}#define CEGUI_DEFINE_WR_FACTORY( className )\namespace CEGUI {\class className ## WRFactory : public WindowRendererFactory\{\public:\className ## WRFactory(void) : WindowRendererFactory(className::TypeName) { }\WindowRenderer* create(void)\{ return new className(className::TypeName); }\void destroy(WindowRenderer* wr)\{ delete wr; }\};\}\static CEGUI::className ## WRFactory s_ ## className ## WRFactory;CEGUI_DEFINE_WR_FACTORY(FalgardTimerWindow)
//FalgardTimerWindow.cpp
namespace CEGUI{const String FalgardTimerWindow::TypeName("Core/TimeWindow");FalgardTimerWindow::FalgardTimerWindow(const String& type):WindowRenderer(type){}FalgardTimerWindow::~FalgardTimerWindow(void){}void FalgardTimerWindow::render(){TimeWindow* w = (TimeWindow*)d_window ;const WidgetLookFeel& wlf = getLookNFeel() ;wlf.getImagerySection( "Text" ).render( *w , 0 ) ;}}
//以上这些还不够,我们需要添加到样式文件中,这些文件是cegui默认提供的
//VanillaSkin.scheme里添加一行
<FalagardMapping windowType="Vanilla/TimeWindow" targetType="CEGUI/TimeWindow" renderer="Core/TimeWindow" lookNFeel="Vanilla/TimeWindow" />
//Vanilla.looknfeel
<WidgetLook name="Vanilla/TimeWindow">
<ImagerySection name="Text">
<ImageryComponent>
<Area>
<Dim type="LeftEdge"><AbsoluteDim value="3" /></Dim>
<Dim type="TopEdge"><AbsoluteDim value="3" /></Dim>
<Dim type="Width"><UnifiedDim scale="1" offset="-3" type="Width" /></Dim>
<Dim type="Height"><UnifiedDim scale="1" offset="-3" type="Height" /></Dim>
</Area>
<Image name="Vanilla-Images/FrameTopLeft"/>
<VertFormat type="Stretched" />
<HorzFormat type="Stretched" />
</ImageryComponent>
</ImagerySection>
</WidgetLook>
接下来最重要的一步就是注册(说白了就是你得让你的样式xml文件能够和咱们的窗口类对应起来)
Direct3D9Renderer* render = &Direct3D9Renderer::bootstrapSystem(g_pd3dDevice); //WindowFactoryManager::getSingleton().addFactory( &(CEGUI_WINDOW_FACTORY(TimeWindow)) ) ; WindowFactoryManager::addFactory<TplWindowFactory<TimeWindow> >() ;//注册窗口 WindowRendererManager& wfm = WindowRendererManager::getSingleton(); wfm.addFactory( &s_FalgardTimerWindowWRFactory);//注册渲染窗口
以上就是在0.6种自定义一个控件的所有步骤,s_FalgardTimerWindowWRFactory这个可能大家有点疑惑,请看我的源代码中有一个宏CEGUI_DEFINE_WR_FACTORY
2.那么在0.8中有什么不同呢
其实并没有什么不同,当然我说的没有不同只针对自定义一个窗口的流程,至于CEGUI库有无不同,我们不做考虑,废话不多说,我们看一下0.8中如何实现
以下宏都去掉
CEGUI_DECLARE_WINDOW_FACTORY(TimeWindow);
CEGUI_DEFINE_WINDOW_FACTORY(TimeWindow) ;
#define CEGUI_DEFINE_WR_FACTORY( className )\
namespace CEGUI {\
class className ## WRFactory : public WindowRendererFactory\
{\
public:\
className ## WRFactory(void) : WindowRendererFactory(className::TypeName) { }\
WindowRenderer* create(void)\
{ return new className(className::TypeName); }\
void destroy(WindowRenderer* wr)\
{ delete wr; }\
};\
}\
static CEGUI::className ## WRFactory s_ ## className ## WRFactory;
CEGUI_DEFINE_WR_FACTORY(FalgardTimerWindow)
以上全部不要,0.8为了使我们更方便的注册自定义控件,为我们添加了两个静态函数来完成注册
WindowFactoryManager::addFactory<TplWindowFactory<TimeWindow> >() ;
WindowRendererManager::addFactory<TplWindowRendererFactory<FalgardTimerWindow> >();
只需要 这两行就完成了我们上面坐的所有东西,具体的意义,大家看一下源代码,就知道了和0.6并无本质上的不同,相信不难看懂
3.请注意大坑来了
1)用0.6的方式一样可以在0.8中完成窗口的注册
2)当用0.6的方式时
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); // Turn on the zbuffer g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );Direct3D9Renderer* render = &Direct3D9Renderer::bootstrapSystem(g_pd3dDevice);WindowFactoryManager::getSingleton().addFactory( &(CEGUI_WINDOW_FACTORY(TimeWindow)) ) ;WindowRendererManager& wfm =WindowRendererManager::getSingleton();wfm.addFactory( &s_FalgardTimerWindowWRFactory);DefaultResourceProvider* resPro = static_cast<DefaultResourceProvider*>(System::getSingleton().getResourceProvider());resPro->setResourceGroupDirectory("schemes","schemes\\");resPro->setResourceGroupDirectory("imagesets", "imagesets\\");resPro->setResourceGroupDirectory("fonts", "fonts\\");resPro->setResourceGroupDirectory("layouts", "layouts\\");resPro->setResourceGroupDirectory("looknfeels", "looknfeel\\");resPro->setResourceGroupDirectory("lua_scripts", "lua_scripts\\");resPro->setResourceGroupDirectory("schemas", "xml_schemas\\");resPro->setResourceGroupDirectory("animations", "animations\\");AnimationManager::setDefaultResourceGroup("animations");ImageManager::setImagesetDefaultResourceGroup("imagesets");Font::setDefaultResourceGroup("fonts");Scheme::setDefaultResourceGroup("schemes");WidgetLookManager::setDefaultResourceGroup("looknfeels");WindowManager::setDefaultResourceGroup("layouts");ScriptModule::setDefaultResourceGroup("lua_scripts");XMLParser* parser = System::getSingleton().getXMLParser();if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))parser->setProperty("SchemaDefaultResourceGroup", "schemas");/*if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))parser->setProperty("SchemaDefaultResourceGroup", "schemas");*///加载方案//TaharezLook.schemeSchemeManager::getSingleton().createFromFile( "VanillaSkin.scheme" );SchemeManager::getSingleton().createFromFile( "TaharezLook.scheme" );
注册渲染窗口可以放在加载方案的前面,但是如果0.8将渲染窗口的注册放在前面的话,会崩溃,我看了一下调用堆栈,大概的原因就是 当cegui加载方案的时候会注册很多渲染类,例如button editbox等,但是他会首先释放掉我们注册的工厂,释放动作是在dll中完成的(也就是cegui基础库dll),但是对象的创建是通过一个宏来完成,也就是new操作实在我们的exe中,这就会出问题,解决的方法就是将渲染窗口的注册放在加载scheme的后面进行,上代码
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); // Turn on the zbuffer g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );Direct3D9Renderer* render = &Direct3D9Renderer::bootstrapSystem(g_pd3dDevice);WindowFactoryManager::addFactory<TplWindowFactory<TimeWindow> >() ;//注册窗口DefaultResourceProvider* resPro = static_cast<DefaultResourceProvider*>(System::getSingleton().getResourceProvider());resPro->setResourceGroupDirectory("schemes","schemes\\");resPro->setResourceGroupDirectory("imagesets", "imagesets\\");resPro->setResourceGroupDirectory("fonts", "fonts\\");resPro->setResourceGroupDirectory("layouts", "layouts\\");resPro->setResourceGroupDirectory("looknfeels", "looknfeel\\");resPro->setResourceGroupDirectory("lua_scripts", "lua_scripts\\");resPro->setResourceGroupDirectory("schemas", "xml_schemas\\");resPro->setResourceGroupDirectory("animations", "animations\\");AnimationManager::setDefaultResourceGroup("animations");ImageManager::setImagesetDefaultResourceGroup("imagesets");Font::setDefaultResourceGroup("fonts");Scheme::setDefaultResourceGroup("schemes");WidgetLookManager::setDefaultResourceGroup("looknfeels");WindowManager::setDefaultResourceGroup("layouts");ScriptModule::setDefaultResourceGroup("lua_scripts");XMLParser* parser = System::getSingleton().getXMLParser();if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))parser->setProperty("SchemaDefaultResourceGroup", "schemas");/*if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))parser->setProperty("SchemaDefaultResourceGroup", "schemas");*///加载方案//TaharezLook.schemeSchemeManager::getSingleton().createFromFile( "VanillaSkin.scheme" );SchemeManager::getSingleton().createFromFile( "TaharezLook.scheme" );
//当加载完scheme的后面注册渲染窗口WindowRendererManager::addFactory<TplWindowRendererFactory<FalgardTimerWindow> >();
这样不出问题的原因就是不会去做释放操作,那为什么注册窗口就没问题,大家可以看一下注册窗口并没有这个释放动作所以不会出问题
4.还有一个 我偷懒了 我给出的样式文件中的xml块是0.8版本下的,如果有问题,大家请参照cegui深入详解上的片段
- CEGUI自定义控件的几个关键步骤
- Android 自定义控件的几个步骤
- CEGUI添加自定义控件
- socket通信的几个关键步骤
- socket通信的几个关键步骤
- ios socket通信的几个关键步骤
- Android自定义控件几个重要步骤
- SqlServer 调优的几个关键的步骤--sp_lock,sp_who
- SqlServer 调优的几个关键的步骤--sp_lock,sp_who
- 自定义控件的的步骤
- 定制WinCE6.0操作系统的几个关键步骤
- 定制WinCE6.0操作系统的几个关键步骤
- Windows Tensorflow CPU版安装的几个关键步骤
- 开发自定义控件的步骤
- 自定义控件的创建步骤
- 自定义组合控件的步骤
- 几个cegui,ogre编译错误的处理
- java的几个关键
- Visual Studio 2012 Ultimate旗舰版下载地址与序列号
- 设计模式之工厂模式
- Problem 1603 - Minimum Sum 【好题】
- Linux下select, poll和epoll IO模型的详解
- ....
- CEGUI自定义控件的几个关键步骤
- HDOJ 2058 The sum problem
- socket编程UDP小例子
- 使用 Shell 脚本自动化 Linux 系统维护任务
- 《leetCode》:Isomorphic Strings
- Java深克隆和浅克隆的原理及实现
- POJ 3768 Repeater
- Git远程操作详解
- iOS如何上传代码到Github