[翻译]魔兽世界插件基础

来源:互联网 发布:淘宝怎么开游戏店铺 编辑:程序博客网 时间:2024/04/24 21:24
原文:http://www.wowwiki.com/XML_User_Interface

World of Warcraft has a fairly powerful layout engine for creating user interface. 魔兽世界给用户交互界面提供了一个非常强大的布局引擎。
The Basics 基础
An XML file is a collection of elements (with a start and end tag), of which the User Interface files are no exception.  XML文件是标签元素的集合(开始标签和结束标签),Interface文件也是如此。
There are two main types of elements that appear in the UI XML files. UI XML文件中有两类标签元素。
The first type are those that declare user interface items (or widgets), such as Buttons, Frames, Checkboxes. 第一类是用户的界面元素,如按钮,框体,选择框等。
We will call these widget elements. 我们称它们为widget元素。
The second type of elements, which always occur inside the first type, define properties and behaviour of the widgets. 第二类标签总是定义在第一类标签里,用来描述widget的属性和行为。
We will call these property elements. 我们称第二类标签为property元素。
Here is an example: 这是一个例子:

<Button name="MyAddon_Button">
  <Anchors>
    <Anchor point="CENTER"/>
  </Anchors>
</Button>

The Button element is of the first type, in other words a widget element. 例子中第一个元素是按钮,它就是一个widget元素。
Its appearance in the XML file causes a Button with the name MyAddon_Button to be created. 第一行创建了一个名字是"MyAddon_Button"的按钮。
The elements inside it (such as Anchors, Anchor) define its properties, hence are of the second type. 在按钮元素的里面用Anchors元素定义了按钮的特性,Anchors就属于第二种类型的元素了。
The general structure is always the same, you have elements representing widgets, and other elements inside them representing their properties. 通常的文件结构就是这样的,首先定义widget,然后在widget内用properties描述它的特性。
It can also happen that a widget element is inside another one. 这样的结构也可以用来描述一个widget包含另外一个widget的情况。
For example:例如:

<Frame name="MyAddon_Frame">
  <Anchors>
    <Anchor point="CENTER"/>
  </Anchors>
  <Frames>
    <Button name="MyAddon_Button">
      <Anchors>
        <Anchor point="CENTER"/>
      </Anchors>
    </Button>
  </Frames>
</Frame>

This example has two widget elements (Frame and Button), and several property elements (Anchors, Anchor). 在这个例子当中出现了2个widget,frame和button,以及几个property元素。
This creates a Frame, with a Button inside it. 创建了一个包含一个按钮的框体。
Here, MyAddon_Button is a child of MyAddon_Frame, and MyAddon_Frame is a parent of MyAddon_Button. "MyAdd_Button"是"MyAddon_Frame"的子元素,"MyAddon_Frame"是"MyAddon_Button"的父元素。
Also note how the XML convention of abbreviating an empty element such as <Anchor point="CENTER"></Anchor> as <Anchor point="CENTER"/> is used. 同时这里要注意XML标准中是如何缩写空元素的。
Many of the elements (widget and property alike) can have attributes, such as the name attribute in the above examples. 许多元素(widget和property)都可以拥有属性,如比如它的名字。
A complete and valid XML file must contain exactly one element named UI, with some rather long attributes (best use copy/paste for this). 一个完整且有效的XML文件必须含有有且只有一个名字为UI的元素,以及一串非常长的属性(最好用复制粘贴)。
Hence a minimal example of a complete UI XML file would be something like: 因此,一个最小的UI XML示范文本就应该是这样子的:

<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="MyAddon_Frame">
   </Frame>
</Ui>

Such a file will create a single Frame, named MyAddon_Frame. However, that Frame wouldn't be visible and wouldn't have any content. 这个文件创建了一个命名为"MyAddon_Frame"的,不可见的,没有任何内容的框体。

