[TOC]
屬性
在類Bill中定義一個(gè)amoutDue屬性:
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
class Bill {
// 定義一個(gè)變量存儲(chǔ)屬性
private DoubleProperty amountDue = new SimpleDoubleProperty();
// 定義一個(gè)getter方法獲取屬性值
public final double getAmountDue(){return amountDue.get();}
// 定義一個(gè)setter方法設(shè)置屬性值
public final void setAmountDue(double value){amountDue.set(value);}
// 定義一個(gè)getter方法獲取屬性本身
public DoubleProperty amountDueProperty() {return amountDue;}
}
amountDue對象是javafx.beans.property.DoubleProperty的一個(gè)實(shí)例,并使用private對其進(jìn)行了標(biāo)記,從而將其封裝起來與外部隔離。這是Java和JavaBeans應(yīng)用開發(fā)中的一個(gè)標(biāo)準(zhǔn)做法。注意雖然這個(gè)對象的類型不是標(biāo)準(zhǔn)Java基本類型,而是一個(gè)新的包裝類,其中封裝了基本類型并增加了一些額外方法(javafx.beans.property包下的類的設(shè)計(jì)中都包含了對可觀察性和綁定的內(nèi)建支持,property包下包含了各種數(shù)據(jù)類型的property封裝)。
屬性方法的命名規(guī)范如下:
- getAmountDue()方法是標(biāo)準(zhǔn)的取值方法(getter),返回了amountDue屬性的當(dāng)前值。按照規(guī)范,這個(gè)方法應(yīng)該聲明為final。需要注意這個(gè)方法的返回類型為double,而不是DoubleProperty。
- setAmountDue(double)方法(同樣也是final的)是一個(gè)標(biāo)準(zhǔn)的設(shè)值方法(setter),它允許調(diào)用者設(shè)置屬性值。setter方法是可選的。其參數(shù)類型同樣也是double。
- 最后,amountDueProperty()方法定義了屬性的getter方法。這是一條新規(guī)范,它要求方法名包含屬性名(在本例中是amountDue),以單詞Property結(jié)尾。返回類型與屬性本身一致(在本例中是DoubleProperty)。

上面提到了,javafx.beans.property包下的類的設(shè)計(jì)中都包含了對可觀察性和綁定的內(nèi)建支持,我們可以添加一個(gè)監(jiān)聽器來監(jiān)聽屬性的改變:
public class Main {
public static void main(String[] args) {
Bill electricBill = new Bill();
electricBill.amountDueProperty().addListener(new ChangeListener(){
@Override
public void changed(ObservableValue o,Object oldVal,Object newVal){
System.out.println("Electric bill has changed!");
}
});
electricBill.setAmountDue(100.00);//當(dāng)amoutDue值改變時(shí),會(huì)打印出上面那句話
}
}
綁定
使用高級綁定api
高級API是在你的應(yīng)用程序中開始使用綁定的最簡單快捷的方法。它包含兩部分:Fluent API和Binding類。Fluent API在各種依賴對象上暴露方法,而Binding類提供了靜態(tài)工廠方法。
要開始使用Fluent API時(shí),可以考慮這樣一個(gè)簡單的例子:有兩個(gè)整數(shù)被綁定在一起,所以它們的值總是被相加到一起。在例1-3中包含三個(gè)變量:num1(依賴變量),num2(依賴變量)和sum(綁定變量)。依賴變量的類型都是IntegerProperty,而綁定變量的類型是NumberBinding。
public class Main {
public static void main(String[] args) {
IntegerProperty num1 = new SimpleIntegerProperty(1);
IntegerProperty num2 = new SimpleIntegerProperty(2);
NumberBinding sum = num1.add(num2);
System.out.println(sum.getValue());//3
num1.set(2);
System.out.println(sum.getValue());//4,說明綁定有效
}
}
你也可以使用Bindings類(同樣binding包下也包含了一系列數(shù)據(jù)類型的binding類)來做同樣的事:
public class Main {
public static void main(String[] args) {
IntegerProperty num1 = new SimpleIntegerProperty(1);
IntegerProperty num2 = new SimpleIntegerProperty(2);
NumberBinding sum = Bindings.add(num1,num2);
System.out.println(sum.getValue());//3
num1.setValue(2);
System.err.println(sum.getValue());//4
}
}
使用低級綁定api
低級API相比高級API為開發(fā)者提供了更高的靈活性(或更高性能)。
public class Main {
public static void main(String[] args) {
final DoubleProperty a = new SimpleDoubleProperty(1);
final DoubleProperty b = new SimpleDoubleProperty(2);
final DoubleProperty c = new SimpleDoubleProperty(3);
final DoubleProperty d = new SimpleDoubleProperty(4);
DoubleBinding db = new DoubleBinding() {
{
super.bind(a, b, c, d);
}
@Override
protected double computeValue() {
return (a.get() * b.get()) + (c.get() * d.get());
}
};
System.out.println(db.get());
b.set(3);
System.out.println(db.get());
}
}
使用低級API包括對某一個(gè)綁定類進(jìn)行擴(kuò)展并重寫其computeValue()方法以返回綁定的當(dāng)前值。上例中使用了DoubleBinding 的一個(gè)自定義子類。子類中調(diào)用super.bind()方法將依賴變量向上傳遞給了DoubleBinding類,所以默認(rèn)的失效行為會(huì)被保留。一般不需要檢查綁定是否是失效;基類會(huì)為你提供這種行為。
探索Observable, ObservableValue, InvalidationListener和ChangeListener
綁定API定義了一系列的接口,可以做到當(dāng)一個(gè)值發(fā)生改變或者失效時(shí)可以通知對象。Observable與ObservableValue接口觸發(fā)改變通知,而InvalidationListener和ChangeListener接口接收通知。
兩者的區(qū)別是Observable中只有添加和刪除InvalidationListener的方法,ObservableValue繼承于Observable,并新增了添加和刪除ChangeListener的方法。
ChangeListener每次ObservableValue值改變的時(shí)候都會(huì)觸發(fā),InvalidationListener在Observable的某一個(gè)依賴變量改變時(shí)觸發(fā),并且只能觸發(fā)一次,直到Observable再次變得有效(被訪問)。
JavaFX綁定與屬性的實(shí)現(xiàn)都支持延遲計(jì)算(lazy evaluation),意思是當(dāng)改變發(fā)生時(shí)值并不是立即重新計(jì)算。當(dāng)此值隨后被請求時(shí)才進(jìn)行重新計(jì)算。
public class Main {
public static void main(String[] args) {
Bill bill1 = new Bill();
Bill bill2 = new Bill();
Bill bill3 = new Bill();
NumberBinding total =Bindings.add(bill1.amountDueProperty().add(bill2.amountDueProperty()),bill3.amountDueProperty());
total.addListener(new InvalidationListener() {
@Override
public void invalidated(Observable o) {
System.out.println("The binding is now invalid.");
}
});
// 某個(gè)依賴變量改變使綁定失效
bill1.setAmountDue(200.00);
// 不會(huì)觸發(fā)InvalidationListener,因?yàn)橐呀?jīng)失效了
bill2.setAmountDue(100.00);
bill3.setAmountDue(75.00);
// 使綁定恢復(fù)有效,并重新計(jì)算值
System.out.println(total.getValue());
// 綁定失效
bill3.setAmountDue(150.00);
// 綁定有效
System.out.println(total.getValue());
}
}