WTKX是用于创建Pivot应用程序的基于XML的标记语言。虽然,通常是用于定义用户界面的结构,但是也可以用于声明创建Java对象。
本节主要介绍WTKX和解释如何使用WTKX创建和配置java对象集合。假定你已经熟悉掌握了Pivot和Java程序设计语言。
元素(element)
在WTKX中,一个XML元素可能表示一下其一:
-
一个类的实例
-
一个类实例的特性(属性)
-
WTKX串行化处理指令
如果一个元素的标签名称以大写字母开头,被认为是一个类实例。其它当做类实例的属性处理,除非标签名称以保留名称空间前缀"wtkx"开始。以wtkx名称空间前缀开始的元素属于串行化指令,在后面的章节会详细的描述。
类实例元素(Class Instance Elements)
当WTK串行化(org.apache.pivot.wtkx.WTKXSerializer的一个实例, 后面会描述) 遇到一个元素的标签是以大写字母开头时,它认为标签的名字是一个Java的类并创建一个该类的实例。元素名称空间指定类名所属的Java包。
例如,下面的WTKX展示了org.apache.pivot.wtk.Label类的一个实例,并显示text"Hello,World"(和特性一个,属性也是可以用于设置特性的值,在下节讨论):
1 | < Label text = "Hello, World!" |
2 | xmlns = "org.apache.pivot.wtk" /> |
注意:默认的名称空间被定义为 org.apache.pivot.wtk. 在Pivot开发中,这是一个非常常见的惯例,因为WTKX经使用定义在该包的类来构造用户界面。
更复杂的例子可能使用定义于其它包的类和使用多个名称空间。名称空间前缀可以使用于此目的。例如,下面的WTKX给包 org.apache.pivot.wtk.charts 分配了名称空间前缀charts , 并且设置org.apache.pivot.wtk.charts.BarChartView 的实例为Window的内容:
1 | < Window xmlns = "org.apache.pivot.wtk" |
2 | xmlns:charts = "org.apache.pivot.wtk.charts" > |
字典 vs.Bean字典(Dictionary vs. BeanDictionary)
通常情况下,WTKX文件中以大写字母开头的元素代表的是一个JavaBean类的实例,在WTKX系列化内部使用org.apache.pivot.beans.BeanDictionary 来封装类的实例,并调用它的Set方法。然而如果名称所代表的对象的类实现了接口org.apache.pivot.collections.Dictionary (比如 org.apache.pivot.collections.HashMap),就不使用JavaBean封装,而是使用dictionary的方法直接存取。例如,下面的WTKX创建了一个 org.apache.pivot.collections.HashMap 的实例,并设置 "foo" 和"bar" 的值分别为 "123" 和"456":
1 | < HashMap foo = "123" bar = "456" |
2 | xmlns = "org.apache.pivot.collections" /> |
实例特性元素(Instance Property Elements)
那些标签以小写字母开始的元素代表了一个实例的特性。一个特性可能表示下面的其一情况:
-
一个标准JavaBean特性的setter
-
一个只读的序列
-
一个只读的字典
-
一个事件监听者列表
WTKX串行化使用bean字典获得的信息可以知道特性的类型和正确的处理元素的内容。
JavaBean特性Setters(JavaBean Property Setters)
如果一个元素表示一个JavaBean特性setter,元素的内容就会被当做值传递给特性的setter。例如,下面的WTKX创建了Label类的一个实例,并且设置label的text特性的值为"Hello,World!":
1 | < Label xmlns = "org.apache.pivot.wtk" > |
2 | < text >Hello, World!</ text > |
下面展示了一个具有相同结果的实例,使用属性设置text的特性:
1 | < Label text = "Hello, World!" |
2 | xmlns = "org.apache.pivot.wtk" /> |
下面的事例创建了一个ListView的实例,并且设置listData特性的值为一个org.apache.pivot.collections.ArrayList 对象,一个具有多个 org.apache.pivot.wtk.content.ListItem 对象的类型:
01 | < ListView xmlns = "org.apache.pivot.wtk" |
02 | xmlns:collections = "org.apache.pivot.collections" |
03 | xmlns:content = "org.apache.pivot.wtk.content" > |
05 | < collections:ArrayList > |
06 | < content:ListItem text = "A" /> |
07 | < content:ListItem text = "B" /> |
08 | < content:ListItem text = "C" /> |
09 | </ collections:ArrayList > |
只读序列(Read-Only Sequences)
如果特性代表的是一个只读序列(一个bean特性的getter返回一个org.apache.pivot.collections.Sequence 对象并且没有相应的setter方法),元素的内容被添加到序列。例如, org.apache.pivot.wtk.TabPane类的tabs特性返回 TabSequence的实例
1 | < TabPane xmlns = "org.apache.pivot.wtk" > |
只读字典(Read-Only Dictionaries)
一个特性属性可能代表一个只读字典(一个bean特性的getter方法返回一个org.apache.pivot.collections.Dictionary 实例,但是没有相应的setter方法)。例如 org.apache.pivot.wtk.Component 的userData特性代表一个只读字典特性:
1 | < Label text = "Hello, World!" |
2 | xmlns = "org.apache.pivot.wtk" > |
3 | < userData foo = "123" bar = "456" /> |
uaserData特性的属性值被放入到字典,使用属性的名字作为键,属性值为键的值。
监听者列表(Listener Lists)
最后属性可能代表一个事件监听者列表(org.apache.pivot.util.ListenerList的一个实例)。如果是这样,子元素代表了适当的监听者并被添加到监听者列表。 在脚本一章节详细描述。
属性(Attributes)
WTKX的熟悉可能代表下面情况之一:
-
一个标准的JavaBean特性的setter方法
-
一个静态的特性setter方法
-
一个事件监听者
JavaBean特性Setter方法(JavaBean Property Setters)
如果一个属性代表一个bean特性的setter,属性值会被当做参数传递给setter方法。如果属性的类型为strng,值按原样传递;然而,如果属性类型是其它简单类型(boolean, char, byte, short, int, long, float, or double)或者简单类型的封装类型,在调用setter方法之前会被转换为适当的类型。例如,下面给出一个简单的bean类:
3 | public String getFoo() { ... } |
4 | public void setFoo(String foo) { ... } |
5 | public int getBar() { ... } |
6 | public void setBar( int bar) { ... } |
下面的WTKX实例化了bean,并调用foo和bar setters方法,并且传递string给setFoo和setBar:
1 | < MyBean foo = "hello" bar = "123" |
然而,如果一个元素表示的对象的类已经实现了Dictionary接口(如HasmMap),属性的类型就无法决定,也不会有类型转换发生,值简单的按strng传递。
静态特性Setters方法(Static Property Setters)
属性可能摆式"静态setters" (有些时候"附加特性")。附加特性就是那些只有在特定上下文才出现的特性(属性)。当类被调用时,他们并不是类内定义的属性,而是在其它的类定义(一般的,比如父容器或者组件)。
下面的WTKX为TabPane 类的label特性调用了静态setter:
1 | < TabPane xmlns = "org.apache.pivot.wtk" > |
3 | < Label TabPane.label = "First Tab" text = "Tab 1" /> |
上面的WTKX代码可以转换为下面对应的Javad代码:
1 | TabPane tabPane = new TabPane(); |
2 | Label label = new Label(); |
4 | tabPane.getTabs().add(label); |
5 | TabPane.setLabel(label, "First Tab" ); |
调用TabPane.setLabel()把"name"特性和Label实例关联在一起。tab pane随后使用特性的值作为出现在pane按钮栏的按钮的数据。TabPane同样也为tab的图标定义了一个静态setter。其它容器,包含Accordion和TablePane也定义了类似的setters。
注意:虽然在WTKX中静态setter属性定义在最前面,但事实上是在setter(text)特性后调用(就像Label的实例被添加到tab pane一样)。 因为静态setter是将一个实例添加到其父类对象(组件)中,在实例为创建之前,静态setter是不能被调用的。添加一个对象到父对象时使得关联的特性生效。相反的,从父对象删除一个对象时,先前关联的特性也被移除。
事件监听者(Event Listeners)
最后,属性可能代表一个事件监听者。属性值包含的脚本代码用于在响应事件时被执行。详细的描述在脚本一章节。
操作符解析(Resolution Operators)
WTKX的Setter属性支持几种操作符解析的处理能力:
-
对象解引用 Object dereference
-
资源解析Resource resolution
-
URL定位解析 URL resolution
对象解引用(Object Dereference)
对象解引用操作允许属性相应的setter函数调用前使用一个先前定义的命名对象替换属性的值。任何属性其值以$开头时都被认为是对象解引用。
例如,一个table view header必须与一个TableView对象关联。在Java,痛过使用setTableView方法实现。在WTKX,对象解引用操作被使用。下面的WTKX定义了一个ScrollPane对象,设置TableView为组建的view,并且使用TableViewHeader作为列头。table view 痛过tableView属性关联列头:
01 | < ScrollPane xmlns = "org.apache.pivot.wtk" |
04 | < TableView wtkx:id = "tableView" > |
09 | < TableViewHeader tableView = "$tableView" /> |
注意:上面的例子使用了"wtkx"名称空间前缀。这是一个由WTKX串行化对象解析的特别的名称空间。如上所示,定义了元素的id,用于给类的实例分配一个名称。除了解引用之外,该ID也可以用于在Java代码系列化WTKX或者脚本代码包含WTKX文件时获得被实例化的元素的引用。I
其它特别的元素也被定义于wtkx名称空间中,在后面的章节在详细描述。
资源解析(Resource Resolution)
在WTKX中,为了本地化的目的,资源的替代在加载时才被执行。当给出一个.org.apache.pivot.util.Resources实例时, WTKXSerializer 会使用指定的值替换资源的名称. 资源名称使用%前缀定义,如下所示:
2 | xmlns = "org.apache.pivot.wtk" > |
与之关联的本地资源文件可能包含如下所示的内容:
1 | { myText: "This is my text!" |
显示lable的文本是 "This is my text!".
WTKXSerializer 在后面会详细的讨论。
URL解析(URL Resolution)
属性也可以用来指定URLs。一个值以'@'字符开始的属性被转换为URL,该URL的地址相对于WTKX源文件所在的地址。例如,下面的WTKX从与WTKX文件相同的目录加载图像。WTKX转换为调用ImageView#setImage(java.net.URL)方法:
1 | < ImageView image = "@foo.png" |
2 | xmlns = "org.apache.pivot.wtk" /> |
如果没有 "@" 操作符bean属性就没有相关的上下文可以解析资源的路径。
包含(Includes)
<wtkx:include>标签允许WTKX文件嵌入一个外部定义的WTKX文件为其内容。 这个对于组织文件的多个部分是非常用于的。
下面的WTKX定义了Windows的内容包含一个外部文件content.wtkx文件:
1 | < Window xmlns = "org.apache.pivot.wtk" |
4 | < wtkx:include src = "content.wtkx" /> |
包含文件的内容使用一个嵌套的WTKXSerializer实例进行加载。如果给包含标签分配一个ID,定义于该包含文件内的对象可以通过名称调用WTKXSerializer#get获得。例如,下面给如的WTKX,调用者可以在随后使用"content.label"取得Label的实例:
2 | < Window xmlns = "org.apache.pivot.wtk" |
5 | < wtkx:include wtkx:id = "content" src = "content.wtkx" /> |
2 | < Label xmlns = "org.apache.pivot.wtk" |
4 | wtkx:id = "label" text = "Hello, World!" /> |
Java 代码:
1 | Label label = (Label)wtkxSerializer.get( "content.label" ); |
通常情况下WTKX中定义的类实例元素都期望自己有一个父标签。然而,某些时候声明的对象并不需要一个直接的父对象。<wtkx:define>标签可以用于实现该目的。
例如,下面的WTKX实例化了一个 login对话框对象,通过include实现。对话框实例被分配了一个ID,可以用于在脚本或者Java代码中定义与之相关的事件处理器:
2 | xmlns = "org.apache.pivot.wtk" > |
4 | < wtkx:include wtkx:id = "loginDialog" src = "login_dialog.wtkx" /> |
<wtkx:script>标签允许调用者导入脚本代码或者嵌入包含脚本代码的WTKX文件。 任何JVM脚本语言都可以被使用。.The name of the scripting language is passed to the WTKXSerializer instance that is used to load the WTKX file. WTKXSerializer is discussed in more detail below.
例如,下面的WTKX定义了一个JavaScript代码,并在JavaScript中定义了一个名称为foo的变量。该变量的值被用于展现定义在Windows content 的Label实例:
2 | xmlns = "org.apache.pivot.wtk" > |
4 | var foo = "Hello, World!"; |
脚本代码也可以被定义于外部文件:
2 | xmlns = "org.apache.pivot.wtk" > |
3 | < wtkx:script src = "foo.js" /> |
任何在脚本中被声明为global的变量都被添加到WTKX文件名称空间内,并且可以用于对象解引用操作和通过WTKXSerializer#get获得对象的引用。
监听者列表元素(Listener List Elements)
WTKX中的脚本代码可能被用于定义事件处理器。每一个事件处理器定义于脚本会比定义于Java代码更加方便。例如,下面给出的WTKX:
1 | < PushButton xmlns = "org.apache.pivot.wtk" |
3 | wtkx:id = "pushButton" buttonData = "Click Me!" /> |
Java代码获得PushButton的引用和关联按钮的press监听者的代码可能如下:
1 | PushButton pushButton = (PushButton)wtkxSerializer.get( "pushButton" ); |
2 | pushButton.getButtonPressListeners().add( new ButtonPressListener() { |
3 | public void buttonPressed(Button button) { |
然而可以更加简单的完成这个事情,一个相似的脚本代码可能如下:
01 | < PushButton xmlns = "org.apache.pivot.wtk" |
03 | buttonData = "Click Me!" > |
04 | < buttonPressListeners > |
06 | function buttonPressed(button) { |
10 | </ buttonPressListeners > |
This version is quite a bit easier to read, and creates a much stronger association between the button and the handler. It doesn't even require the button to be given an ID.
当脚本被定义于监听者列表元素内时,WTKXSerializer创建了一个局部范围的本地处理器。其结果就是,任何出现在脚本块中定义的变量和函数只有在块内可见。
基于脚本的事件处理器没有必要实现监听者接口的所有方法,可以忽略掉方法,会被简单的处理为 no-op处理器。
事件监听者属性(Event Listener Attributes)
事件监听者也可以被定义为属性,使用于静态特性setter相似的语法。属性的名称包含事件处理器的接口和其名称,通过·分隔。 和监听者列表元素一样,一个局部范围的代码被创建。 任何定义于处理器内的变量只有在处理器内可见。
例如,上面的按钮press监听者可以被定义为一个属性,如下:
1 | < PushButton xmlns = "org.apache.pivot.wtk" |
4 | ButtonPressListener.buttonPressed = "// Handle event" /> |
基于属性事件处理器主要使用于短小代码的处理器,通常适合于只有单行代码的处理器。长代码的事件处理器最好是使用基于元素的监听者列表或者使用Java代码实现。
WTKX串行化(WTKXSerializer)
org.apache.pivot.wtkx.WTKXSerializer类主要用于加载和处理WTKX文件和关联脚本与包含文件。实现了 org.apache.pivot.serialization.Serializer 接口,和返回了定义于WTKX文件中的对应的对象层次结构。.定义重载了 readObject()方法:
1 | public Object readObject(String resourceName) { ... } |
2 | public Object readObject(URL location) { ... } |
3 | public Object readObject(InputStream inputStream) { ... } |
第一个版本,在应用程序的路径下加载WTKX文件资源。第二个版本的函数从一个URL中加载。
1 | < Window xmlns = "org.apache.pivot.wtk" |
4 | < Label wtkx:id = "label" text = "Hello, World!" /> |
1 | public void startup(Display display, Map<String, String> properties) |
3 | WTKXSerializer wtkxSerializer = new WTKXSerializer(); |
5 | (Window)wtkxSerializer.readObject(getClass().getResource( "window.wtkx" )); |
访问命名对象(Accessing Named Objects)
当WTKX文件的跟对象被加载以后,WTKXSerializer#get()方法允许调用者取得一个在WTKX中命名对象的实例 。readObject()方法会处理命名对象ID和对象实例之间的映射,使得调用者随后可以引用到这些对象。
继续上一个例子,下面的代码取得了Lable实例,并且改变text为 "Welcome to Pivot"!:
1 | public void startup(Display display, Map<String, String> properties) |
3 | WTKXSerializer wtkxSerializer = new WTKXSerializer(); |
5 | (Window)wtkxSerializer.readObject(getClass().getResource( "window.wtkx" )); |
6 | Label label = wtkxSerializer.getObjectByID( "label" ); |
7 | label.setText( "Welcome to Pivot!" ); |
WTKXSerializer 实现了Dictionary接口,所以调用者可以使用put和remove方法修改serializer's 名称空间,在加载之前。
嵌套包含(Nested Includes)
定义于WTKX包含的对象可以通过get()方法取得。包含文件的ID定义了改包含的名传空间,调用者可以使用点分隔的名称空间路径访问嵌套对象:
1 | Label label = (Label)wtkxSerializer.get( "content.label" ) |
"content" 是包含Label实例的包含文件的ID, "label"是 label本身的ID。
WTKX绑定(WTKX Binding)
org.apache.pivot.wtkx包包含的注解可以用于简单的映射命名对象到java程序。 @WTKX注解可以用于标记一个成员变量,会自动映射WTKX文件中的命名对象。WTKXSerializer 的bin() 方法用于执行实际的映射:
1 | < Window xmlns = "org.apache.pivot.wtk" |
4 | < Label wtkx:id = "label" text = "Hello, World!" /> |
当WTKXSerializer#bind() 被调用时,下面的代码被自动添加:
1 | @WTKX private Label label; |
总结(Summary)
WTKX 提供了一系列特性用于帮助构建用户接口。可以用于实例化对象、设置成员的值和定义逻辑脚本等。