Java FX17 集合的属性和绑定

ObservableList、ObservableSet和ObservableMap集合可以被声明为Property对象。 它们还支持使用高级和低级绑定api的绑定。

理解ObservableList属性和绑定

ListProperty类实现了ObservableValue和ObservableList接口。它是一个可观察值,并且可以使用Observable List的所有方法。

可以使用SimpleListProperty类的下列构造函数之一来创建ListProperty的实例:

• SimpleListProperty() ​ • SimpleListProperty(ObservableList<E> initialValue) ​ • SimpleListProperty(Object bean, String name) ​ • SimpleListProperty(Object bean, String name, ObservableList<E> initialValue)

在使用ListProperty之前要将ObservableList传递给它的构造函数,在对ListProperty执行有意义的操作之前,它必须有一个对ObservableList的引用。在包装空引用的ListProperty上执行的操作将被视为在不可变的空ObservableList上执行的操作。

创建和初始ListProperty:

ObservableList<String> list1 = FXCollections.observableArrayList();
ListProperty<String> lp1 = new SimpleListProperty<String>(list1);
lp1.add("Hello");
ListProperty<String> lp2 = new SimpleListProperty<String>();
lp2.set(FXCollections.observableArrayList());
lp2.add("Hello");
观察ListProperty的变化

可以给ListProperty附加三种类型的监听器:

• An InvalidationListener ​ • A ChangeListener ​ • A ListChangeListener

// ListPropertyTest.java
package com.jdojo.collections;
​
import javafx.beans.Observable;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
​
public class ListPropertyTest {
    public static void main(String[] args) {
        // Create an observable list property
        ListProperty<String> lp =
                new SimpleListProperty<>(FXCollections.observableArrayList());
​
        // Add invalidation, change, and list change listeners
        lp.addListener(ListPropertyTest::invalidated);
        lp.addListener(ListPropertyTest::changed);
        lp.addListener(ListPropertyTest::onChanged);
​
        System.out.println("Before addAll()--------------");
        lp.addAll("one", "two", "three");
        System.out.println("After addAll()--------------------");
​
        System.out.println("\nBefore set()--------------------------");
​
        // Replace the wrapped list with a new one
        lp.set(FXCollections.observableArrayList("two", "three"));
        System.out.println("After set()---------------------------------");
​
        System.out.println("\nBefore remove()------------------------------");
        lp.remove("two");
        System.out.println("After remove()---------------------------------");
    }
​
    // An invalidation listener
    public static void invalidated(Observable list) {
        System.out.println("List property is invalid.");
    }
​
    // A change listener
    public static void changed(ObservableValue<? extends ObservableList<String>> observable,
                               ObservableList<String> oldList,
                               ObservableList<String> newList) {
        System.out.print("List Property has changed.");
        System.out.print(" Old List: " + oldList);
        System.out.println(", New List: " + newList);
    }
​
    // A list change listener
    public static void onChanged(ListChangeListener.Change<? extends String> change) {
        while (change.next()) {
            String action = change.wasPermutated() ? "Permutated" : change.wasUpdated()
                    ? "Updated" : change.wasRemoved() && change.wasAdded() ? "Replaced"
                    : change.wasRemoved() ? "Removed" : "Added";
​
            System.out.print("Action taken on the list: " + action);
            System.out.print(". Removed: " + change.getRemoved());
            System.out.println(", Added: " + change.getAddedSubList());
        }
    }
}
绑定ListProperty的大小和属性

ListProperty公开了两个属性,size和empty,它们的类型分别是ReadOnlyIntegerProperty和ReadOnlyBooleanProperty

package com.jdojo.collections;
​
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
​
public class ListBindingTest {
    public static void main(String[] args) {
        StringProperty desc = new SimpleStringProperty();
        StringProperty iniStr = new SimpleStringProperty("Size: ");
        ListProperty<String> lp = new SimpleListProperty<>(FXCollections.observableArrayList());
        desc.bind(iniStr.concat(lp.sizeProperty()).concat(" isEmpty: ").concat(lp.emptyProperty()));
        System.out.println(desc.get());
        lp.add("1");
        System.out.println(desc.get());
        lp.add("2");
        System.out.println(desc.get());
        lp.remove(0,2);
        System.out.println(desc.get());
​
​
    }
}
绑定List 属性和内容

支持列表属性的高级绑定的方法位于ListExpression和Bindings类中。 低级绑定可以通过创建ListBinding类的子类来创建。ListProperty支持两种类型的绑定:

• Binding the reference of the ObservableList that it wraps ​ • Binding the content of the ObservableList that it wraps

bind()和bindBidirectional()方法用于创建第一种绑定。

注意两个列表属性在绑定后都引用了同一个ObservableList。