Validation with XSD
If you use the Blizzard Interface Customization tool to extract the contents of the Interface/FrameXML folder, you will come across the file UI.xsd which provides a schema definition for automated validation of your customized XML-files. 如果你用Blizzard Interface Customization工具提取Interface/FrameXML目录,你可能会看到UI.xsd文件,它提供了schema定义,可以用来自动检查你的xml文件内容是否符合规范。
Notice that XSD is an advanced XML feature and requires a special editor as well as a good knowledge of advanced XML-concepts. XSD是XML的一个高级应用,它需要特殊的XML编辑器才能完成自动检查的工作。
If you've already worked with XML you might find this very helpful to get started with WoW. 如果你已经熟悉xml,你会发现这将对你开始wow的工作很有帮助。

Naming Widgets
Every widget element may have the name attribute. 每个widget都可以拥有一个name属性。
If an element has a name, it causes a global Lua variable to be created with that name. 如果元素有名字,那同时会创建一个同名的全局变量。
This variable can then be used to call API methods on that widget. 这个全局变量就代表这个元素,可以被API中使用。
Note that global variables are truly global across the entire UI, meaning that every name must be unique across all XML files. 需要注意的是这个全局变量的有效范围是整个UI,所以所有XML文件中的元素命名不能重复。
Here is an example. Let's say in your XML file you have a section like this:

<Frame name="MyAddon_Frame">
 ..
 <Frames>
  <Button name="MyAddon_Button">
   ..
  </Button>
 </Frames>
</Frame>

In any Lua code then you can use the variable MyAddon_Frame to refer to the frame and MyAddon_Button to refer to the button. 在LUA代码中,你可以用变量MyAddon_Frame来表示框体,用变量MyAddon_Button来表示变量。
For example, to show the frame, call MyAddon_Frame:Show(). Or to disable the button, call MyAddon_Button:Disable(). 例如,要显示框体,调用MyAddon_Frame:Show()。或者禁用按钮,调用MyAddon_Button:Disable()。
When defining the name of a widget, the special string $parent may be used. 当定义widget的时候,可以使用特殊的字符串$parent。
This will take on the name of whatever the parent of that widget is. For example: 它代表这个widget的父元素的名字。例如:

<Frame name="MyAddon_Frame">
 ..
 <Frames>
  <Button name="$parent_Button">
  ..
  </Button>
 </Frames>
</Frame>

This results in two global Lua variables: MyAddon_Frame and MyAddon_Frame_Button. 这样创建的LUA变量分别是:MyAddon_Frame和MyAddon_Frame_Button。

Managing Frames
Note: A lot of this section applies to all user interface widgets, not just Frames. Properties for layout, sizing and so on are common to all widgets.
注意:很多小节描述的内容不只是可以引用到框体元素上,还可以引用到其它所有界面元素。比如说布局的特性,改变大小。

Layout
Frames have a combination of a size and one or more anchors. For a frame to be laid out, the combination of these needs to define a rectangle on the screen in which the frame is to be laid out. 框体要用一个或多个锚点来表示位置,用size来表示大小。
A size is specified using a Size element with either an AbsDimension or RelDimension child element. 大小用size元素和AbsDimension/RelDimension子元素来表示。
Anchors allow for relative positioning, and also to allow frames to dynamically reposition their content based on resizing. 锚点用来确定frame的相对位置,以及可以根据frame的内容来动态更新它的位置。
A group of anchors is expressed via an Anchors element with one or more Anchor children, each of which may have an Offset. 通过Anchors元素和多个Anchor子元素来表述一组锚点,

<Frame>
 <Size><AbsDimension x="100" y="100"/></Size>
 <Anchors>
  <Anchor point="TOPLEFT"/>
 </Anchors>
</Frame>

This specifies a 100x100 frame anchored so that its top left is at the top left of its parent frame. 一个100*100大小的框体,它的左上角在它的父元素的左上角。

<Frame>
 <Size><RelDimension x="0.5" y="0.5"/> </Size>
 <Anchors>
  <Anchor point="LEFT"/>
 </Anchors>
</Frame>

This specifies a frame that covers a quarter of your UI (regardless to the selected resolution). 一个覆盖1/4 UI面积的框体。

