ObservableList/ObservableSet/ObservableMap是JavaFX库的观察者集合类,它们继承java.util包的List、Set、Map接口,同时还继承JavaFX的集合接口和Observable接口。
ObservableList/ObservableSet/ObservableMap这些观察者集合有2个新特性:
注意,这两个事件都能监听集合中元素的状态,根据条件触发。但元素中数据的状态只有invalidated事件会监听。
操作类:
package learnjavafx8.ch03;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
/**
* @copyright 2023-2022
* @package learnjavafx8.ch03
* @file SimpleListChangeTest01.java
* @date 2023-06-12 16:19
* @author qiao wei
* @version 1.0
* @brief 测试ObservableList实例注册的事件ListChange是否会监控列表中元素字段的修改。经过测试修改列表中元素
* Person并不会触发事件ListChange。如果ObservableList实例注册事件invalidated,修改列表中元素
* Person同时会触发ObservableList实例注册的invalidated事件。
* @history
*/
public class SimpleListChangeTest01 {
public static void main(String[] args) {
ObservableList observableList = FXCollections.observableArrayList();
// 列表注册监听事件之前添加元素,不会触发监听事件。
observableList.add(new Person("A", "1"));
// Register changed listener and invalidated listener.
observableList.addListener(SimpleListChangeTest01::onChanged);
observableList.addListener(SimpleListChangeTest01::invalidated);
// 列表中添加元素Person,触发列表的监听事件。
observableList.add(new Person("CC", "33"));
FXCollections.sort(observableList);
System.out.println("Modify element's data");
// 修改列表中元素的值,没有触发列表的事件ListChange,没有触发列表的事件invalidated。
observableList.get(0).addListener(SimpleListChangeTest01::invalidatedForData);
observableList.get(0).setFirstName("B");
// 移除列表中索引为1的元素,触发列表的监听事件。
// observableList.remove(1);
}
public static void onChanged(ListChangeListener.Change extends Person> personChange) {
while (personChange.next()) {
/**
* 注意change的事件序列。wasReplaced事件由wasRemoved和wasAdded两个事件组合而成,所以将
* wasReplaced事件在wasRemoved和wasAdded事件之前处理。
*/
if (personChange.wasPermutated()) {
System.out.println("List was permutated: " + personChange);
} else if (personChange.wasUpdated()) {
System.out.println("List was updated : " + personChange);
} else if (personChange.wasReplaced()) {
System.out.println("List was replaced : " + personChange);
} else {
if (personChange.wasAdded()) {
System.out.println("List was added : " + personChange);
} else if (personChange.wasRemoved()) {
System.out.println("List was removed : " + personChange);
}
}
}
}
/**
* @class SimpleListChangeTest01
* @date 2023-06-12 21:14
* @author qiao wei
* @version 1.0
* @brief This method is called if an Observable becomes invalid.
* @param observable The Observable that became invalid.
* @return
* @throws
*/
public static void invalidated(Observable observable) {
System.out.println("Fire invalidated method!");
if (observable instanceof ObservableList) {
System.out.println("It is ObservableList instance!");
ObservableList observableList = (ObservableList) observable;
}
}
public static void invalidatedForData(Observable observable) {
System.out.println("Fired in data");
}
}
Person类:
package learnjavafx8.ch03;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
/**
* @copyright 2023-2022
* @package learnjavafx8.ch03
* @file Person.java
* @date 2023-06-11 21:18
* @author qiao wei
* @version 1.0
* @brief 继承Comparable。实现Comparable接口进行实例比较。Person有多个属性作为字段,通过组合方式处理数据。
* Person类继承Observable, ObservableValue接口,实现对invalidated事件和change事件的
* 处理。
* @history
*/
public class Person implements Comparable,
Observable,
ObservableValue,
Cloneable {
/**
* @class Person
* @date 2023-06-11 21:19
* @author qiao wei
* @version 1.0
* @brief Default constructor.
* @param
* @return
* @throws
*/
public Person() {
this("Unknown", "Unknown");
}
/**
* @class Person
* @date 2023-06-11 21:19
* @author qiao wei
* @version 1.0
* @brief Constructor.
* @param firstName First name.
* @param lastName Last name.
* @return
* @throws
*/
public Person(String firstName, String lastName) {
this.setFirstName(firstName);
this.setLastName(lastName);
addListener(Person::invalidated);
}
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 person) {
// person为null,返回1,当前instance的值大于person
if (null == person) {
return 1;
}
// Assume that the first and last names are always not null
int diff = this.getFirstName().compareTo(person.getFirstName());
if (0 == diff) {
diff = this.getLastName().compareTo(person.getLastName());
}
return diff;
}
@Override
public void addListener(InvalidationListener invalidationListener) {
this.firstName.addListener(invalidationListener);
this.lastName.addListener(invalidationListener);
}
@Override
public void removeListener(InvalidationListener invalidationListener) {
this.firstName.removeListener(invalidationListener);
this.lastName.removeListener(invalidationListener);
}
/**
* @class Person
* @date 2023-06-11 21:26
* @author qiao wei
* @version 1.0
* @brief 实现接口ObservableValue的方法。
* @param changeListener
* @return
* @throws
*/
@Override
public void addListener(ChangeListener super Person> changeListener) {
Person person = getValue();
// this.firstName.addListener(person.firstNameProperty().get());
}
@Override
public void removeListener(ChangeListener super Person> changeListener) {
// helper = ExpressionHelper.removeListener(helper, changeListener);
}
@Override
public Person getValue() {
Person person = null;
try {
person = (Person) super.clone();
} catch (CloneNotSupportedException exception) {
exception.printStackTrace();
} finally {
return person;
}
}
/**
* @class Person
* @date 2023-06-11 21:21
* @author qiao wei
* @version 1.0
* @brief 实现Cloneable接口。重写clone方法,进行深拷贝。
* @param
* @return
* @throws
*/
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.firstName = this.firstName;
person.lastName = this.lastName;
return person;
}
@Override
public String toString() {
return getFirstName() + "." + getLastName();
}
private static void changed(ObservableValue extends StringProperty> property,
StringProperty oldValue,
StringProperty newValue) {
System.out.println("String changed : ");
System.out.println("Old = " + oldValue + ", New = " + newValue + "\n");
}
private static void invalidated(Observable observable) {
System.out.println("调用Person类的invalidated方法");
System.out.println("打印数据 :" + observable.toString());
}
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
}
运行结果:
// 修改列表元素,调用列表注册的invalidated事件和onChanged事件
Fire invalidated method!
It is ObservableList instance!
List was added : { [CC.33] added at 1 }
Fire invalidated method!
It is ObservableList instance!
List was permutated: { permutated by [0, 1] }
// 修改元素的数据,调用元素Person注册的invalidated事件和列表注册invalidated事件
Modify element's data
调用Person类的invalidated方法
打印数据 :StringProperty [value: B]
Fired in data
可以看到。列表注册的onChanged事件只能够监听到列表元素的改变,但是不能监听到元素自身数据的改变,元素自身的改变只能由列表注册的invalidated事件或元素注册的监听事件监听到。
同时需注意的是注册事件的执行顺序,同一控件中invalidated事件执行先于changed事件;对象本身注册的事件执行优先级最高。