package com.jdojo.collections;
​
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
​
public class BindingListReference {
    public static void main(String[] args) {
        ListProperty<String> lp1 = new SimpleListProperty<>(FXCollections.observableArrayList());
        ListProperty<String> lp2 = new SimpleListProperty<>(FXCollections.observableArrayList());
        lp1.bind(lp2);
        System.out.println("----------------------------------");
        System.out.println("lp1: "+ lp1.get());
        System.out.println("lp2: "+ lp2.get());
        System.out.println("----------------------------------");
        System.out.println();
        System.out.println("Add----------------------------------");
        lp1.addAll("1","2","3");
        lp1.get();
        System.out.println("lp1: "+ lp1);
        System.out.println("lp2: "+ lp2);
        System.out.println("----------------------------------");
        System.out.println();
        System.out.println("Add----------------------------------");
        lp2.add("4");
        lp1.get();
        System.out.println("lp1: "+ lp1);
        System.out.println("lp2: "+ lp2);
        System.out.println("----------------------------------");
        System.out.println();
        System.out.println("lp2改变引用----------------------------------");
        ObservableList<String> lp2cp = FXCollections.observableArrayList("2","3");
        lp2.set(lp2cp);
        lp1.get();
        System.out.println("lp1: "+ lp1);
        System.out.println("lp2: "+ lp2);
        System.out.println("----------------------------------");
        System.out.println();
    }
    public static void print(ListProperty<String> lp){
        System.out.println(lp.get());
    }
}

输出如下:

----------------------------------
lp1: []
lp2: []
----------------------------------
​
Add----------------------------------
lp1: ListProperty [bound, value: [1, 2, 3]]
lp2: ListProperty [value: [1, 2, 3]]
----------------------------------
​
Add----------------------------------
lp1: ListProperty [bound, value: [1, 2, 3, 4]]
lp2: ListProperty [value: [1, 2, 3, 4]]
----------------------------------
​
lp2改变引用----------------------------------
lp1: ListProperty [bound, value: [2, 3]]
lp2: ListProperty [value: [2, 3]]
----------------------------------

bindContent()和bindContentBidirectional()方法允许分别将包装在ListProperty中的ObservableList的内容在一个方向和两个方向上绑定到另一个ObservableList的内容。

package com.jdojo.collections;
​
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
​
public class BindingListContent {
    public static void main(String[] args) {
        ListProperty<String> lp1 = new SimpleListProperty<>(FXCollections.observableArrayList());
        ListProperty<String> lp2 = new SimpleListProperty<>(FXCollections.observableArrayList());
        lp1.bindContent(lp2);    //lp1绑定lp2,lp2变化lp1也变化
        print(lp1,lp2);
​
        //lp2改变lp1也改变,lp1使用addAll方法时,lp2不随着改变
        lp2.addAll("1","2","3");
        print(lp1,lp2);
        lp1.unbindContent(lp2);
        print(lp1,lp2);
        lp1.bindContentBidirectional(lp2);
        print(lp1,lp2);
        lp1.addAll("4","5");
        print(lp1,lp2);
        lp2.addAll("6","7");
        print(lp1,lp2);
    }
    public static void print(ListProperty<String> lp1, ListProperty<String> lp2){
        System.out.println("lp1: " + lp1.get() + " lp2: " + lp2.get());
        System.out.println("--------------------------------------");
​
    }
}
绑定List的元素

可以使用ListExpression类的以下方法之一绑定到包装在ListProperty中的ObservableList的特定元素:

• ObjectBinding<E> valueAt(int index) ​ • ObjectBinding<E> valueAt(ObservableIntegerValue index)

该方法的第一个版本创建了一个ObjectBinding,该ObjectBinding指向列表中特定索引处的元素。 第二个版本将索引作为参数,该参数是一个可随时间变化的ObservableIntegerValue。当valueAt()方法中的绑定索引在列表范围之外时,ObjectBinding包含null。

第二种方式:

// BindingToListElements.java
package com.jdojo.collections;
​
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
​
public class BindingToListElements {
    public static void main(String[] args) {
        ListProperty<String> lp =
                new SimpleListProperty<>(FXCollections.observableArrayList());
​
        // Create a binding to the last element of the list
        ObjectBinding<String> last = lp.valueAt(lp.sizeProperty().subtract(1));
        System.out.println("List:" + lp.get() + ", Last Value: " + last.get());
​
        lp.add("John");
        System.out.println("List:" + lp.get() + ", Last Value: " + last.get());
​
        lp.addAll("Donna", "Geshan");
        System.out.println("List:" + lp.get() + ", Last Value: " + last.get());
​
        lp.remove("Geshan");
        System.out.println("List:" + lp.get() + ", Last Value: " + last.get());
​
        lp.clear();
        System.out.println("List:" + lp.get() + ", Last Value: " + last.get());
    }
}

