本文主要讲解了javafx的属性与绑定,并介绍了javafx的集合相关知识。

创建一个属性的代码示例:

class Bill {
    private DoubleProperty amountDue = new SimpleDoubleProperty();

    public final double getAmountDue() {
        return amountDue.get();
    }

    public final void setAmountDue(double value) {
        amountDue.set(value);
    }

    public DoubleProperty amountDueProperty() {
        return amountDue;
    }
}

属性方法的命名规范如下:
● getAmountDue()方法是标准的取值方法(getter),返回了amountDue属性的当前值。按照规范,这个方法应该声明为final。需要注意这个方法的返回类型为double,而不是DoubleProperty。
● setAmountDue(double)方法(同样也是final的)是一个标准的设值方法(setter),它允许调用者设置属性值。setter方法是可选的。其参数类型同样也是double。
● 最后,amountDueProperty()方法定义了属性的getter方法。这是一条新规范,它要求方法名包含属性名(在本例中是amountDue),以单词Property结尾。返回类型与属性本身一致(在本例中是DoubleProperty)。

添加一个改变监听器(change listener)来在属性值改变时获得通知:

public class Proprety {

    public static void main(String[] args) {

        Bill bill = new Bill();

        bill.amountDueProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue o, Object oldVal, Object newVal) {
                System.out.println("Electric bill has changed!");
            }
        });
        bill.setAmountDue(100.00);
    }
}

创建一个绑定的代码示例:

public class Binding {
    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());
        num1.set(2);
        System.out.println(sum.getValue());
    }
}

num1(依赖变量),num2(依赖变量)和sum(绑定变量),其中一个依赖变量改变时,绑定变量也会跟着改变。
使用Binding类的代码示例:

public class Binding {
    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());
//        num1.set(2);
//        System.out.println(sum.getValue());

        NumberBinding sum = Bindings.add(num1, num2);
        System.out.println(sum.getValue());
        num1.setValue(2);
        System.err.println(sum.getValue());
    }
}

两种方式结合的代码示例:

public class Binding {
    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());
//        num1.set(2);
//        System.out.println(sum.getValue());

//        NumberBinding sum = Bindings.add(num1, num2);
//        System.out.println(sum.getValue());
//        num1.setValue(2);
//        System.err.println(sum.getValue());


        IntegerProperty num3 = new SimpleIntegerProperty(3);
        IntegerProperty num4 = new SimpleIntegerProperty(4);
        //multiply乘法
        NumberBinding total = Bindings.add(num1.multiply(num2), num3.multiply(num4));
        System.out.println(total.getValue());
        num1.setValue(2);
        System.err.println(total.getValue());
    }
}

再看下面这个例子:

class Bill {
    private DoubleProperty amountDue = new SimpleDoubleProperty();
    public final double getAmountDue() {
        return amountDue.get();
    }
    public final void setAmountDue(double value) {
        amountDue.set(value);
    }
    public DoubleProperty amountDueProperty() {
        return amountDue;
    }
}

public class Proprety {

    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.");
            }
        });

        // First call makes the binding invalid
        bill1.setAmountDue(200.00);

        // The binding is now invalid
        bill2.setAmountDue(100.00);
        bill3.setAmountDue(75.00);

        // Make the binding valid...
        System.out.println(total.getValue());

        // Make invalid...
        bill3.setAmountDue(150.00);

        // Make valid...
        System.out.println(total.getValue());
    }
}

由于改变了单个账单的值,对应的绑定会变为无效,因此InvalidationListener会被触发。但是如果绑定已经无效了,即使另一个账单发生了改变,InvalidationListener也不会被再次触发。

使用低级绑定API的实例:

    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包括对某一个绑定类进行扩展并重写其computeValue()方法以返回绑定的当前值。使用了DoubleBinding 的一个自定义子类。子类中调用super.bind()方法将依赖变量向上传递给了DoubleBinding类,所以默认的失效行为会被保留。一般不需要检查绑定是否是失效;基类会为你提供这种行为。

上面的内容暂时只需要了解,看见代码能知道是什么作用即可。绑定的结果就是一个变量能够随着另一个变量的变化而变化。通常在进度条的变化中会使用到绑定。
以上是属性和绑定相关知识,下面是集合相关知识。此处的集合不是java基础中所学的集合。此处的集合可以监听到集合内元素的变化。

JavaFX集合由javafx.collections包定义,它由以下接口和类组成:

接口:
ObservableList:一种可以使用监听器(Listener)在发生改变时进行追踪的列表
ListChangeListener:一种可以接收ObservableList的改变通知的接口
ObservableMap:一种可以使用观察者(Observer)在发生改变时进行追踪改变的映射
MapChangeListener:一种可以接收ObservableMap的改变通知的接口

类:
FXCollections:一个工具类,其中包含了一些静态方法,它们与java.util.Collections中的方法一一对应
ListChangeListener.Change:代表ObservableList中的改变
MapChangeListener.Change:代表ObservableMap中的改变

public class CollectionsDemo {

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                System.out.println("Detected a change! ");
            }
        });
        observableList.add("item one");
        list.add("item two");
        System.out.println("Size: " + observableList.size());
//      下面是map
        Map<String, String> map = new HashMap<String, String>();

        ObservableMap<String, String> observableMap = FXCollections.observableMap(map);
        observableMap.addListener(new MapChangeListener() {
            @Override
            public void onChanged(MapChangeListener.Change change) {
                System.out.println("Detected a change! ");
            }
        });

        observableMap.put("key 1", "value 1");
        System.out.println("Size: " + observableMap.size());

        map.put("key 2", "value 2");
        System.out.println("Size: " + observableMap.size());
    }
}
public class TestCollections {

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("d");
        list.add("b");
        list.add("a");
        list.add("c");

        ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener() {

            @Override
            public void onChanged(ListChangeListener.Change change) {
                System.out.println("Detected a change! ");
                while (change.next()) {
                    System.out.println("Was added? " + change.wasAdded());
                    System.out.println("Was removed? " + change.wasRemoved());
                    System.out.println("Was replaced? " + change.wasReplaced());
                    System.out.println("Was permutated? " + change.wasPermutated());//顺序变化
                }
            }
        });
        FXCollections.sort(observableList);
    }
}

Q.E.D.


擅长前端的Java程序员