第10章
在XML
中创建窗体
魔兽世界用户界面的图形部分由一些普通的对象组成,如窗体、纹理和字体。纹理用于显示颜色、渐变效果或图形,而字体用于显示一些文本。窗体可以包含很多的控件。本章将介绍魔兽世界窗体系统的基础,并指导您在XML中绘制窗体。
10.1
了解UI对象
可以创建的用户界面对象主要有3种:
l 纹理(Texture)——纹理在游戏中被用于显示一些图形、颜色和颜色渐变效果。纹理使用<Texture>标签来创建。
l 字体(FontString)——字体被用来指定文本显示的字体、大小和颜色。还可以指定空心、阴影等文字标准效果。字体使用<FontString>标签创建。
l 窗体(Frame)——窗体作为一个容器,在用户界面中“包含”所有的纹理和字体。窗体还可以包含一些特定的子类型,例如按钮、编辑框以及卷轴信息窗体,本章随后将对这些子类型进行介绍。除此之外,一个窗体还可以包含其他窗体,这使得它们极其多变。窗体使用<Frame>标签创建。
10.1.1
为对象进行命名
每个基本用户界面对象都可以通过name属性为它们命名。而这些名字是可以在XML文件的其他对象中或Lua文件使用的。尽管名字冻在所有的情况下都有用,但为每个对象命名,以使得在你需要时可以引用到该对象是一个良好的习惯。
10.1.2
指定父对象
父/子关系带来的好处有三个。
l 当一个父对象被隐藏时,其所有的子对象都被隐藏。
l 当父对象发生缩放时,子对象同比例进行缩放。
l 当父对象发生透明时,子对象同比例透明。
暴雪的许多默认窗体继承自UIParent(
默然说话:即父对象是
UIParent),它是通过命令用于隐藏整个用户界面的一个特殊窗体,它还提供了对象整个用户界面的缩放。当创建我们自己的窗体时,最好使它们的父对象设置为UIParent,以保证它们如同其他窗体一样,随用户的设置而改变。
有三种方法可以设置对象之间的父/子关系:使用XML的parent属性;XML标签的层次关系;或者直接调用SetParent()方法。下面举例说明:
1.
使用属性
可以在XML窗体中使用parent属性来定义一个父/子关系。属性值应当被设置为父对象的名称。这种方法仅对窗体有效。例如:
<Frame name=”MyFrame” parent=”UIParent”>
</Frame>
2.
使用XML
层次结构
在XML文件中简单地通过位置的嵌套可以为每个对象指定一个父对象。下面的例子展示了一个包含单个纹理和单个字体的窗体。
<Frame name="MyFrame" parent="UIParent">
<Layers>
<Layer level="BACKGROUND">
<FontString name="MyText" />
<Texture name="MyGraphic" />
</Layer>
</Layers>
</Frame>
Layers标签用于组织所有的层,而Layer标签表示其中一个层,这个层里定义了一个字体和一个纹理,本章后面的内容会详细介绍。由于Frame标签包含了FontString和Texture标签,所以字体和纹理的父对象都是窗体。
3.使用SetParent()方法
一旦创建了一个对象(无论是在Lua中,还是在XML中),你就可以调用SetParent()方法来改变其父对象(这个方法自然是在Lua脚本中使用)。前面在XML中已经创建了一个MyFrame对象,那么当加载窗体后,我们可以在任何时间调用MyFrame:SetParent(Minimap)来将Minimap设置为MyFrame的父窗体。
10.1.3
设置对象尺寸
可以使用<Size>标签来设置对象的大小,使用绝对尺寸或相对尺寸均可:
1.
绝对尺寸
绝对尺寸用像素值定义一个对象的大小。例如,一个窗体可以定义为宽100像素,高50像素。这样的定义在XML中如下所示:
<Frame>
<Size x=”100” y=”50” />
</Frame>
也可以象下面这样来定义(暴雪在自己的XML中就是这样定义的):
<Frame>
<Size >
<AbsDimension x=”100” y=”50” />
</Size>
</Frame>
这两个定义的效果完全相同。
2.
相对尺寸
你还可以使用父窗体尺寸的百分比来表示一个窗体的高度和宽度下面的XML定义了两个窗体:(
默然说话:相对性就需要两个窗体,一个按照绝对的方式定义,另一个按照相对的方式定义。否则相对两字从何说起呢?)
<Frame name="MyFrame1">
<Size x="100" y="50" />
</Frame>
<Frame name="MyFrame2" parent="MyFrame1">
<Size>
<RelDimension x="0.5" y="0.5" />
</Size>
</Frame>
第一个窗体使用绝对值定义了窗体的大小,第二个窗体使用的就是相对尺寸。它(MyFrame2)相对于它的父窗体(MyFrame1)而定义了尺寸。在绝大多数情况下,我们都会使用绝对尺寸的形式,而不是相对尺寸的形式。这里只是告诉大家一个可用的方法。
10.1.4
锚定对象
在魔兽世界游戏中,所有对象的放置都通过一系列的锚点(anchor)完成,锚点将窗体的一个位置粘附在另一个窗体的某个位置上。表10-1展示了这些锚点,它们都在窗体的边框上。
表10-1
可用的锚定位置
|
|
|
左上
(TOPLEFT)
|
上
(TOP)
|
右上
(TOPRIGHT)
|
左
(LEFT)
|
中
(CENTER)
|
右
(RIGHT)
|
左下
(BOTTOMLEFT)
|
下
(BOTTOM)
|
右下
(BOTTOMRIGHT)
|
所有的锚点都在<Anchors>标签内定义,一个<Anchor>标签定义一个锚点,<Anchor>具备以下属性:
l point——锚定窗体的位置
l relativeTo——被锚定的窗体名称。如果不指定,默认父窗体
l relativePoint——被锚定窗体的位置
此外,<Anchor>标记还包含一个子标签<Offset>,它可以指定一个偏移值。(默
然说话:上面已经列出了所有的九个可以锚定的位置,它们都是准确的方位,那如果我们需要锚定到左上偏右
10像素呢?这时就需要偏移了。)下面的一段代码创建了一个窗体MyFrame,并将其锚定在UIParent的中间:
<Frame name="MyFrame" parent="UIParent">
<Size x="100" y="100" />
<Anchors>
<Anchor point="CENTER" relativePoint="CNETER" relativeTo="UIParent">
<Offset x="0" y="0" />
</Anchor>
</Anchors>
</Frame>
下面的例子创建了一个窗体MyFrame2,通过设置它的左上角锚定到MyFrame的右上角,把MyFrame2放在了MyFrame的右边,两个窗体水平对齐了。
<Frame name="MyFrame2" parent="UIParent">
<Size x="50" y="50" />
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeTo="MyFrame" />
</Anchors>
</Frame>
两个窗体锚定之后带来的一个负作用就是,一个窗体“粘”在了另一个窗体上,如上面的例子,MyFrame2就被“粘”在了MyFrame上,如果移动MyFrame,那么MyFrame2也会跟着一起移动。
在第二个窗体的锚定中,我们没有看到<Offset>标记。如果你不需要偏移,那你完全可以省略它。
10.1.5
将窗体和图形元素分
级
魔兽世界的用户界面系统提供了一个非常规整的方法,用于将图形元素放置于另一个的上层。它允许创建一个完全覆盖于另一个窗体上的窗体,或者由分布于各层的图形元素来得到最终图像。有2个级别:窗体级和图形级,这两个级别又分多层。
1.
窗体级
窗体级又可以分为八个层,这八个层主要决定了谁被谁遮挡,低层的窗体总会被高层的窗体覆盖。
表10-3
从低到高,所有可能的窗体层级
描述
|
举例
|
BACKGROUND
|
本层中所有的窗体都不会接收到鼠标事件,除非窗体等级大于
1
。
|
LOW
|
被默认用户界面用于增益状态窗体,耐久度窗体,团队界面以及宠物窗体。
|
MEDIUM
|
UIParent
及其所有子窗体的默认窗体等级,除非它们被重写
|
HIGH
|
被默认用户界面用于动作按钮,教程窗体,以及界面错误和警告窗体。
|
DIALOG
|
用于任何对话类型的窗体,它们弹出并等待用户的响应。
|
FULLSCREEN
|
本层应当包含所有的全屏窗体,如果世界地图或用户界面选项
|
FULLSCREEN_DIAGLOG
|
位于
FULLSCREEN
层之上的一个对话层,用于对话交互以及下拉菜单。
|
TOOLTIP
|
用于鼠标提示工具条,以使得它们可以总是能够显示。
|
在指定的层绘制窗体很容易,你只需要在XML中指定frameStrate属性即可:
<Frame name="MyFrame" parent="UIParent" frameStrata="HIGH">
</Frame>
在同一层中也可能会有多个窗体(
默然说话:特别是一般用户都不会只使用一个插件,这意味着我们设置的窗体会和其他插件的窗体共存),谁会遮挡谁呢?这由frameLevel属性设置,它的值是一个数,数字越大越靠前(也就是数字大的会遮挡住数字小的窗体)。另外,窗体还有一个toplevel,它是一个布尔值,当把它设置为真时,如果有鼠标点击这个窗体时,它会弹到最前面。
2.
图形级
在一个窗体中可以容纳很多元素,比如前面提到了Texture和FontString(它们都在<Layers>标签之内),还有图片。那么这些元素又是如何进行遮挡呢?它们也通过它们放置的层来决定谁遮挡谁。
表10-4
图形级的描述
描述
|
举例
|
BACKGROUND
|
窗体背景图应当放置在这一层
|
BORDER
|
此层一般放置窗体美化的图形边框。
|
ARTWORK
|
窗体中非功能性的美化插图应当放置于此层
|
OVERLAY
|
窗体的功能性部分,如按钮、文本框以及其他控件。
|
HIGHLIGHT
|
只有当鼠标悬停在窗体上时才显示的所有内容。
|
图形级不同的层次是通过<Layer>标签的level属性创建,例如:
<Frame name="MyFrame">
<Layers>
<Layer level="BACKGROUND">
</Layer>
<Layer level="HIGHLIGHT">
</Layer>
</Layers>
</Frame>
10.1.6
一般属性
表10-5 一般属性
属性
|
描述
|
Name
|
对象的名称,这个名字可以作为全局变量在
Lua
中访问。
|
Inherits
|
WoW
具有一个继承系统,允许开发者生成用于创建新窗体的模板。它可以接受一个用逗号分隔的窗体列表,这也意味着对象可以多继承。
|
Virtual
|
布尔值,指示一个窗体是否为虚模板。虚模板不能创建成对象。
|
setAllPoint
|
布尔值,指示窗体是否能粘附到父窗体的所有点上,这会让窗体的大小和位置都与父窗体相同。
|
Hidden
|
布尔值,用于指示创建的窗体默认是隐藏还是显示。
|
上表中列出了一系列应用于各对象的一般性属性,以及他们的作用。继承和模板将在第11章中深入讨论。
10.2
创建纹理
纹理是游戏客户端为用户界面渲染的二维图形元素。它们可以是从磁盘加载的图形文件,带有透明度的固定颜色值或是从一颜色到另一个的渐变。所有的这些类型,均使用<Texture>标签。
一个纹理元素可以拥有下面的属性,以及之前列出的一般属性:
l file——纹理文件的路径,用于装载,以及作为图形元素使用。
l aplphaMode——当对多个纹理进行分层时,使用的混合模式。它可以填下面的值:DISABLE、BLEND、ALPHAKEY、ADD或MOD。
10.2.1
添加颜色
为了令纹理使用固定的颜色,应当向纹理的定义中添加<Color>元素。这个元素接受4个属性(r,g,b,a),分别对应红、绿、蓝、透明度值。每个值都只能在0.0~1.0之间的数。
<Frame name="MyFrame">
<Layers>
<Layer level="BACKGROUND" setAllPoint="true">
<Color r="1.0" g="0.1" b="0.1" a="1.0" />
</Layer>
</Layers>
</Frame>
上面的代码创建了一个窗体,窗体仅包含红色纹理。这种纹理使用setAllPoint来表示其应当与父对象(即窗体本身)的尺寸与位置完全一致。
10.2.2
添加渐变效果
纹理还可以是两种不同颜色间的渐变。这可以使用<Gradient>标记来设定最小颜色和最大颜色,并以此定义一个渐变效果。
<Gradient>有orientation属性,可以赋值为HORIZONTAL(垂直渐变)或VERTICAL(水平渐变)。默认是HORIZONTAL。标记必须包含两个元素,<MinColor>和<MaxColor>,均为ColorType类型。
仅一个<Gradient>标记并不会创建渐变效果,它必须与<Color>标记结合使用才可以。在渐变效果的每个位置,从<Color>标记得到的颜色值与当前的渐变值相乘,来决定屏幕上应当显示什么样的颜色。这样处理最简单的实现方法是具有下面的颜色值。
<Color r=”1.0” g=”1.0” b=”1.0” a=”1.0” />
这保证了你的渐变值从<MinColor>开始,到<MaxColor>结束,由于每个分量值都为1.0,因此其在相乘时并不改变每个颜色值。
<Ui xmlns="http://www.blizzard.com/wow/ui/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.blizzard.com/wow/ui/
../FrameXML/UI.xsd">
<Frame name="GradientTest" parent="UIParent">
<Size x="200" y="200" />
<Anchors>
<Anchor point="CENTER" relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<!--$parent是一个通配符,它表示如果在Lua中要引用这个对象,需要加上它的父对象的名称,比如这里的名称就是MyFormHorizontal-->
<Texture name="$parentHorizontal">
<Size x="200" y="100" />
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPLEFT" />
</Anchors>
<Color r="1.0" g="0.0" b="0.0" a="1.0" />
<Gradient orientation="HORIZONTAL">
<MinColor r="1.0" g="0.0" b="0.0" a="1.0" />
<MaxColor r="0.0" g="0.0" b="0.0" a="1.0" />
</Gradient>
</Texture>
<Texture name="$parentVertical">
<Size x="200" y="100" />
<Anchors>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT" />
</Anchors>
<Color r="1.0" g="1.0" b="1.0" a="1.0" />
<Gradient orientation="VERTICAL">
<MinColor r="0.0" g="0.0" b="0.0" a="1.0" />
<MaxColor r="1.0" g="1.0" b="0.0" a="1.0"/>
</Gradient>
</Texture>
</Layer>
</Layers>
</Frame>
</Ui>
10.2.3
添加图形元素
向纹理添加图形十分简单,只需在file属性中提供一个正确的文件名即可。下面的XML在屏幕的中间定义了一个100×100的窗体,显示了牧师的暗言术:痛的法术图标。
<Frame name="GraphicTest" parent="UIParent">
<Size x="100" y="100" />
<Anchors>
<Anchor point="CENTER" relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentPainIcon"
file="Interface/Icons/Spell_Shadow_ShadowWordPain" setAllPoints="true">
</Texture>
</Layer>
</Layers>
</Frame>
10.3
使用字体创建文本
向窗体内添加文本需要在窗体中创建一个FontString标签,并将它锚定到窗体上。<FontString>必须位于<Layer>标签之内。除一般属性外,FontString还有一些属性它们可以改变文本的样式。
表10-6 FontString
元素可用的属性
属性
|
描述
|
font
|
用于显示文件的字体文件的路径。它可以是包含于
WoW
中的文件,也可以是被自定义插件所支持的字体。
|
bytes
|
一个正数,用来指定
FontString
最多可以显示的字符数。
|
text
|
显示的文本
|
spacing
|
行间距,以像素为单位
|
outline
|
指定字符串的轮廓类型,应当为下面值的一种:
NONE
、
NORMAL
、
THICK
|
monochrome
|
一个布尔类型,指示字体是否以单色(灰度)显示
|
nonspacewrap
|
一个布尔值,指示没有空格的长字符串是否应当扭曲或是截断。
|
justifyV
|
使用
TOP
、
MIDDLE
、
BOTTOM
值中的一个指定文本的垂直修正。
|
justifyH
|
使用
LEFT
、
CENTER
、
RIGHT
值中的一个指定文本的水平修正。
|
maxLines
|
指定在一个字体字符串中显示的最大行数
|
10.3.1
使用模板
可以使用inherits属性让字体继承其它已定义好的值,下一小节是一个例子。
10.3.2
使用的例子
下面的代码创建了一个窗体,它可以在你的屏幕中央显示一个字体(使用GameFontNormalHuge模板):
10.3.3
进一步自定义
下面的标签可以用于定制一个字体的显示:
l <FontHeight>——可以使用val属性来指定,或者使用<AbsValue>或<RelValue>。以绝对值或相对值来指定一个字体的高度。
l <Color>——改变字体的颜色,使用r、g、b和a属性来进行指定。
l <Shadow>——向字体增加阴影效果。阴影的颜色和位置通过<Color>和<Offset>标签来指定,两个都是必选。
对于一个实际绘制到屏幕上的对象,它必须满足下面的要求:
(1)对象必须包含一些可视组件,如文本、图形、背景色或边框。若全部都没有,则窗体是不可见的。同时,没有任何内容的纹理或是字体也被认为是不可见的。
(2)对象的高度和宽度必须为正数。这看起来似乎是必然的,但很容易被忽略。
(3)对象必须被放置于屏幕边框内的某处。若它被锚定在可见窗口的外部,则无法被显示。
一个对象可以有两种方式被隐藏:
l 通过在XML定义中设定hidden属性为真
l 通过调用对象的:Hide()方法
另外,我们还可以通过IsShown()和IsVisible()方法来判断窗体是否处于隐藏的状态。
10.4
探讨窗体类型
除了<Frame>之外,还有几种窗体类,这里将对这些类型进行介绍,并阐述它们的用途。关于XML模式中可用的这几种类型更详细的信息,可查看http://wiki.cwowaddon.com/XML%E7%94%A8%E6%88%B7%E7%95%8C%E9%9D%A2(英文)
10.4.1
按钮(Button)
通过单击一个有意义的图标或带有文本的可见按钮,用户可以进行你输入。按钮可以对单击动作进行反馈,在一些情况下,甚至可以释放法术或将一个单位设定为目标。按钮在鼠标移过、鼠标单击或不可用时经常显示不同的纹理。许多按钮显示文本或一些图标来传达一些信息。
10.4.2
复选按钮(Check Button)
复选按钮是一种特殊的按钮,它有两种状态:选中和未选中。它们用于指明一些可选的选项,并且通常伴随着文本标签来解释复选所改变的选项。复选按钮主要在自定义配置界面和用户界面选项窗体中使用。
10.4.3
颜色选择(Color Select)
颜色选择窗体在聊天界面中用于改变通道的输出颜色,以及聊天窗口的背景色。它以对话框的形式弹出,允许您为指定的选项选择一个颜色。
10.4.4
编辑框(Editbox)
编辑框类型的窗体允许输入文本,并带有基本的历史记录和编辑功能。我们输入聊天对话的那个细长的窗口就是最简单的编辑框示例。
10.4.5
游戏工具提示(Game ToolTip)
游戏工具提示是一个简单的窗体,它可以显示两栏数据,对鼠标所悬停的UI元素进行进一步的解释,这些UI元素包括按钮、物品甚至是三维世界中的玩家角色等。
10.4.6
消息窗体(Message Frame)
消息窗体在游戏中用于向玩家发送一些错误、警告或者消息。
10.4.7
小地图(Minimap)
小地图用于在魔兽世界中进行简单的导航,并且仅存在于默认小地图界面中。
10.4.8
模型(Model)
模型用于在游戏中显示三维模型,并且具有旋转和缩放的功能。
10.4.9
滚动信息窗体(Scrolling Message Frame)
魔兽世界作为一个大型多人互动角色扮演类游戏,在玩家之间具有极其大量的信息交流,它们通常在滚动信息窗体显示,也称为聊天窗体。
10.4.10
滚动窗体(Scrolling Frame)
当一些信息过大,在原始的窗口中显示不下时,可以使用滚动窗体来允许用户垂直或水平进行滚动(默然说话:在魔兽世界里通常都是垂直滚动)。任务日志窗体就是典型的滚动窗体。
10.4.11
简单的HTML窗体
这个窗体允许使用一些基本的类HTML标签,这样数据的表达就更容易了。
10.4.12
滑动器(Slider)
滑动器用于一个选项所需要的值在一个范围内的情况。比如声音大小的调节。滑动器允许你设定一个最大值和一个最小值,并且可以设置每次调整的默认步长。
10.4.13
状态栏(Status Bar)
经验窗口就是一个状态栏。你必须为它提供一个用来显示的纹理,然后设置最大/最小值。
10.4.14
飞行路线窗体
访问飞行管理员的时候都可以看到这个窗体,它用于显示飞行路径图,并在其中的给定点间画出路线。
10.5
小结
本章介绍了使用XML创建窗体的基础,包括如何定义窗体大小、控制复杂的窗体位置,以及向窗体中添加纹理和文本。此外,还解释了窗体及图形层的概念。下一章我们将学习如何给窗体添加行为。