首先需要声明一个要观察的对象,本例子中要观察的对象是Person,Person包含名和姓两个属性,然后为该类编写setter和getter。
package com.jdojo.collections;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person implements Comparable<Person> {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
public Person() {
this.setFirstName("Unknown");
this.setLastName("Unknown");
}
public Person(String firstName, String lastName) {
this.setFirstName(firstName);
this.setLastName(lastName);
}
public final String getFirstName() {
return firstName.get();
}
public final void setFirstName(String newFirstName) {
firstName.set(newFirstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public final String getLastName() {
return lastName.get();
}
public final void setLastName(String newLastName) {
lastName.set(newLastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
@Override
public int compareTo(Person p) {
// Assume that the first and last names are always not null
int diff = this.getFirstName().compareTo(p.getFirstName());
if (diff == 0) {
diff = this.getLastName().compareTo(p.getLastName());
}
return diff;
}
@Override
public String toString() {
return getFirstName() + " " + getLastName();
}
}
然后编写更改监听器类,它实现ListChangeListener接口的onChanged()方法来处理Person对象的ObservableList的所有类型的更改通知。
// PersonListChangeListener.java
package com.jdojo.collections;
import java.util.List;
import javafx.collections.ListChangeListener;
public class PersonListChangeListener implements ListChangeListener<Person> {
@Override
public void onChanged(ListChangeListener.Change<? extends Person> change) {
while (change.next()) {
if (change.wasPermutated()) { //被重新排列
handlePermutated(change);
}
else if (change.wasUpdated()) { //被更新
handleUpdated(change);
}
else if (change.wasReplaced()) { //被替换
handleReplaced(change);
}
else {
if (change.wasRemoved()) {
handleRemoved(change);
}
else if (change.wasAdded()) {
handleAdded(change);
}
}
}
}
public void handlePermutated(ListChangeListener.Change<? extends Person> change) {
System.out.println("Change Type: Permutated");
System.out.println("Permutated Range: " + getRangeText(change));
int start = change.getFrom();
int end = change.getTo();
for(int oldIndex = start; oldIndex < end; oldIndex++) {
int newIndex = change.getPermutation(oldIndex);
System.out.println("index[" + oldIndex + "] moved to " +
"index[" + newIndex + "]");
}
}
public void handleUpdated(ListChangeListener.Change<? extends Person> change) {
System.out.println("Change Type: Updated");
System.out.println("Updated Range : " + getRangeText(change));
System.out.println("Updated elements are: " +
change.getList().subList(change.getFrom(), change.getTo()));
}
public void handleReplaced(ListChangeListener.Change<? extends Person> change) {
System.out.println("Change Type: Replaced");
// A "replace" is the same as a “remove” followed with an "add"
handleRemoved(change);
handleAdded(change);
}
public void handleRemoved(ListChangeListener.Change<? extends Person> change) {
System.out.println("Change Type: Removed");
int removedSize = change.getRemovedSize();
List<? extends Person> subList = change.getRemoved();
System.out.println("Removed Size: " + removedSize);
System.out.println("Removed Range: " + getRangeText(change));
System.out.println("Removed List: " + subList);
}
public void handleAdded(ListChangeListener.Change<? extends Person> change) {
System.out.println("Change Type: Added");
int addedSize = change.getAddedSize();
List<? extends Person> subList = change.getAddedSubList();
System.out.println("Added Size: " + addedSize);
System.out.println("Added Range: " + getRangeText(change));
System.out.println("Added List: " + subList);
}
public String getRangeText(ListChangeListener.Change<? extends Person> change) {
return "[" + change.getFrom() + ", " + change.getTo() + "]";
}
}
然后创建一个测试类,类中创建了一个带有提取器的ObservableList,提取器返回Person对象的firstName和lastName属性数组。这意味着当这些属性之一发生更改时,作为列表元素的Person对象被视为已更新,并且将向所有更改侦听器发送更新通知。然后向列表中添加一个更改监听器。最后,对列表进行几种类型的更改来触发更改通知,更改通知的详细信息打印在标准输出中。
package com.jdojo.collections;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.util.Callback;
public class ListChangeTest {
public static void main(String[] args) {
Callback<Person, Observable[]> cb =
(Person p) -> new Observable[] {
p.firstNameProperty(),
p.lastNameProperty()
};
// Create a list
ObservableList<Person> list = FXCollections.observableArrayList(cb);
// Add a change listener to the list
list.addListener(new PersonListChangeListener());
Person p1 = new Person("Li", "Na");
System.out.println("Before adding " + p1 + ": " + list);
list.add(p1);
System.out.println("After adding " + p1 + ": " + list) ;
Person p2 = new Person("Vivi", "Gin");
Person p3 = new Person("Li", "He");
System.out.println("\nBefore adding " + p2 + " and " + p3 + ": " + list);
list.addAll(p2, p3);
System.out.println("After adding " + p2 + " and " + p3 + ": " + list);
System.out.println("\nBefore sorting the list:" + list);
FXCollections.sort(list);
System.out.println("After sorting the list:" + list);
System.out.println("\nBefore updating " + p1 + ": " + list);
p1.setLastName("Smith");
System.out.println("After updating " + p1 + ": " + list);
Person p = list.get(0);
Person p4 = new Person("Simon", "Ng");
System.out.println("\nBefore replacing " + p +
" with " + p4 + ": " + list);
list.set(0, p4);
System.out.println("After replacing " + p + " with " + p4 + ": " + list);
System.out.println("\nBefore setAll(): " + list);
Person p5 = new Person("Lia", "Li");
Person p6 = new Person("Liz", "Na");
Person p7 = new Person("Li", "Ho");
list.setAll(p5, p6, p7);
System.out.println("After setAll(): " + list);
System.out.println("\nBefore removeAll(): " + list);
list.removeAll(p5, p7); // Leave p6 in the list
System.out.println("After removeAll(): " + list);
Person p8 = new Person();
list.add(p8);
}
}
输出结果:
Before adding Li Na: []
Change Type: Added
Added Size: 1
Added Range: [0, 1]
Added List: [Li Na]
After adding Li Na: [Li Na]
Before adding Vivi Gin and Li He: [Li Na]
Change Type: Added
Added Size: 2
Added Range: [1, 3]
Added List: [Vivi Gin, Li He]
After adding Vivi Gin and Li He: [Li Na, Vivi Gin, Li He]
Before sorting the list:[Li Na, Vivi Gin, Li He]
Change Type: Permutated
Permutated Range: [0, 3]
index[0] moved to index[1]
index[1] moved to index[2]
index[2] moved to index[0]
After sorting the list:[Li He, Li Na, Vivi Gin]
Before updating Li Na: [Li He, Li Na, Vivi Gin]
Change Type: Updated
Updated Range : [1, 2]
Updated elements are: [Li Smith]
After updating Li Smith: [Li He, Li Smith, Vivi Gin]
Before replacing Li He with Simon Ng: [Li He, Li Smith, Vivi Gin]
Change Type: Replaced
Change Type: Removed
Removed Size: 1
Removed Range: [0, 1]
Removed List: [Li He]
Change Type: Added
Added Size: 1
Added Range: [0, 1]
Added List: [Simon Ng]
After replacing Li He with Simon Ng: [Simon Ng, Li Smith, Vivi Gin]
Before setAll(): [Simon Ng, Li Smith, Vivi Gin]
Change Type: Replaced
Change Type: Removed
Removed Size: 3
Removed Range: [0, 3]
Removed List: [Simon Ng, Li Smith, Vivi Gin]
Change Type: Added
Added Size: 3
Added Range: [0, 3]
Added List: [Lia Li, Liz Na, Li Ho]
After setAll(): [Lia Li, Liz Na, Li Ho]
Before removeAll(): [Lia Li, Liz Na, Li Ho]
Change Type: Removed
Removed Size: 1
Removed Range: [0, 0]
Removed List: [Lia Li]
Change Type: Removed
Removed Size: 1
Removed Range: [1, 1]
Removed List: [Li Ho]
After removeAll(): [Liz Na]