JavaFX学习:ObservableList/ObservableSet/ObservableMap的invalidated事件和changed事件

ObservableList/ObservableSet/ObservableMap是JavaFX库的观察者集合类,它们继承java.util包的List、Set、Map接口,同时还继承JavaFX的集合接口和Observable接口。

ObservableList/ObservableSet/ObservableMap这些观察者集合有2个新特性:

  • 注册InvalidationListener接口,当集合数据失效时,触发invalidated事件通知,该事件继承自Observable接口。
  • 注册ListChangeListener接口,当几何数据修改时(增、删、改、重列)时,触发onChanged事件通知,该事件是JavaFX集合自定义的。

注意,这两个事件都能监听集合中元素的状态,根据条件触发。但元素中数据的状态只有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 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 changeListener) {
        Person person = getValue();
//        this.firstName.addListener(person.firstNameProperty().get());
    }

    @Override
    public void removeListener(ChangeListener 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 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事件;对象本身注册的事件执行优先级最高。

你可能感兴趣的:(个人学习,JavaFX,Java,学习,java,JavaFX)