<Frame>
 <Size><AbsDimension x="100" y="100"/></Size>
 <Anchors>
  <Anchor point="TOPLEFT" relativePoint="TOPRIGHT"/>
 </Anchors>
</Frame>

This specifies a 100x100 frame anchored so that its top left is at the top right of its parent frame. 一个100*100大小的框体,它的左上角在它的父元素的右上角。

<Frame>
 <Size><AbsDimension x="100" y="100"/></Size>
 <Anchors>
  <Anchor point="TOPLEFT" relativeTo="SomeOtherFrame">
   <Offset><AbsDimension x="10" y="-10"/></Offset>
  </Anchor>
 </Anchors>
</Frame>

This specifies a 100x100 frame anchored at the top left of the frame SomeOtherFrame, and offset by 10 pixels to the right and 10 pixels down. (Note that the Y axis increases from the bottom up, so negative Y coordinates indicate downwards movement). 一个100*100的框体,它的左上角在SomeOtherFrame的左上角,偏移是向右10,向下10。(注意,Y坐标轴是向上增大,所以Y值为负值时表示向下)

<Frame>
 <Anchors>
  <Anchor point="TOPLEFT" relativeTo="SomeOtherFrame">
   <Offset><AbsDimension x="5" y="-5"/></Offset>
  </Anchor>
  <Anchor point="BOTTOMRIGHT" relativeTo="SomeOtherFrame">
   <Offset><AbsDimension x="-5" y="5"/></Offset>
  </Anchor>
 </Anchors>
</Frame>

Note that no Size is specified here; the size and location of this frame is defined entirely by its relationship to SomeOtherFrame. In particular, it will be inset by 5 pixels from the top left and bottom right of SomeOtherFrame. As SomeOtherFrame changes size, our frame will change size as well. 注意,这里没有指定Size属性,因此在这种特殊情况下,没有size属性的元素将会覆盖父元素的面积(比父元素略微小一点),并随父元素改变大小而同时改变大小。

Frames may be shown or hidden by FrameName:Hide() and FrameName:Show(). 通过调用FrameName:Hide()和FrameName:Show()可以显示或隐藏框体。
Also available are ShowUIPanel(FrameName) and HideUIPanel(FrameName). 也可以用ShowUIPanel(FrameName)和HideUIPanel(FrameName)实现相同的功能。

Layers and Textures
There are 3 levels of layers: BACKGROUND is in the back, ARTWORK is in the middle and OVERLAY is in front. 有三层,BACKGROUND在最后面,ARTWORK在中间,OVERLAY在最前面。
If you want to be sure that a object is before another, you must specify the level where you want to place it. 当你要指定某元素在另外一个的前面时,只要指定它所属的层就可以了。
BACKGROUND - Level 0. Place the background of your frame here.
BORDER - Level 1. Place the artwork of your frame here .
ARTWORK - Level 2. Place the artwork of your frame here.
OVERLAY - Level 3. Place your text, objects, and buttons in this level
HIGHLIGHT - Level 4. Place your text, objects, and buttons in this level
Elements in the HIGHLIGHT Layer are automatically shown or hidden when the mouse enters or leaves! 当鼠标移动时,HIGHLIGHT层会自动显示或消失。
For Highlighting to work you need enableMouse="true" in your <Frame> attributes. 要让Highlight正常工作,必须给<frame>指定属性enableMouse="true"。

<Layers>
  <Layer level="BACKGROUND">
    ...
  </Layer>
  <Layer level="ARTWORK">
    ...
  </Layer>
  <Layer level="OVERLAY">
    ...
  </Layer>
</Layers>

