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(); |
3 |
label.setText( "Tab 1" ); |
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 提供了一系列特性用於幫助構建用戶接口。可以用於實例化對象、設置成員的值和定義邏輯腳本等。