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对其内容进行排序。