当前位置: BOLT界面引擎 > 知识库文章 > HelloBolt系列教程 > HelloBolt2:创建窗口和对象树

HelloBolt2:创建窗口和对象树

作者:Tsukasa

      HelloBolt2HelloBolt1的基础之上,创建窗口,并在窗口中贴出一张半透明的底图,效果如下所示:
                    
         从效果图中可以看到,窗口有着透明的圆角,而且透过窗口可以看到之下的桌面。接触过windows开发的人都应该知道,这样一个半透明的界面,用传统的windows开发实现起来是很不容易的。让我们进入Bolt的教程,来看看如何用Bolt简单搞定。
        
 
在HelloBolt.cpp中的工作与HelloBolt1中基本相同,唯一不同的是指定加载名为HelloBolt2的XAR包。
Bolt对界面交互的解构是将界面抽象为树结构(UIObjectTree),将界面上的各种元素(贴图,文字等)抽象为界面对象(UIObject),将UIObject加入到UIObjectTree上的不同层次(zorder)和不同位置之上组成界面。同时,UIObjectTree需要一个容器窗口(HostWnd)让操作系统将各种输入事件发给UIObjectTree处理,并能把UIObjectTree渲染生成的界面显示展示到屏幕上。所以,用Bolt创建界面的主干就是创建UIObjectTree和与之广联的HostWnd。
如果完全以编程的方式,创建空UIObjectTree,创建各种UIObject,再通过接口往UIObjTree中加入UIObject,这样的做法不够直观,而且枯燥复杂,开发效率低,且不易维护。为了更加高效,直观的组织UIObjectTree ,Bolt提供了模板(Template)机制,在布局xml文件中,以树状结构组织的特定xml节点来定义对象树模板(ObjectTree Template)。
模板(Template)机制是支持界面布局的基础,所谓模板,就是以xml格式静态定义Bolt各类对象(包括UIObjectTree, HostWnd, UIObject, Animation)的属性。之后再从模板创建对象实例,那么对象实例的属性值就已经被预定义,不需要通过编程方式设置。比如定义一个对象树模板(ObjectTree Template),并在模板定义中加入若干指定了层次(zorder)和位置的UIObject, 那么从该模板上创建出的UIObjectTree实例就如模板定义已经含有被布局好的UIObject.
在HelloBolt2 XAR包中加入layout目录,在该目录下加入布局xml。MainWnd.xml中定义对象树模板和容器窗口模板(HostWnd Template),xml节点如下:
<objtreetemplate id="HelloBolt.Tree" class="ObjectTreeTemplate">
     <hostwndtemplate id="HelloBolt.Wnd" class="FrameHostWnd">
在HelloBolt2的入口脚本onload.lua中,需要从模板创建UIObjectTree和HostWnd并关联之, 这样当HelloBolt2被Bolt加载时,就会打开一个窗口并展示内容了。
转到onload.lua中的代码:
local templateMananger = XLGetObject("Xunlei.UIEngine.TemplateManager")
这行,XLGetObject接口获取通过XLLuaRuntime的XLLRT_RegisterGlobalObj接口以特定id注册到Bolt运行环境中的全局对象,Bolt内置的核心对象都可以在lua脚本中通过调用XLGetObject来获取,id为"Xunlei.UIEngine.TemplateManager"的对象是模板管理器对象,在布局xml中定义的各种模板都可以通过模板管理器的GetTemplate()接口来获取(模板指南)。

local frameHostWndTemplate = templateMananger:GetTemplate("HelloBolt.Wnd","HostWndTemplate")

local frameHostWnd = frameHostWndTemplate:CreateInstance("MainFrame")
以上两行,调用模板管理器的GetTemplate()方法获取模板对象,然后通过模板的CreateInstance方法以创建该模板的实例对象。这样就通过MainWnd.xml布局中定义的容器窗口模板创建了HostWnd对象。

local objectTreeTemplate = templateMananger:GetTemplate("HelloBolt.Tree","ObjectTreeTemplate")

         local uiObjectTree = objectTreeTemplate:CreateInstance("MainObjectTree")
同样,以上两行从模板上创建了UIObjectTree对象。

frameHostWnd:BindUIObjectTree(uiObjectTree)

