JavaFX學習:屬性中的invalidated事件和changed事件

JavaFX中的屬性與基礎數據(int,double,boolean等)一一對應,可以認爲是對基礎數據進行了包裝,相較基礎數據,屬性最大的區別就是屬性對“失效、修改”等事件可以做出反饋。

基礎數據與對應的屬性示例:

String:StringProperty, SimpleStringProperty, ReadOnlyStringProperty

int: IntegerProperty, SimpleIntegerProperty, ReadOnlyIntegerProprety

每個屬性都繼承了Observable,ObservableValue接口,必須實現void addListener(InvalidationListener listener)方法和void addListener(ChangeListener<? super T> listener)方法(remove方法是刪除監聽器)。

// Invalidate event
void addListener​(InvalidationListener listener)

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



// Change event
void addListener​(ChangeListener<? super T> listener)

interface ChangeListener{
    void changed​(ObservableValue<? extends T> observable, T oldValue, T newValue);
}

在此分別對Invalidate和Change進行測試。

Invalidate事件:

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事件。

 

Change事件:

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<? extends Number> 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

每次數據進行修改就會出發change事件。

 

如果一個屬性同時註冊監聽invalidate事件和chagne事件,那會怎麼處理,處理順序是什麼?

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<? extends Number> 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

從運行結果可以得出都是先觸發invalidate方法,後change方法。invalidte在Observable接口,是ObservableValue的超類接口(change方法在此接口中)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章