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方法在此接口中)。