frameHostWnd:Create()
以上两行,将HostWnd对象和UIObjectTree对象关联,之后从HostWnd对象上创建出窗口来。
 
 
回到MainWnd.xml中,仔细看看如何定义一个模板:
<objtreetemplate id="HelloBolt.Tree" class="ObjectTreeTemplate">
以上节点定义中,节点名指定模板的类型,是对象树模板时指定为objtreetemplate, id属性指定模板id(需是XAR包内唯一的),class属性指定模板类,决定了可以在模板中设置的属性,以及从模板创建出来的对象类型。<attr>子节点中可以指定UIObjectTree的各种属性,这里设置其位置为-200,-200,2000,2000的矩形区域(Bolt引擎坐标系简介)。
如果UIObjectTree上没有加入任何UIObject, 它的渲染输出一定是空白的。为了达到效果图所示的效果,要在UIObjectTree上加入一个用于显示位图的UIObject——ImageObject:
<obj id="app.bkg" class="ImageObject">
以上xml节点在UIObjectTree模板上加入一个id为app.bkg ,class为ImageObject的UIObject。同一UIObjectTree上的不同UIObject的id必须不同(可以为空,但是为空时无法通过id索引到该对象),class为Bolt的各种内建UIObject类型,如 LayoutObject, ImageObject, TextureObject, TextObject等等, 也可以是在布局xml中通过control节点定义的自定义控件类型。同样在<obj>的<attr>子节点中,定义该ImageObject对象的各种属性,包括位置(left,top,width,height),透明度(alpha), 以及位图资源(image),就是我们要在窗口上显示的底图。
     <image>节点中指定的位图资源,是以字符串id标识的。Bolt用资源管理器来统一管理各种资源,包括位图,纹理,颜色,字体,曲线等等。在XAR包被加载时,XAR中的资源包会被Bolt的资源管理器加载。然后就可以在界面布局中通过资源的id来引用资源。
     现在我们来看看如何在XAR包中添加资源包。首先在XAR包的res目录里加入一个子目录, res/default/,资源包中需要在根目录存在resource.cfg文件以指定该资源包的名称。然后建立xml文件配置资源,分配资源id。在资源包中加入我们要使用的位图,即我们要在窗口中显示的背景图,将位图素材bkg.png放入default目录,为了方便管理,我们在资源包中加入子目录统一放置素材文件,这里放入default\bitmap目录中;建立bitmap.xml文件,在其中添加如下xml节点:
<XLUE>
<resource>
 <bitmap id="app.bkg" path="bitmap\bkg.png" />
</resource>
</XLUE>
定义一个id为app.bkg的位图资源,其素材为bitmap\bkg.png。这样,在MainWnd.xml中的ImageObject对象的<image>属性就表明,该ImageObject对象展示bkg.png这张位图(Bolt引擎资源简介) 。
 
     这样UIObjectTree的模板就定义好了,从该模板上创建的UIObjectTree对象上已经加入了一个ImageObject对象,并且该ImageObject对象展示bkg.png位图资源。当该UIObjTree关联到HostWnd上时,就会在窗口中显示出bkg.png。
     再看HostWnd的模板定义,xml节点如下:
<hostwndtemplate id="HelloBolt.Wnd" class="FrameHostWnd">
与UIObjectTree模板类似的id和class属性,Bolt提供了若干功能不同的HostWnd class(HostWnd手册),用于程序主窗口选择FrameHostWnd class。<attr>子节点中定义HostWnd的各种属性,<mainwnd>设1指定为主窗口;<layered>设1指定为Windows平台下的layered window,若设0为unlayered window,在windows下只有指定为layered window才可以为窗口指定透明度,当layered window遮盖其他窗口时,在窗口中贴出透明或者半透明的底图时才能正确被与下面的窗口内容混合(MSDN Layered Window)。若为unlayered window, 则无法半透明显示窗口;<left><top><width><height>指定HostWnd的大小和位置,注意因为UIObjectTree的渲染结果要在窗口中显示,所以窗口大小必须足够大才能将渲染结果完整的展示出来,因为我们要贴出的底图大小被设置为429*267,所以我们的窗口大小要不小于这个尺寸。    
        在布局xml中定义好了模板之后,还需要另外两步工作才能让定义好的模板可以在布局xml或者lua脚本中被使用:
1.    为了提高加载效率, Bolt加载template , control, animation等在XAR的布局xml中定义的元素时,需要一个映射表nametalbe.cfg指明要加载的某个template是定义在哪个文件中的,每次在XAR中更新了这些元素(比如新加入一个template, 或者重新指定了template 的 id等)时,需要使用XLUECL工具(XLUECL工具手册)更新nametable.cfg。在命令行中,用如下命令:
.\tools\xluecl.exe -xar .\HelloBolt\XAR\HelloBolt2\
为HelloBolt2 XAR包生成nametable.cfg。
2.   HelloBolt2的XAR包中的配置文件package.cfg,相较HelloBolt1多出如下两个节点:
<nametablecfg path="./nametable.cfg" type="xml"/>
<mainres package="default"/>
分别指定该XAR的nametable文件和默认资源包,也就是HelloBolt2中包含图片的名为default的资源包。
 

迅雷公司 版权所有 Copyright 2003-2010 Thunder Inc.All Rights Reserved. 意见反馈:xl7doc@xunlei.com