JavaFX屬性與綁定

[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)。
property.jpg

上面提到了,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());
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容