尽管SOUI已经内置了大部分常用的控件,很显然内置控件很难满足各种应用的形式各异的需求。

因此只有提供足够的扩展性才能满足真实应用场景。

除了将系统尽可能的组件化外,SOUI在控件自绘(SWindow)及绘图对象(ISkinObj)两个方面提供用户扩展。

绘图对象(ISkinObj)的扩展

系统内置了如SSkinImgList, SSkinImgFrame, SSkinScrollbar等绘图对象,在窗口中通过引用这些绘图对象可以绘制出不同的预定义图形图象(如按钮,滚动条,九宫格等)。

实际上用户可以实现任意的绘图对象并把它们注册到系统里,以便在XML及代码中使用。

下面先看一下实现一个ISkinObj需要实现哪些接口:

    /**
* @struct ISkinObj
* @brief Skin 对象
*
* Describe
*/
class SOUI_EXP ISkinObj : public SObject,public TObjRefImpl2<IObjRef,ISkinObj>
{
public:
ISkinObj()
{
}
virtual ~ISkinObj()
{
} /**
* Draw
* @brief 将this绘制到RenderTarget上去
* @param IRenderTarget * pRT -- 绘制用的RenderTarget
* @param LPCRECT rcDraw -- 绘制位置
* @param DWORD dwState -- 绘制状态
* @param BYTE byAlpha -- 透明度
* @return void
* Describe
*/
virtual void Draw(IRenderTarget *pRT, LPCRECT rcDraw, DWORD dwState,BYTE byAlpha=0xFF)=; /**
* GetSkinSize
* @brief 获得Skin的默认大小
* @return SIZE -- Skin的默认大小
* Describe 派生类应该根据skin的特点实现该接口
*/
virtual SIZE GetSkinSize()
{
SIZE ret = {, }; return ret;
} /**
* IgnoreState
* @brief 查询skin是否有状态信息
* @return BOOL -- true有状态信息
* Describe
*/
virtual BOOL IgnoreState()
{
return TRUE;
} /**
* GetStates
* @brief 获得skin对象包含的状态数量
* @return int -- 状态数量
* Describe 默认为1
*/
virtual int GetStates()
{
return ;
}
};

ISkinObj是一个派生自SObject及TObjRefImpl2<IObjRef,ISkinObj>的类,提供了几个状态查询相关的接口,也提供了一个Draw接口来在IRenderTarget上绘制该绘制对象。

注意的是,这些接口中只有Draw接口是纯虚接口。

在它的基类中,SOjbect使得ISkinObj可以方便的从XML配置文件中初始化,而TObjRefImpl2<IObjRef,ISkinObj>则提供引用计数的实现。

内置的ISkinObj不支持显示GIF图片,以显示GIF图象为例来分析如何扩展绘图对象来支持GIF图片显示。

对象定义(trunk\controls.extend\gif\SSkinGif.h)

namespace SOUI
{
class SGifFrame
{
public:
CAutoRefPtr<IBitmap> pBmp;
int nDelay;
}; /**
* @class SSkinGif
* @brief GIF图片加载及显示对象
*
* Describe
*/
class SSkinGif : public ISkinObj
{
SOUI_CLASS_NAME(SSkinGif, L"gif")
public:
SSkinGif():m_nFrames(),m_iFrame(),m_pFrames(NULL)
{ } //初始化GDI+环境,由于这里需要使用GDI+来解码GIF文件格式
static BOOL Gdiplus_Startup();
//退出GDI+环境
static void Gdiplus_Shutdown(); virtual ~SSkinGif()
{
if(m_pFrames) delete [] m_pFrames;
} /**
* Draw
* @brief 绘制指定帧的GIF图
* @param IRenderTarget * pRT -- 绘制目标
* @param LPCRECT rcDraw -- 绘制范围
* @param DWORD dwState -- 绘制状态,这里被解释为帧号
* @param BYTE byAlpha -- 透明度
* @return void
* Describe
*/
virtual void Draw(IRenderTarget *pRT, LPCRECT rcDraw, DWORD dwState,BYTE byAlpha=0xFF); /**
* GetStates
* @brief 获得GIF帧数
* @return int -- 帧数
* Describe
*/
virtual int GetStates(){return m_nFrames;} /**
* GetSkinSize
* @brief 获得图片大小
* @return SIZE -- 图片大小
* Describe
*/
virtual SIZE GetSkinSize()
{
SIZE sz={};
if(m_nFrames> && m_pFrames)
{
sz=m_pFrames[].pBmp->Size();
}
return sz;
} /**
* GetFrameDelay
* @brief 获得指定帧的显示时间
* @param int iFrame -- 帧号,为-1时代表获得当前帧的延时
* @return long -- 延时时间(*10ms)
* Describe
*/
long GetFrameDelay(int iFrame=-); /**
* ActiveNextFrame
* @brief 激活下一帧
* @return void
* Describe
*/
void ActiveNextFrame(); /**
* SelectActiveFrame
* @brief 激活指定帧
* @param int iFrame -- 帧号
* @return void
* Describe
*/
void SelectActiveFrame(int iFrame); /**
* LoadFromFile
* @brief 从文件加载GIF
* @param LPCTSTR pszFileName -- 文件名
* @return int -- GIF帧数,0-失败
* Describe
*/
int LoadFromFile(LPCTSTR pszFileName); /**
* LoadFromMemory
* @brief 从内存加载GIF
* @param LPVOID pBits -- 内存地址
* @param size_t szData -- 内存数据长度
* @return int -- GIF帧数,0-失败
* Describe
*/
int LoadFromMemory(LPVOID pBits,size_t szData); SOUI_ATTRS_BEGIN()
ATTR_CUSTOM(L"src",OnAttrSrc) //XML文件中指定的图片资源名,(type:name)
SOUI_ATTRS_END()
protected:
LRESULT OnAttrSrc(const SStringW &strValue,BOOL bLoading);
int LoadFromGdipImage(Gdiplus::Bitmap * pImg);
int m_nFrames;
int m_iFrame; SGifFrame * m_pFrames;
};
}//end of name space SOUI