Using Templates
Templates are used when you want to create a common layout for several frames. 当你要用一个布局创建多个框体的时候就要用到模板了。
In this way you can save on the amount of code needed to recreate each frame, as the frames will automatically take on the properties, children, and attributes from whatever template it inherits. 模板保存了重建框体需要的代码,当框体创建的时候,这些代码被自动地应用到框体的特性,子元素和属性上。
There are several rules that must be following when initially creating the template: 这里有几个创建模板必须遵守的规定:
1.Templates are created at the root of the file. Meaning that you cannot have a template that is a child of another element. 模板元素必须是XML文件的根标签元素。
2.Templates must have their virtual attributes set to true. 模板必须包含一个virtual的属性,其值为true。
3.Templates must have a name, and it cannot use the $parent keyword. 模板必须有名字,且不能用$parent。
4.Children of a template do not need to be named, but when doing so, you should use the $parent keyword. 模板的子元素不需要名字,如果有名字,也必须在命名时使用$parent。
As discussed above, there is a special keyword that can be used when naming something inside the template. 上面说到了模板的子元素有一个特别的名字。
When you inherit a frame, any object inside the template that is inherited, which has the keyword $parent, will automatically replace the keyword with the name of the parent which inherited the template. Example: 当你用模板创建一个框体的时候,所有模板上定义的子元素都被框体继承,子元素的名字中$parent被它的父框体的名字所替代。如:
<Button name="MyAddonButtonTemplate" parent="UIParent" virtual="true">
     <ButtonText name="$parentText"/>
</Button>
<Button name="MyAddonSpecialButton" inherit="MyAddonButtonTemplate">
     <Size><AbsDimension x="40" y="22"/></Size>
</Button>
同样的
<Button name="MyAddonSpecialButton" parent="UIParent">
     <Size><AbsDimension x="40" y="22"/></Size>
     <ButtonText name="MyAddonSpecialButtonText"/>
</Button>

Be aware that any inherited attributes, properties, or children can also be overridden. Example: 在继承的时候,任何属性,子元素,特性都可以被替代。
<Button name="MyAddonButtonTemplate" parent="UIParent" movable="true" virtual="true">
     <ButtonText name="$parentText"/>
</Button>
<Button name="MyAddonSpecialButton" inherit="MyAddonButtonTemplate" movable="false">
     <Size><AbsDimension x="40" y="22"/></Size>
</Button>
同样的
<Button name="MyAddonSpecialButton" parent="UIParent" movable="false">
     <Size><AbsDimension x="40" y="22"/></Size>
     <ButtonText name="MyAddonSpecialButtonText"/>
</Button>

Templates can inherit other templates as well. When done in this way, any $parent keywords used in the template being inherited carry over to the template that inherits it. Example: 模板也能继承自其它的模板,此时$parent也将被继承。
<Button name="MyAddonButtonTemplate1" parent="UIParent" movable="true" virtual="true">
     <ButtonText name="$parentText"/>
</Button>
<Button name="MyAddonButtonTemplate2" clampedToScreen="true" inherit="MyAddonButtonTemplate1" virtual="true">
     <NormalFont inherits="GameFontNormal"/>
</Button>
<Button name="MyAddonSpecialButton" inherit="MyAddonButtonTemplate2">
     <Size><AbsDimension x="40" y="22"/></Size>
</Button>
同样的
<Button name="MyAddonSpecialButton" parent="UIParent" clampedToScreen="true" movable="true">
     <Size><AbsDimension x="40" y="22"/></Size>
     <ButtonText name="MyAddonSpecialButtonText"/>
     <NormalFont inherits="GameFontNormal"/>
     <HighlightFont inherits="GameFontHighlight"/>
</Button>

Scripts
To attach behaviour to the UI elements defined in the XML files, you must use Lua. 把行为和xml文件中定义的界面元素联系起来,必须用到LUA。
There are two methods of attaching Lua code to UI elements. 有两种方法来建立这种关联。
Short codes can go directly in the XML files in the appropriate event handler element (see later). 简短的代码可以直接写在XML文件中。
Long codes should go in a separate .lua file, and included via a Script element. 冗长的代码应该写在单独的.lua文件中,并且在xml中用Script元素指定之。
To include Lua code via a Script element, you must have one or more <Script> elements at the start of the XML file. For example: <Script>的用法如下:

<Ui ... >
 <Script file="mycode.lua"/>
 <Frame name="MyFrame">
  ...
 </Frame>
