CEGUI自定义控件的几个关键步骤
2016-04-09 20:13
357 查看
接触cegui也不算太长的时间,后来特别想了解一下原理,以及弄懂为什么设计,读了 <<CEGUI深入详解>>这本书,受益颇多,但是也遇到了版本不一致导致的各种问题,尤其是当设计到自定义控件这种实际性的检验学习成果的时候
1.版本差别,该书作者使用的是0.6.x 我用的是 0.8.x,具体的小版本已经不记得了,本篇文章的目的并不是为了实现一个多么强大的控件,更多的是把我遇到的一些坑给大家讲解一下,大家一定要注意的是我实现的自定义控件并不编译到cegui库中,也就是只有我自己的exe能够用
2.首先我们用0.6来实现一下,这个 cegui深入详解已经讲得很明白了,不过难免令粘贴党感觉到有语焉不详的地方,我把完整的代码
//TimeWindow.h
//TimeWindow.cpp
以上是渲染类,大家请注意我为了省事,我是直接粘贴的自己的源代码,d_lastTime并没有任何作用,因为我开始是照着书本弄得,但是后来发现连基本流程都走不通,索性就实现一个绘制图片的按钮
//下面我们把渲染类实现出来
//FalgardTimerWindow.h
//FalgardTimerWindow.cpp
//以上这些还不够,我们需要添加到样式文件中,这些文件是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文件能够和咱们的窗口类对应起来)
以上就是在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的方式时
注册渲染窗口可以放在加载方案的前面,但是如果0.8将渲染窗口的注册放在前面的话,会崩溃,我看了一下调用堆栈,大概的原因就是 当cegui加载方案的时候会注册很多渲染类,例如button editbox等,但是他会首先释放掉我们注册的工厂,释放动作是在dll中完成的(也就是cegui基础库dll),但是对象的创建是通过一个宏来完成,也就是new操作实在我们的exe中,这就会出问题,解决的方法就是将渲染窗口的注册放在加载scheme的后面进行,上代码
这样不出问题的原因就是不会去做释放操作,那为什么注册窗口就没问题,大家可以看一下注册窗口并没有这个释放动作所以不会出问题
4.还有一个 我偷懒了 我给出的样式文件中的xml块是0.8版本下的,如果有问题,大家请参照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 events static const String EventNamespace; //! Window factory name static 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.scheme SchemeManager::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.scheme SchemeManager::getSingleton().createFromFile( "VanillaSkin.scheme" ); SchemeManager::getSingleton().createFromFile( "TaharezLook.scheme" );
//当加载完scheme的后面注册渲染窗口 WindowRendererManager::addFactory<TplWindowRendererFactory<FalgardTimerWindow> >();
这样不出问题的原因就是不会去做释放操作,那为什么注册窗口就没问题,大家可以看一下注册窗口并没有这个释放动作所以不会出问题
4.还有一个 我偷懒了 我给出的样式文件中的xml块是0.8版本下的,如果有问题,大家请参照cegui深入详解上的片段
相关文章推荐
- iOS开发学习之 - 深入学习UIButton(2)
- 关于视图方面的UI控件
- 一些蓝牙(Bluetooth)相关的技术术语表
- AlertDialog和AlertDialog.Builder
- AlertDialog.Builder详解
- APUE------线程控制
- UITableView的scrollToRowAtIndexPath:atScrollPosition:animated的崩溃
- easyui treegrid动态加载节点
- UIImage
- 山东省第四届ACM大学生程序设计竞赛-Rescue The Princess(计算几何)
- LeetCode *** 225. Implement Stack using Queues
- J2EE中getParameter与getAttribute以及EL表达式${requestScope}和${param[]}
- VC读写txt文件时提示unrecognized character escape sequence(无法识别的字符转移序列)
- IOS开发UI系列之常用控件 UILabel, UITextField, UIButton, UIImageView等常用属性与方法
- UITextField点击return后注销第一响应者
- 代码篇——Easyui的formatter实现超链接跳转页面
- android学习第四天,其他UI控件
- iOS之UITabBar 的相关属性
- android 在线程中调用handle更新UI
- 使用runOnUiThread解决Handler无法调用含用子线程方法的问题