理解ObservableSet 属性和绑定

•SetProperty对象包装了一个ObservableSet,使用SetProperty与使用ListProperty非常相似。

•SetExpression和Bindings类包含了支持高级属性绑定的方法。需要创建SetBinding类的子类来 创建低级绑定。

•像ListProperty一样,SetProperty暴露了size和empty属性。

•像ListProperty一样,SetProperty支持引用和它包装的ObservableSet内容的绑定。

•像ListProperty一样,SetProperty支持三种类型的通知:无效通知,更改通知和设置更改通知。与list 不同,set是一组无序的项目集合。它的元素没有索引。它不支持绑定到它的特定元素。因此, SetExpression类不像ListExpression类那样包含valueAt()这样的方法。

可以使用下列SimpleSetProperty类的构造函数之一来创建SetProperty的实例:

• SimpleSetProperty() • SimpleSetProperty(ObservableSet<E> initialValue) • SimpleSetProperty(Object bean, String name) • SimpleSetProperty(Object bean, String name, ObservableSet<E> initialValue)

理解ObservableMap 属性和绑定

一个MapProperty对象包装了一个ObservableMap。使用MapProperty与使用ListProperty非常相似。

•MapExpression和Bindings类包含支持映射属性的高级绑定的方法。您需要创建MapBinding类的 子类来创建低级绑定。

•像ListProperty一样,MapProperty公开大小和空属性。

•像ListProperty一样,MapProperty支持引用的绑定和它包装的ObservableMap的内容。与 ListProperty一样,MapProperty支持三种类型的通知:无效通知、更改通知和映射更改通知。

•MapProperty支持使用valueAt()方法绑定到特定键的值。

创建MapProperty:

• SimpleMapProperty() ​ • SimpleMapProperty(Object bean, String name) ​ • SimpleMapProperty(Object bean, String name, ObservableMap<K,V> ​ initialValue) ​ • SimpleMapProperty(ObservableMap<K,V> initialValue)

// MapBindingTest.java
package com.jdojo.collections;
​
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.MapProperty;
import javafx.beans.property.SimpleMapProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
​
public class MapBindingTest {
    public static void main(String[] args) {
        MapProperty<String, Double> mp1 =
                new SimpleMapProperty<>(FXCollections.observableHashMap());
​
        // Create an object binding to bind mp1 to the value of the key "Ken"
        ObjectBinding<Double> kenSalary = mp1.valueAt("Ken");
        System.out.println("Ken Salary: " + kenSalary.get());
​
        // Bind the size and empty properties of the MapProperty
        // to create a description of the map
        StringProperty initStr = new SimpleStringProperty("Size: " );
        StringProperty desc = new SimpleStringProperty();
        desc.bind(initStr.concat(mp1.sizeProperty())
                .concat(", Empty: ")
                .concat(mp1.emptyProperty())
                .concat(", Map: " )
                .concat(mp1.asString())
                .concat(", Ken Salary: ")
                .concat(kenSalary));
​
        System.out.println("Before mp1.put(): " + desc.get());
​
        // Add some entries to mp1
        mp1.put("Ken", 7890.90);
        mp1.put("Jim", 9800.80);
        mp1.put("Lee", 6000.20);
        System.out.println("After mp1.put(): " + desc.get());
​
        // Create a new MapProperty
        MapProperty<String, Double> mp2 =
                new SimpleMapProperty<>(FXCollections.observableHashMap());
​
        // Bind the content of mp1 to the content of mp2
        mp1.bindContent(mp2);  //mp2内容为空,所以mp1也变为空
​
        System.out.println("Called mp1.bindContent(mp2)...");
        System.out.println("Before mp2.put(): " + desc.get());
        mp2.put("Ken", 7500.90);
        mp2.put("Cindy", 7800.20);
        System.out.println("After mp2.put(): " + desc.get());
    }
}

总结

JavaFX扩展了Java中的集合框架,增加了对可观察列表、集合和映射(称为可观察集合)的支持。可观察集合是一个列表、集合或映射,可以在无效和内容更改时进行观察。javafx中ObservableList, ObservableSet和ObservableMap接口的实例。集合包表示JavaFX中的可观察接口。您可以为这些可观察集合的实例添加无效和更改侦听器。

FXCollections类是一个用于处理JavaFX集合的实用程序类。它由所有静态方法组成。JavaFX不公开可观察列表、集合和映射的实现类。您需要使用FXCollections类中的一个工厂方法来创建ObservableList、ObservableSet和ObservableMap接口的对象。

JavaFX库提供了JavaFX中两个名为FilteredList和SortedList的类。FilteredList是一个ObservableList,它使用指定的谓词过滤它的内容。SortedList对其内容进行排序。

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值