对象注册:

        theApp->RegisterSkinFactory(TplSkinFactory<SSkinGif>());//注册SkinGif

对象的使用(trunk\demo\uires\xml\dlg_main.xml):

  <skin>
<!--局部skin对象-->
<gif name="gif_horse" src="gif:gif_horse"/>
<gif name="gif_penguin" src="gif:gif_penguin"/>
</skin>

这里的gif标签与SSkinGif类中的宏SOUI_CLASS_NAME(SSkinGif,L"gif")中的“gif”是匹配的。

到此,在布局XML及程序中都可以获得这个SSkinGif对象的指针了。

控件的扩展

控件的扩展和绘图对象的扩展套路类似,也是先从系统提供的基础类派生,再注册到系统,最后再XML或者代码中使用。

和绘图对象不同在于,控件是UI,需要处理各种UI相关的消息以及向程序发出各种控件特有的事件。

同样我们还是以GIF显示的控件为例(trunk\controls.extend\gif\SGifPlayer.h):

namespace SOUI
{ /**
* @class SGifPlayer
* @brief GIF图片显示控件
*
* Describe
*/
class SGifPlayer : public SWindow
{
SOUI_CLASS_NAME(SGifPlayer, L"gifplayer") //定义GIF控件在XM加的标签
public:
SGifPlayer();
~SGifPlayer(); /**
* PlayGifFile
* @brief 在控件中播放一个GIF图片文件
* @param LPCTSTR pszFileName -- 文件名
* @return BOOL -- true:成功
* Describe
*/
BOOL PlayGifFile(LPCTSTR pszFileName); protected://SWindow的虚函数
virtual CSize GetDesiredSize(LPRECT pRcContainer); public://属性处理
SOUI_ATTRS_BEGIN()
ATTR_CUSTOM(L"skin", OnAttrGif) //为控件提供一个skin属性,用来接收SSkinObj对象的name
SOUI_ATTRS_END()
protected:
HRESULT OnAttrGif(const SStringW & strValue, BOOL bLoading); protected://消息处理,SOUI控件的消息处理和WTL,MFC很相似,采用相似的映射表,相同或者相似的消息映射宏 /**
* OnPaint
* @brief 窗口绘制消息响应函数
* @param IRenderTarget * pRT -- 绘制目标
* @return void
* Describe 注意这里的参数是IRenderTarget *,而不是WTL中使用的HDC,同时消息映射宏也变为MSG_WM_PAINT_EX
*/
void OnPaint(IRenderTarget *pRT); /**
* OnTimer
* @brief SOUI窗口的定时器处理函数
* @param char cTimerID -- 定时器ID,范围从0-127。
* @return void
* Describe SOUI控件的定时器是Host窗口定时器ID的分解,以方便所有的控件都通过Host获得定时器的分发。
* 注意使用MSG_WM_TIMER_EX来映射该消息。定时器使用SWindow::SetTimer及SWindow::KillTimer来创建及释放。
* 如果该定时器ID范围不能满足要求,可以使用SWindow::SetTimer2来创建。
*/
void OnTimer(char cTimerID); /**
* OnShowWindow
* @brief 处理窗口显示消息
* @param BOOL bShow -- true:显示
* @param UINT nStatus -- 显示原因
* @return void
* Describe 参考MSDN的WM_SHOWWINDOW消息
*/
void OnShowWindow(BOOL bShow, UINT nStatus); //SOUI控件消息映射表
SOUI_MSG_MAP_BEGIN()
MSG_WM_TIMER_EX(OnTimer) //定时器消息
MSG_WM_PAINT_EX(OnPaint) //窗口绘制消息
MSG_WM_SHOWWINDOW(OnShowWindow)//窗口显示状态消息
SOUI_MSG_MAP_END() private:
SSkinGif *m_pgif;
int m_iCurFrame;
}; }

实现了该类以后,在WinMain中注册:

        theApp->RegisterWndFactory(TplSWindowFactory<SGifPlayer>());//注册GIFPlayer

