數據綁定連接一些對象並且使它們同步盡管Swing的開發者們取決於額外的類庫但是綁定是完全融入了JavaFX Script編程語言仔細看一看它運行的庫顯示了一個完全綁定構架其基本概念與JGoodies Binding 和 Beans Binding很相似(在我以前的文章Binding Beans中有做過比較)JSR (Beans Binding)可能不會成為Java的一部分所以一直尋找可代替品的開發者們會問自己JavaFX綁定構架是否可以通過簡單的Java程序而進行使用
JavaFX建立在普通的Java SE運行上為了在本文中展示這個示例你需要為你的操作系統(在此只支持官方的Windows 和Mac OS X)下載合適的JavaFX SDK具體請參考Resources安裝installation過程只需要幾個步驟在Windows的機器上默認安裝地址是C:\Program Files\JavaFX\javafxsdk Mac OS X users should look at /Library/Frameworks/JavaFXframework/Versions/
![Hacking JavaFX Binding](http://tw.wingwit.com/Article/UploadFiles/201311/2013111509473759.jpg)
圖 JavaFX SDK基礎目錄
圖 顯示了JavaFX SDK的基礎目錄這個bin目錄包括可執行編譯並運行JavaFX Script程序我們不使用它們JavaFX(Script)documentation在docs中文件srczip包括部分JavaFX運行的來源如果你打開它你會注意到文件是以stg 和 st結尾的最後lib和它的子目錄包含庫jars本文的示例取決於它們中的一些
Locations
lib/shared/javafxrtjar包含comsunjavafxruntimelocation包它的類和接口來自基本的JavaFX Binding的構建塊例如Location接口代表一個值它可能是可變的或是不能改變的有效或無效的空的或是非空這樣的狀態可以通過相應的getters來查詢例如isMutable()如果Location的值是無效的當update()方法被調用時或該值被檢索時它會被更新
一個Location的類型是通過子接口來決定的;例如IntLocation如果你要在srczip中查詢IntLocationjava你不會看到它這是因為它的來源是來自兩個文件XxxLocationst 和XxxTemplatestg每個子接口為類型XYZ添加getAsXYZ和and setAsXYZ()還有DoubleLocation FloatLocation ShortLocation CharLocation LongLocation BooleanLocation ByteLocation和 ObjectLocation
其他的對象可能會附屬於一個Location當值與地址變化聯系在一起的時候change listeners可以接收到通知最後Locations是很懶惰的雖然當值無效的時候change listeners會得到通知但是新的值不會被重新計算直到需要它的時候到目前為止我指談論了接口的問題當然可以為我以上所提到的類型而隨時執行Locations
public static void main(String[] args) {
final IntVariable i = IntVariablemake();
iaddChangeListener(new ChangeListener() {
@Override
public boolean onChange() {
Systemoutprintln(onChange(): + iget());
return false;
}
});
Systemoutprintln(iget() +
isMutable(): + iisMutable());
IntLocation i = IntConstantmake();
Systemoutprintln(iget() +
isMutable(): + iisMutable());
iset(iget());
}
為了編譯並運行LocationDemo請附加lib/shared/javafxrtjar到你的類路徑上這個演示示例采用了IntVariable 和IntConstant類兩個都執行了IntLocation接口因此是Locations使用靜態make()方法創建Instances使用get()查詢當前值正如你在圖中所看到的在初始化引發一個通知之後設置一個值它通過子抽象類ChangeListener來進行處理
![Hacking JavaFX Binding](http://tw.wingwit.com/Article/UploadFiles/201311/2013111509473754.jpg)
圖 LocationDemo輸出
當地址內容已經改變的時候它的onChange()方法被調用該方法返回一個Boolean值指示監聽者是否仍然有效返回false將導致監聽者從監聽者名單上刪除Javadoc建議當相關的弱引用被報告清除的時候那些做它們自己弱引用管理的監聽者應該返回false
就像JGoodies Binding的ValueModel還有Beans Binding的Property一樣Locations 讀取和編寫類型值提供了一個方法它們也可以通知注冊的監聽者關於值的變化最後你將會在以下的小節中看到它們用於建立綁定
建立綁定
像Beans Binding 和JGoodies Binding一樣JavaFX運行包含一個輔助類來建立綁定comsunjavafxruntimelocationBindings它是用於在兩個Locations之間建立bijective關系這個意思是說如果一個值被更新它所對應的也會被更新在Locations被實例之後它們被傳遞到bijectiveBind()
public class BindingDemo {
private static IntLocation i i;
public static void main(String[] args) {
i = IntVariablemake();
i = IntVariablemake();
BindingsbijectiveBind(i i);
showValues();
isetAsInt();
showValues();
isetAsInt();
showValues();
}
private static void showValues() {
Systemoutprintln(i: + iget());
Systemoutprintln(i: + iget());
}
}
bijectiveBind(i i)在i 和 i之間建立兩種依賴關系如果其中一個被更新例如調用setAsInt()其他的值也會變化為了到達此目的執行附加了兩個監聽者在Locations中分享狀態方便的方法makeBijectiveBind()創建一個新的Location並它綁定到現存的綁定上面如下所示
i = IntVariablemake();
i = BindingsmakeBijectiveBind(i);
BindingDemo展示了如何使用它它包含在/today////sourceszip中具體細節請參考Resources圖顯示了它的輸出
![Hacking JavaFX Binding](http://tw.wingwit.com/Article/UploadFiles/201311/2013111509473851.jpg)
圖 BindingDemo輸出
請注意只有可編譯的類型才能使用bijectiveBind()來進行綁定以下的代碼行取自BindingDemojava(包含在sourceszip中的)第一眼看上去代碼沒什麼問題但是它們會拋出ClassCastException異常這裡發生什麼事情了呢?
ObjectLocation loc = IntVariablemake();
ObjectLocation loc = BooleanVariablemake();
BindingsbijectiveBind(loc loc);
在創建綁定的過程中locget()結果被傳遞到loc的set()方法中這個不會為Boolean 和 Integer工作的為了避免這種問題只要適當的確定參數泛型類型ObjectLocation目前為止我們已經看到兩個變量是如何被同步的以下的小節中將看一看Swing組件是如何被綁定的
綁定Swing組件
幾乎每個JavaFX Script教程都是由顯示一個窗口按鈕或是標簽的小程序開始的JavaFX 使用Swing來構建並顯示這些組件因此我們可以假設Swing融入了JavaFX運行不久你將會看到這個也會應用於綁定
lib/desktop/javafxswingjar文件包含javafxextswing包它的類包含了大多數常見的Swing組件如果你檢查它們你將會注意到它們用$開始顯示各區域它們的類型是ObjectVariable它可以執行ObjectLocation
![Hacking JavaFX Binding](http://tw.wingwit.com/Article/UploadFiles/201311/2013111509473874.jpg)
圖 在Eclipse的Members視圖中SwingLabel
考慮到這個接口屬於comsunjavafxruntimelocation包它是安全的假設這樣的Locations可以綁定到其他的變量上以下的程序展示你是如何做到這個的為了編譯並運行這個示例請添加lib/shared/javafxrtjar lib/desktop/javafxswingjar lib/desktop/Scenariojar 以及 lib/desktop/javafxguijar到你的類路徑上
public class SwingDemo {
public static void main(String[] args) {
JFrame f = new JFrame();
fsetDefaultCloseOperation(JFrameEXIT_ON_CLOSE);
JPanel p = new JPanel(new BorderLayout());
fsetContentPane(p);
SwingLabel label = new SwingLabel();
ObjectLocation text =
BindingsmakeBijectiveBind(label$text);
padd(labelgetJComponent() BorderLayoutCENTER);
fpack();
fsetVisible(true);
textset(Hello JavaFX!);
}
}
除了這個很有用的創建並顯示窗口的Swing代碼之外
還有三件比較重要的事情要做
SwingLabel被實例化並分配到label
Location被分配到test並綁定到label的$text上
標簽被有層次的添加到組件上
請注意你不能直接添加SwingLabel到容器中相反它的getJComponent()方法用來獲取JComponent實例
雖然這個簡單的例子展示了一個Swing組件如何被綁定到一個變量上的但是卻沒有說明使用JavaFX 綁定的好處在我以前的文章Binding Beans中我演示了如何使用JGoodies Binding 和 Beans Binding來執行一個簡單的音量控制
VolumeControl示例
音量控制是基於一個簡單的特定應用的POJO叫做Volume它有兩個區域volume 和mute如圖所示它通過一個復選框和一個滑塊進行操作標簽顯示現在的volume值除此之外mute控制音量是否調整
![Hacking JavaFX Binding](http://tw.wingwit.com/Article/UploadFiles/201311/2013111509473811.jpg)
圖 音量控制示例
涉及Swing組件和POJO區域之間的關系如下
復選框設置mute
滑塊設置volume
Mute選擇或不選擇復選框
Volume設置成滑塊的位置
Mute啟用或禁用滑塊
Volume設置標簽文本
完整的來源包含在sourceszip中細節請參考Resources部分它的結構很像我以前的文章中的版本所以很容易比較不同的版本為了編譯並運行VolumeControl請添加lib/shared/javafxrtjar lib/desktop/javafxswingjar lib/desktop/Scenariojar 和lib/desktop/javafxguijar到你的類路徑
首先所有相關的組件都要初始化這個發生在initComponents()中例如垂直壞塊被創建並有如下設置
sliderVolume = new SwingSlider();
sliderVolume$verticalset(true);
在initEventHandling()中建立綁定例如復選框與mute鏈接用以下命令BindingsbijectiveBind(checkboxMute$selected volumemute); 當復選框被選擇的時候禁用滑塊是通過添加一個監聽者到mute上實現的
volumemuteaddChangeListener(new ChangeListener() {
@Override
public boolean onChange() {
sliderVolume$enabledset(! volumemuteget());
return true;
}
});
每次volume
mute 改變的時候
onChange()就會被調用
如果它變成true
滑塊就被禁用
如果變成false
滑塊就再次使用
這個狀態用sliderVolume
$enabled
set()來設置
相同的方法同樣適用於創建標簽文本
滑塊的值用Integer代表
正如我們早前已經看到的
它不能綁定到Strings上
轉換完成如下
public boolean onChange() {
labelInfo$textset(volumevolumeget()toString());
return true;
}
通過使用toString()
get()結果變成a String並傳遞labelInfo
$text
set()
總結
很驚訝的看到JavaFX綁定在Swing應用程序中的使用是如此簡單雖然綁定構架還沒有為這個所設計但是它是一個相當體面的工作盡管如此本文還是故意忽視了一些問題
Sun會允許使用並可能重新分配部分JavaFX運行給非JavaFX應用程序嗎?
如何安全使用內部類?這裡所描述的包還沒有被設計成公共的APIS
為什麼沒有成熟的綁定構架給Swing開發者們使用?
即使JavaFX綁定可以或是不能在產品環境中使用但是對於它的內部研究還是充滿樂趣和鼓舞的
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19126.html