Win32编程中,用户需要一个新控件时,需要向系统注册一个新的控件类型。注册以后,调用::CreateWindow时才能根据标识控件类型的字符串创建出一个新的控件窗口对象。

为了能够从XML描述的字符串中创建出需要的控件对象,和Win32类似,在SOUI中要创建一个新的控件也同样需要向SOUI系统注册新的控件类。

从demo.cpp的main中我们可以看到类似如下的控件注册控件的代码:

        //向SApplication系统中注册由外部扩展的控件及SkinObj类
SWkeLoader wkeLoader;
if(wkeLoader.Init(_T("wke.dll")))
{
theApp->RegisterWndFactory(TplSWindowFactory<SWkeWebkit>());//注册WKE浏览器
}
theApp->RegisterWndFactory(TplSWindowFactory<SGifPlayer>());//注册GIFPlayer
theApp->RegisterSkinFactory(TplSkinFactory<SSkinGif>());//注册SkinGif
theApp->RegisterSkinFactory(TplSkinFactory<SSkinAPNG>());//注册SSkinAPNG
theApp->RegisterSkinFactory(TplSkinFactory<SSkinVScrollbar>());//注册纵向滚动条皮肤 theApp->RegisterWndFactory(TplSWindowFactory<SIPAddressCtrl>());//注册IP控件
theApp->RegisterWndFactory(TplSWindowFactory<SPropertyGrid>());//注册属性表控件
theApp->RegisterWndFactory(TplSWindowFactory<SChromeTabCtrl>());//注册ChromeTabCtrl
theApp->RegisterWndFactory(TplSWindowFactory<SIECtrl>());//注册IECtrl
theApp->RegisterWndFactory(TplSWindowFactory<SChatEdit>());//注册ChatEdit
theApp->RegisterWndFactory(TplSWindowFactory<SScrollText>());//注册SScrollText if(SUCCEEDED(CUiAnimation::Init()))
{
theApp->RegisterWndFactory(TplSWindowFactory<SUiAnimationWnd>());//注册动画控件
}
theApp->RegisterWndFactory(TplSWindowFactory<SFlyWnd>());//注册飞行动画控件
theApp->RegisterWndFactory(TplSWindowFactory<SFadeFrame>());//注册渐显隐动画控件
theApp->RegisterWndFactory(TplSWindowFactory<SRadioBox2>());//注册渐显隐动画控件

上面代码中即有新皮肤对象的注册也有窗口控件的注册,这种注册控件方式看起来有点怪异,但使用起来也还算是简单,只需要一行代码(实际上是从著名的游戏GUI CEGUI借鉴过来的)。

以注册窗口控件为例,下面我来解释一下为什么会有这样一种控件注册方式。

先看看TplSWindowFactory模板类的实现:

    class SWindowFactory
{
public:
virtual ~SWindowFactory() {}
virtual SWindow* NewWindow() = ;
virtual LPCWSTR SWindowBaseName()=; virtual const SStringW & getWindowType()=; virtual SWindowFactory* Clone() const =;
}; template <typename T>
class TplSWindowFactory : public SWindowFactory
{
public:
//! Default constructor.
TplSWindowFactory():m_strTypeName(T::GetClassName())
{
} LPCWSTR SWindowBaseName(){return T::BaseClassName();} // Implement WindowFactory interface
virtual SWindow* NewWindow()
{
return new T;
} virtual const SStringW & getWindowType()
{
return m_strTypeName;
} virtual SWindowFactory* Clone() const
{
return new TplSWindowFactory();
}
protected:
SStringW m_strTypeName;
};
TplSWindowFactory从SWindowFactory派生,自动为模板参数中指定的类型生成一个SWindowFactory对象。
SWindowFactory有什么用呢?SWindowFactory最核心的用途就在于它的方法:SWindow * SWindowFactory::NewWindow();
该方法说来很简单,不过是根据不同的字符串从堆上分配一个SWindow对象,但是在C++中我们需要满足一条基本原则:内存在哪个模块中分配(从哪个模块的堆上分配)就必须被哪个模块释放。
在SOUI中,通常情况下控件都是由SOUI.DLL这个模块来分配内存的,也就是说SWindow * SWindowFactory::NewWindow()只会在SOUI模块中调用。 那么生成的对象在哪里释放呢?
这就需要看一下SWindow或者SSkinObjBase这两个类的实现了。
    class SOUI_EXP SWindow : public SObject
, public SMsgHandleState
, public TObjRefImpl2<IObjRef,SWindow>
{
SOUI_CLASS_NAME(SWindow, L"window")
//....
}; class SOUI_EXP SSkinObjBase : public TObjRefImpl<ISkinObj>
{
//......
};
SWindow和SSkinObjBase实际上都派生自TObjRefImpl这个模板类。下面看一下这个类的实现:
template<class T>
class TObjRefImpl : public T
{
public:
TObjRefImpl():m_cRef()
{
} virtual ~TObjRefImpl(){
} //!添加引用
/*!
*/
virtual void AddRef()
{
InterlockedIncrement(&m_cRef);
} //!释放引用
/*!
*/
virtual void Release()
{
InterlockedDecrement(&m_cRef);
if(m_cRef==)
{
OnFinalRelease();
}
} //!释放对象
/*!
*/
virtual void OnFinalRelease()
{
delete this;
}
protected:
volatile LONG m_cRef;
}; template<class T,class T2>
class TObjRefImpl2 : public TObjRefImpl<T>
{
public:
virtual void OnFinalRelease()
{
delete static_cast<T2*>(this);
}
};
TObjRefImpl一个重要的虚函数是void OnFinalRelease(){delete this;}