我们可以在布局XML中创建GIF控件控件并显示了(trunk\demo\uires\xml\dlg_main.xml):

        <gifplayer pos="10,10" skin="gif_horse" name="giftest" cursor="ANI_ARROW"/>
<button width="250" height="30" name="btnSelectGif">load gif file</button>
<gifplayer pos="10,150" skin="gif_penguin"/>

上面的gifplayer节点即表示从XML中创建两个SGifPlayer类对象。

而gifplayer对象的skin属性则引用前面定义的SSkinGif对象。

备注:

实际上更多扩展技巧可以参考系统内置的控件的实现。内置控件与扩展控件唯一的区别就在于由谁实现将控件向系统注册。

内置控件在SOUI内核初始化的时候自动注册,而扩展控件则需要手动增加一行注册代码。

效果预览

第十篇:扩展SOUI的控件及绘图对象(ISkinObj)的更多相关文章

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

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

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

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

  3. WPF 精修篇 Winform 嵌入WPF控件

    原文:WPF 精修篇 Winform 嵌入WPF控件 首先 创建WPF控件库 这样就有了一个WPF界面 在wpf中增加界面等 在winform中增加WPFDLL 重新生成解决方案 在左侧工具栏 出现W ...

  4. WPF 精修篇 WPF嵌入Winfrom控件

    原文:WPF 精修篇 WPF嵌入Winfrom控件 先增加DLL 支持 使用  WindowsFormsHost 来加载Forms的控件 引用命名空间 xmlns:forms="clr-na ...

  5. Qt 在控件上面绘图 label,pushbutton。。。。。

    最近有点时间,就研究研究Qt ,提升一下自己 我记得我在刚开始学习Qt 的时候,想要在一个控件上面绘制图形,那就要构建一个新类来调用该控件的绘图函数 今天看到了狗哥的学习博客,感觉自己好渺小啊,按照狗 ...

  6. 第二十六篇:两个SOUI新控件 ---- SListView和SComboView(借用Andorid的设计)

    SOUI原来实现的SListBoxEx的效率一直是我对SOUI不太满意的地方.包括后来网友实现的SListCtrlEx. 这类控件为每一个列表项创建一个SWindow来容纳数据,当数据量比较大(100 ...

  7. C# 扩展方法奇思妙用高级篇六:WinForm 控件选择器

    在Web开发中,jQuery提供了功能异常强大的$选择器来帮助我们获取页面上的对象.但在WinForm中,.Net似乎没有这样一个使用起来比较方便的选择器.好在我们有扩展方法,可以很方便的打造一个. ...

  8. ExtJS6.0扩展日期选择控件为也可以选择时间

    PS:ExtJS自带的日期选择控件只能够选择日期,但是现在的需求需要精确到秒,所以在网上搜索了一些例子(大部分是4.0的)作为参考,然后改出了6.0可用的一个日期时间选择控件. 1.找到extjs6. ...

  9. 扩展easyUI tab控件,添加加载遮罩效果

    项目里要用HighChart显示图表,如果返回的数量量太多,生成图表是一个很耗时的过程.tab控件又没有显示遮罩的设置(至少本菜是没有找到), Google了一下,根据另一个兄台写的方法,拿来改造了一 ...

随机推荐

  1. java servlet的工作原理

    servlet本质上就是java类嘛.不过是有特殊规范的java类而已.下面就说一说为什么servlet要有特殊规范. 首先,考虑一下什么地方用servlet,WEB应用,而且是需要servlet容器 ...

  2. [k]web页面-browser兼容问题-1

    1:空的a标签在IE7/8下不能点击(2015-05-22) html代码: <ul class='oUl'><li><a href="#"> ...

  3. 【leetcode】Word Break II

    Word Break II Given a string s and a dictionary of words dict, add spaces in s to construct a senten ...

  4. hdu 1195

    题意:就是给你n组的四位数,在一次变化中又一位数字可以变化,而变化的方式为加一减一或者是与隔壁的互换,注意,是每一个数字都可以, 求最少的变化次数到达目标的数字 一看这个就应该知道这是一个bfs的题目 ...

  5. Django用户管理及认证

    同步组http://www.douban.com/group/topic/29387804/ ldapsearch -x -w password -D "cn=me,cn=Users,dc= ...

  6. Spring AOP基于配置文件的面向方法的切面

    Spring AOP基于配置文件的面向方法的切面 Spring AOP根据执行的时间点可以分为around.before和after几种方式. around为方法前后均执行 before为方法前执行 ...

  7. Unity3d UGUI序列帧动画

    代码 using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine. ...

  8. Delphi TcxCurrencyEditt控件说明

    金额类控件说明: AlignWithMargins:是否显示边框.由Margins 属性来设置边框的值 Anchors:控件停靠,来处理窗口最大化或是调动里的位置 AutoSize:是否自动变化大小 ...

  9. android快速开发--常用utils类

    1.日志工具类L.java package com.zhy.utils; import android.util.Log; /** * Log统一管理类 * * * */ public class L ...

  10. UVA 11827 Maximum GCD

    F - Maximum GCD Time Limit:1000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Given the ...