JavaFX 学习:属性中的 invalidated 事件和 changed 事件

JavaFX 中的属性与基础数据(int,double,boolean 等)一一对应,可以认为是对基础数据进行了包装,相较基础数据,属性最大的区别就是属性对 “失效、修改” 等事件可以做出反馈。

基础数据与对应的属性示例:

String:StringProperty, SimpleStringProperty, ReadOnlyStringProperty

int: IntegerProperty, SimpleIntegerProperty, ReadOnlyIntegerProprety

每个属性都继承了 Observable,ObservableValue 接口,必须实现 void addListener​(InvalidationListener listener) 方法和 void addListener​(ChangeListener listener) 方法(remove 方法是删除监听器)。

// Invalidate event
void addListener​(InvalidationListener listener)

// 接口
interface InvalidationListener {
    void invalidated​(Observable observable);
}



// Change event
void addListener​(ChangeListener listener)

// 接口
interface ChangeListener{
    void changed​(ObservableValue observable, T oldValue, T newValue);
}

在此分别对 Invalidate 和 Change 进行测试。

注意Invalidation event和Changed event的区别: change events and invalidation events. A change event indicates that the value has changed (see note 2 in "Implementation Requirements"). An invalidation event is generated if the current value is not valid anymore. This distinction becomes important if the ObservableValue supports lazy evaluation, because for a lazily evaluated value one does not know if an invalid value really has changed until it is recomputed. For this reason, generating change events requires eager evaluation while invalidation events can be generated for eager and lazy implementations.(转载JavaFX17中接口ObservableValue介绍)。

Invalidated事件:

package learnjavafx8.ch02;

import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;

/**************************************************************************************************
 * @copyright 2003-2022
 * @package   learnjavafx8.ch02
 * @file      InvalidationTest.java
 * @date      2022/11/19 11:30
 * @author    qiao wei
 * @version   1.0
 * @brief     
 * @history
 *************************************************************************************************/
public class InvalidationTest {

    public static void main(String[] args) {
        IntegerProperty counter = new SimpleIntegerProperty(100);
        
        // Register an invalidation listener to counter property
        counter.addListener(InvalidationTest::invalidated);

        // Set the same value 100
        System.out.println("Before invalidating the counterProperty value-1--------------------");
        // 数据从100到100,没有触发invalidation event
        counter.set(100);
        System.out.println("Before invalidating the counterProperty value-1-------------------\n");
        
        // At this point counter property is invalid and further changes to its value will not 
        // generate invalidation events
        System.out.println("Before changing the counter value-2--------------------");
        counter.set(102);
        System.out.println("counter's value is not changed, invalidating event is ");
        System.out.println("After changing the counter value-2-------------------\n");

        // Make the counter property valid by calling its get() method
        int value = counter.get();
        System.out.println("Counter value = " + value);
        
        // At this point counter property is valid and further changes to its value will generate
        // invalidation events.

        // Try to set the same value
        System.out.println("Before changing the counter value-3--------------------");
        counter.set(102);
        System.out.println("After changing the counter value-3-------------------\n");

        // Try to set a different value
        System.out.println("Before changing the counter value-4--------------------");
        counter.set(103);
        System.out.println("After changing the counter value-4--------------------\n");
    }
    
    public static void invalidated(Observable property) {
        System.out.println("Counter is invalid. The invalidation event is fired.");
    }
}




运行结果:
Before invalidating the counterProperty value-1--------------------
Before invalidating the counterProperty value-1-------------------

Before changing the counter value-2--------------------
Counter is invalid. The invalidation event is fired.
counter's value is not changed, invalidating event is 
After changing the counter value-2-------------------

Counter value = 102
Before changing the counter value-3--------------------
After changing the counter value-3-------------------

Before changing the counter value-4--------------------
Counter is invalid. The invalidation event is fired.
After changing the counter value-4--------------------


Process finished with exit code 0

每次数据的变化都会触发 invalidate 事件。

Changed事件:

package learnjavafx8.ch02;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ObservableValue;

/**************************************************************************************************
 * @copyright 2003-2022
 * @package   learnjavafx8.ch02
 * @file      ChangeTest.java
 * @date      2020/5/2 18:51
 * @author    qiao wei
 * @version   1.0
 * @brief     Test change event declared from ObservableValue interface
 * @history
 *************************************************************************************************/
public class ChangeTest {

    public static void main(String[] args) {
        changedFunction();
    }
    
    private static void changedFunction() {
        IntegerProperty property = new SimpleIntegerProperty(100);
        
        // Register change listener
        property.addListener(ChangeTest::changed);
        
        fireChangedEvent(property, 101, 1);
        fireChangedEvent(property, 102, 2);
        
        // New value is the same with old value, the change event is not fired
        fireChangedEvent(property, 102, 3);
        
        fireChangedEvent(property, 104, 4);
    }
    