由于SWindow及SSkinObjBase是在SOUI模块中实现的,因此派生自这两个类的新的控件类及皮肤类最后都将在SOUI模块中被释放,从而保证了对象内存的分配、释放在一个模块。
这也就是说不管是SOUI模块内实现的控件还是在应用层扩展的控件一般情况下都应该向SOUI系统注册并经由SOUI内核来实现对象的分配与释放。 那么问题来了,是不是所有新控件都必须向系统注册呢?
当然不是的,注意OnFinalRelease是一个虚函数,只需要在新的控件类中增加一个
void OnFinalRelease(){delete this;}
就可以把控件内存的释放转移到应用层的模块了。如此你就可以在自己的模块中直接使用new来创建新控件了。(可以参考属性表控件中部分子控件的实现)

第二十一篇:SOUI中的控件注册机制的更多相关文章

  1. VFP中OCX控件注册检测及自动注册

    这是原来从网上搜集.整理后编制用于自己的小程序使用的OCX是否注册及未注册控件的自动注册函数. CheckCtrlFileRegist("ctToolBar.ctToolBarCtrl.4& ...

  2. 在VS2010中ActiveX控件注册方法,使用regsvr32命令

    上一篇小编展示了如何设置VS2010自带的ActiveX控件的容器测试程序,现在为大家演示一下如何注册ActiveX控件. 首先简单了解一下ActiveX控件的知识,ActiveX控件:简单来说,就是 ...

  3. 第二十一篇 Linux中的环境变量简单介绍

        环境变量之   PATH 定义解释器搜索用户执行命令的路径 获取PATH变量的值: echo $PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/us ...

  4. 第二十九篇:使用SOUI的SMCListView控件

    列表控件是客户端应用最常用的控件之一.列表控件通常只负责显示数据,最多通知一下APP列表行的选中状态变化. 现在的UI经常要求程序猿在列表控件里不光显示内容,还要能和用户交互,显示动画等等,传统的列表 ...

  5. Android中常用控件及属性

    在之前的博客为大家带来了很多关于Android和jsp的介绍,本篇将为大家带来,关于Andriod中常用控件及属性的使用方法,目的方便大家遗忘时,及时复习参考.好了废话不多讲,现在开始我们本篇内容的介 ...

  6. WPF中TreeView控件数据绑定和后台动态添加数据(二)

    写在前面:在(一)中,介绍了TreeView控件MVVM模式下数据绑定的方法.在这篇文章中,将总结给节点添加事件的方法,这样说有些不对,总之实现的效果就是点击某个节点,将出现对应于该节点的页面或者数据 ...

  7. WPF中Ribbon控件的使用

    这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可 ...

  8. iOS开发UI篇—使用picker View控件完成一个简单的选餐应用

    iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162 ...

  9. iOS开发UI篇—Quartz2D(自定义UIImageView控件)

    iOS开发UI篇—Quartz2D(自定义UIImageView控件) 一.实现思路 Quartz2D最大的用途在于自定义View(自定义UI控件),当系统的View不能满足我们使用需求的时候,自定义 ...

随机推荐

  1. 【GoLang】GO语言系列--002.GO语言基础

    002.GO语言基础 1 参考资料 1.1 http://www.cnblogs.com/vimsk/archive/2012/11/03/2736179.html 1.2 https://githu ...

  2. iOS NSObject 的 isa 属性的类型 Class

    以前对NSObject的isa属性也知道点,但是了解不深,今天看了这篇博文,感觉很好,总结一下: http://chun.tips/blog/2014/11/05/bao-gen-wen-di-obj ...

  3. CXGrid的使用技巧

    CXGrid的使用技巧 ========================================================================== 在主从TableView中 ...

  4. C# Winform中如何获取文件名与文件路径

    获取文件名方法: 用System.IO.Path.GetFileName和System.IO.Path.GetFileNameWithoutExtension(无扩展名)的方法 获取文件路径方法: / ...

  5. 7.django之自定义分页记录

    只是大概记录下步骤: 1.表结构: class UserProfile(models.Model): ''' 用户表 ''' user = models.OneToOneField(User,verb ...

  6. sql server 取日期

    Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM Select CONVERT(varchar(100), GETDATE( ...

  7. #ifndef -摘自百度百科

    #ifndef 标识1 //判断"标识1"是否定义,如果被定义则返回假,如果没有被定义则返回真. /**********************************/ 语句1 ...

  8. IOS- 自定义 UIButton

    #pragma mark init方法内部默认会调用initWithFrame: - (id)initWithFrame:(CGRect)frame { self = [super initWithF ...

  9. 35. Search Insert Position

    题目: Given a sorted array and a target value, return the index if the target is found. If not, return ...

  10. 让UserControl能显示焦点状态

    'set the control can display the focus status Protected Overrides Sub OnGotFocus(ByVal e As System.E ...