</Ui>

When the XML file is read, the contents of the mycode.lua file is read and interpreted. 当xml文件被读取时,mycode.lua文件的内容也同时被读取和解释。
The code in that file is then available for the rest of this XML file, and any XML files that are read after this one. 被引入的lua代码在<script>之后的xml文件中都是有效的。
Functions that are defined in mycode.lua can be called from event handlers in the XML file. mycode.lua文件中定义的函数可以被xml文件调用。

Basic Event Handling concepts 基本事件处理的概念
If you are not used to event handled programming, read this section, otherwise you can skip right through it. 如果你不了解事件处理,那么请仔细阅读。否则请略过此章节。
==== 此章节不翻译 ====

处理UI事件
To handle UI events, you must include event handler elements in your XML code.  要处理UI事件,那么xml代码中必须包含事件句柄元素。
You do this by having a Scripts element, inside of which you have one or more Onxxxx event handler elements. For example: 具体的做法是添加包含一个或多个事件处理子元素的<script>元素。事件处理子元素形如Onxxxxx。例:

<Frame name="MyFrame">
 <Scripts>
  <OnShow>
   message("Hello!");
  </OnShow>
 </Scripts>
</Frame>

This frame has one event handler only, which is executed every time this Frame becomes visible. 这个框体只有一个事件处理,当每次这个框体被显示的时候触发这个事件。
The contents of the OnShow element can be any valid Lua code. OnShow元素的内容可以是任意有效的LUA代码。
In this example, it's a single statement, which calls the function message, which causes a dialog box to pop up with "Hello" inside it. 在此例中,它仅包含一个简单的语句,显示一个对话框内容为"Hello"。
(message is a function defined in BasicControls.xml and is available by default.) message函数在BasicControls.xml中定义,是默认的系统函数。
Here is a more complete example of how you include Lua code and then reference it from the event handlers. 再一个完整的例子,告诉你怎么引用lua文件,以及如何在事件处理中调用其中的函数。

mymod.xml:
<Ui ... >
  <Script file="mymod.lua"/>
  <Frame name="MyModMainFrame">
    <Scripts>
      <OnLoad>
        MyMod_ShowMessage();
      </Onload>
    </Scripts>
  </Frame>
</Ui>

mymod.lua:
function MyMod_ShowMessage()
  message("Hello World!");
end

When MyModMainFrame gets loaded (which happens once, at the start of the game, when all the XML files are read in), the OnLoad handler gets executed. 当MyModMainFrame加载的时候(在游戏开始时,所有xml文件都被读入后),OnLoad事件被触发。
In this case, the single Lua statement there simply calls the MyMod_ShowMessage function.例子中,LUA语句只是简单得调用了MyMod_ShowMessage函数。
It is recommended that you prefix the names of all of your functions, UI objects and global variables with the name of your AddOn like above; 在此,建议大家给函数,UI元素,全局变量命名时在前面加上你的插件的名字,就像上面例子中的那样。
all data is shared between Blizzard's own UI and all your addons, so picking a unique prefix helps avoid clashes with other people's code. 所有数据在Blizzard自己的插件和所有用户插件中都是共享的,因此选择一个唯一的前缀可以避免和其它人的插件冲突。
For the above example to actually work, you must either create an AddOn with the mymod.lua and mymod.xml files, or include them in the FrameXML directory and reference myframe.xml from FrameXML.toc.
为了让上面的例子真正运行起来,你要新建一个插件,添加mymod.lua和mymod.xml文件。或者把这两个文件放在FrameXML目录中,并在FrameXML.toc中引用myframe.xml。
See AddOns on how to combine these files into an AddOn. 更多内容在http://www.wowwiki.com/AddOns。

Event Handler reference
"http://www.wowwiki.com/Widget_Handlers" is a complete reference of what event handlers can be used by each object type. 这是每个UI Object可用的事件处参考。
Note: the OnEvent handler is special (see below). 注意:OnEvent是一个特殊的事件。

Widget Elements
...