REDM基础教程20-注册类机制
其实插件系统和注册机制在REDM文档中都有详细的流程图,因回答过很多次类似的问题,所以这里作二次阐述:
1.注册类机制
REDM统一使用了注册类机制,内置的基础功能均使用了这一机制,如下所示:
enum DMREGTYPE { DMREG_Unknown = 0, ///<此类型仅供内部使用 DMREG_Skin = 1, ///<皮肤类,指单张图片的绘制方式,如平铺、拉伸、9宫格 DMREG_Style = 2, ///<样式类 DMREG_Attribute = 3, ///<XML解析类 DMREG_Window = 4, ///<DUI窗口类 DMREG_Layout = 5, ///<锚点布局类 DMREG_ImgDecoder = 6, ///<解码类 DMREG_Res = 7, ///<资源打包类 DMREG_Render = 8, ///<渲染类 DMREG_Draw = 9, ///<绘制类 DMREG_Log = 10, ///<LOG类 DMREG_FlowLayout = 11, ///<流式布局类,基于DUIWindow实现 DMREG_ToolTip = 12, ///<tooltip类 DMREG_Animate = 13, ///<动画注册类 DMREG_Script = 14, ///<脚本类 DMREG_Trans = 15, ///<翻译类 DMREG_MAX, };
在DmMain\inc\Modules\DMPluginImpl.cpp的Install函数中注册了所有的内置类:
void DMPluginImpl::Install() { DMCode iErr = DM_ECODE_OK; // 默认Log ----------------------------- ... // 默认解码器 ---------------------------- ... // 默认Res ------------------------------- ... // 默认Render----------------------------- ... // 默认Draw----------------------------- ... // 默认Skin ----------------------------- ... // 默认Style ----------------------------- ... // 默认Layout ---------------------------- ... // 内置Tooltip --------------------------- ... // 内置Trans --------------------------- ... // 内置Widget ---------------------------- ... // 内置FlowLayout ---------------------------- iErr = g_pDMApp->Register(DMRegHelperT<DUIVLayout>(),true); ...... }
1.1.注册类机制好处
1.允许你在外部重写类来覆盖内部的类。
例如内置的DUIButton.h,它的类定义了以下宏:
DMDECLARE_CLASS_NAME(DUIButton,L"Button",DMREG_Window);
DMREG_Window表示是DMREGTYPE类型,这里是指控件集合。
而"Button"关键字表示一种特定的DUI控件,它也是xml的唯一标识(不区分大小写),我们的xml是这样写的:
<button pos="......"/>
在解析xml时会自动针对此行xml生成一个DUIButton的类实例对象。
对于重写类,它们和内置的类一样,都需要实现以下宏定义:
DMDECLARE_CLASS_NAME(theclass, classname, classtype)
假定外部定义了一个class,它的类名可能叫A,B,C,我们就假定它是A:
class A : public xxx { DMDECLARE_CLASS_NAME(A,L"Button",DMREG_Window); }
然后调用:
iErr = g_pDMApp->Register(DMRegHelperT<A>(),true);
注意最后一个参数为true,表示强制替换。
这时内部在解析xml时会自动针对上行xml生成一个A的类实例对象。而不再是DUIButton的类实例对象。
2.允许你外部加入新的类,并把它设置为默认调用。
在DMDesigner工程的Plugin.cpp中,你可以找到如下代码:
void Plugin::Install() { g_pDMApp->Register(DMRegHelperT<Layout>(),true); ... g_pDMApp->SetDefRegObj(Layout::GetClassName(),Layout::GetClassType()); } ==》 DMDECLARE_CLASS_NAME(Layout,L"Layout",DMREG_Layout);
表示对布局(DMREG_Layout)做了重载,因为DMMain内置的是:
DMDECLARE_CLASS_NAME(DMLayoutImpl,L"DMLayoutImpl",DMREG_Layout);
"Layout"和"DMLayoutImpl"是不同的关键字,所以Layout并没有直接覆盖内置的DMLayoutImpl,而是通过
g_pDMApp->SetDefRegObj(Layout::GetClassName(),Layout::GetClassType());
把它设置为默认调用。
同样搜索SetDefRegObj关键字你还能发现:
g_pDMApp->SetDefRegObj(ResMultFolder::GetClassName(),ResMultFolder::GetClassType());// 默认使用Res多文件夹方式 g_pDMApp->SetDefRegObj(DMResZipImpl::GetClassName(),DMResZipImpl::GetClassType());// 默认使用Res的zip方式 g_pDMApp->SetDefRegObj(DMResMultZipImpl::GetClassName(),DMResMultZipImpl::GetClassType());// 默认使用Res的多个zip方式 g_pDMApp->SetDefRegObj(DMSkiaRenderImpl::GetClassName(),DMSkiaRenderImpl::GetClassType());// 默认使用Skia绘制引擎
tips类型比较特殊,比如QQDemo和DMDesigner中各实现了一个:
DMDECLARE_CLASS_NAME(DMTipsImpl,L"DMTipsImpl",DMREG_ToolTip); DMDECLARE_CLASS_NAME(TipsImpl,L"TipsImpl",DMREG_ToolTip);
它的使用方式为xml中配置:
<dm regtip="DMTipsImpl" ....>
也就是我们可以针对不同的DM主窗口使用不同的tips效果类
3.允许你加入新的控件
这个在1的基础上应该比较好理解,比如实现了一个DUI控件B并注册
class B : public xxx { DMDECLARE_CLASS_NAME(B,L"cc",DMREG_Window); } g_pDMApp->Register(DMRegHelperT<B>(),true);
它的使用方式为xml中配置:
<cc pos="..."/>
1.2.注册类机制原理
IDMReg通过DMRegHelperT模板来辅助注册。
IDMReg通过DMRegHelperT模板来辅助注册。
IDMReg对象提供了 创建注册类实例对象、取得注册类名、取得注册父类名、提供注册类型Type等封装接口。
例如:
IDMReg对象是通过注册类名这个字符串来标识是否相同的, 注册类名是用户自定义的一个标识字符串,不一定是真实的类名。
比如:对于DUIButton这个类,内部用L“Button”来标识注册类名,而不是L“DUIButton”
DMRegTypeItem管理了同一type的IDMReg
DMRegMgr对每个Type维护一个DMRegTypeItem提供Register注册接口和CreateRegObj创建对象接口
文章作者:hgy413
本文地址:https://hgy413.com/5302.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!