    /**********************************************************************************************
     * @class   ChangeTest
     * @date    2023-01-19 12:59
     * @author  qiao wei
     * @version 1.0
     * @brief   Fire change event by reset property
     * @param   property Property
     * @param   newNumber The new value
     * @param   counter The number of count
     * @return  
     * @throws
     *********************************************************************************************/
    private static void fireChangedEvent(IntegerProperty property, int newNumber, int counter) {
        System.out.println("\nBefore changing the counter value-" + counter);
        
        // Set new value, fire change event
        property.set(newNumber);
        System.out.println("After changing the counter value-" + counter);
    }
    
    /**********************************************************************************************
     * @class   ChangeTest
     * @date    2022/10/22 16:33
     * @author  qiao wei
     * @version 1.0
     * @brief   修改事件
     * @param   property 触发事件的实例,在这里是changedFunction方法中的实例property。触发事件会自动判定传入
     *                    的oldValue和newValue
     * @param   oldValue 触发事件前的值
     * @param   newValue 触发事件后的值
     * @return  
     * @throws
     *********************************************************************************************/
    private static void changed(ObservableValue property,
                                Number oldValue,
                                Number newValue) {
        // Observable instance's value is the new value
        System.out.println("Property's value : " + property.getValue().intValue());
        System.out.println("Number changed : ");
        System.out.println("Old = " + oldValue + ", New = " + newValue);
    }
}



// 运行结果
Before changing the counter value-1
Property's value : 101
Number changed : 
Old = 100, New = 101
After changing the counter value-1

Before changing the counter value-2
Property's value : 102
Number changed : 
Old = 101, New = 102
After changing the counter value-2

Before changing the counter value-3
After changing the counter value-3

Before changing the counter value-4
Property's value : 104
Number changed : 
Old = 102, New = 104
After changing the counter value-4

每次数据进行修改就会出发changed事件。

如果一个属性同时注册监听invalidated事件和chagned事件,那会怎么处理,处理顺序是什么?

package learnjavafx8.ch02;

import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ObservableValue;

/**************************************************************************************************
 * @copyright 2003-2022
 * @package   learnjavafx8.ch02
 * @file      ChangeAndInvalidationTest.java
 * @date      2020/5/3 12:10
 * @author    qiao wei
 * @version   1.0
 * @brief     测试ChangeListener和InvalidationListener方法的区别。Invalidation事件触发在Change事件之前
 * @history
 *************************************************************************************************/
public class ChangeAndInvalidationTest {

    public static void main(String[] args) {
        IntegerProperty counter = new SimpleIntegerProperty(100);

        // Register a change listener to the property
        counter.addListener(ChangeAndInvalidationTest::changed);
        
        // Register an invalidation listener to the property
        counter.addListener(ChangeAndInvalidationTest::invalidated);    
        
        printDetails(counter, 101, 1);
        printDetails(counter, 102, 2);
        
        // No change value, no validate no change, skip to call invalidated and changed method
        printDetails(counter, 102, 3);
        printDetails(counter, 104, 4);
    }
    
    /**********************************************************************************************
     * @class   ChangeAndInvalidationTest
     * @date    2023-01-30 22:08
     * @author  qiao wei
     * @version 1.0
     * @brief   Invalidate event
     * @param   observable Observer
     * @return  
     * @throws
     *********************************************************************************************/
    public static void invalidated(Observable observable) {
        System.out.println("Counter is in invalid status");
    }
    
    /**********************************************************************************************
     * @class   ChangeAndInvalidationTest
     * @date    2023-01-24 15:44
     * @author  qiao wei
     * @version 1.0
     * @brief   Change event
     * @param   observableValue Observer
     * @param   oldValue Old value
     * @param   newValue New value
     * @return  
     * @throws
     *********************************************************************************************/
    public static void changed(ObservableValue observableValue,
                               Number oldValue,
                               Number newValue) {
        System.out.println("Counter is changed: ");
        System.out.println("old = " + oldValue + ", new = " + newValue);
    }
    
    /**********************************************************************************************
     * @class   ChangeAndInvalidationTest
     * @date    2023-01-24 15:48
     * @author  qiao wei
     * @version 1.0
     * @brief   Print details
     * @param   
     * @return  
     * @throws
     *********************************************************************************************/
    private static void printDetails(IntegerProperty property, int newNumber, int counter) {
        System.out.println("\nBefore setting the counter value:" + counter);
        // Reset property value and fire invalidate event first and change event second
        property.set(newNumber);
        System.out.println("After setting the counter value:" + counter);
    }
}

运行结果:

Before setting the counter value:1
Counter is in invalid status
Counter is changed: 
old = 100, new = 101
After setting the counter value:1

Before setting the counter value:2
Counter is in invalid status
Counter is changed: 
old = 101, new = 102
After setting the counter value:2

Before setting the counter value:3
After setting the counter value:3

Before setting the counter value:4
Counter is in invalid status
Counter is changed: 
old = 102, new = 104
After setting the counter value:4

Process finished with exit code 0

从运行结果可以得出都是先触发 invalidated方法,后 changed方法。invalidted在Observable接口定义,是ObservableValue的超类接口(changed 方法在此接口中)。

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