JavaFX 学习:属性和字段

107 篇文章 7 订阅

现在的编程体系,都是面向对象编程,其中分为两个部分:方法 + 字段,其中字段设置为 private,通过方法读取字段,外界程序不直接对字段操作。

在程序运行过程中,经常会对对象的字段进行更新,所以如何将更新的字段信息通知,这是要注意的问题。在 JavaFX 中,可以使用属性 Property 替代字段,使用属性的监听器通知所有监听者,在数据修改时通知监听者更新数据。每个基本类型字段的属性接口:***Property,对应的属性实例有 2 种,分别是 Simple***Property 和 ReadOnly***Wrapper,第 2 个是属性的包装器。

属性示例,属性构成 Book 类中的字段:

package learnjavafx8.ch02;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

/**************************************************************************************************
 @copyright  2003-2022
 @package    learnjavafx8.ch02
 @file       Book.java
 @date       2021/7/10 12:22
 @author     qiao wei
 @version    1.0
 @brief      Book. Test properties
 @history
**************************************************************************************************/
public class Book {
    
    /**********************************************************************************************
     * @class   Book
     * @date    2022-12-24 15:11
     * @author  qiao wei
     * @version 1.0
     * @brief   Default constructor
     * @param   
     * @return  
     * @throws
     *********************************************************************************************/
    public Book() {
        this("Unknown", 0.0d, "Unknown");
    }
    
    /**********************************************************************************************
     * @class   Book
     * @date    2022-12-24 15:10
     * @author  qiao wei
     * @version 1.0
     * @brief   Constructor
     * @param   
     * @return  
     * @throws
     *********************************************************************************************/
    public Book(String title, double price, String ISBN) {
        this.titleProperty = new SimpleStringProperty(this, "title", title);
        this.priceProperty = new SimpleDoubleProperty(this, "price", price);
        
        // Property wrapper. It can read/write
        this.ISBN = new ReadOnlyStringWrapper(this, "ISBN", ISBN);
    }
    
    /**********************************************************************************************
     @class      Book
     @date       2022/1/16 22:09
     @author     qiao wei
     @version    1.0
     @brief      Get title Property
     @return     The title property
    **********************************************************************************************/
    public final StringProperty getTitleProperty() {
        return titleProperty;
    }
    
    /**********************************************************************************************
     @class      Book
     @date       2022/1/16 22:09
     @author     qiao wei
     @version    1.0
     @brief      Get book title
     @return     The book title
    **********************************************************************************************/
    public final String getTitle() {
        return titleProperty.get();
    }

    public final void setTitle(String title) {
        titleProperty.set(title);
    }
    
    /**********************************************************************************************
     @class      Book
     @date       2022/1/16 22:10
     @author     qiao wei
     @version    1.0
     @brief      Get the book price property
     @return     The book price property
    **********************************************************************************************/
    public final DoubleProperty getPriceProperty() {
        return priceProperty;
    }

    /**********************************************************************************************
     @class      Book
     @date       2022/1/16 22:13
     @author     qiao wei
     @version    1.0
     @brief      Get the book price
     @return     The book price
    **********************************************************************************************/
    public double getPrice() {
        return priceProperty.get();
    }
    
    public final void setPrice(double price) {
        priceProperty.set(price);
    }

    /**********************************************************************************************
     @class      Book
     @date       2022/1/16 22:20
     @author     qiao wei
     @version    1.0
     @brief      获取只读型ISBN属性
     @return     ISBN属性
    **********************************************************************************************/
    public final ReadOnlyStringProperty getISBNProperty() {
        return ISBN.getReadOnlyProperty();
    }
    
    /**********************************************************************************************
     @class      Book
     @date       2022/1/16 22:21
     @author     qiao wei
     @version    1.0
     @brief      获取只读型ISBN数据
     @return     ISBN数据
    **********************************************************************************************/
    public final String getISBN() {
        return ISBN.get(); 
    }
    
    /**********************************************************************************************
     @date      2022/1/16 22:06
     @author    qiao wei
     @brief     Book title property
    **********************************************************************************************/
    private StringProperty titleProperty;
    
    /**********************************************************************************************
     @date      2022/1/16 22:06
     @author    qiao wei
     @brief     Price property
    **********************************************************************************************/
    private DoubleProperty priceProperty;
    
    /**********************************************************************************************
     @date      2022/1/16 22:06
     @author    qiao wei
     @brief     Book ISBN. Read only field
    **********************************************************************************************/
    private ReadOnlyStringWrapper ISBN;

}

测试 Book 类:

package learnjavafx8.ch02;

import javafx.beans.property.ReadOnlyProperty;
//import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

/**************************************************************************************************
 @copyright  2003-2022
 @package    learnjavafx8.ch02
 @file       BookTest.java
 @date       2022/1/26 16:21
 @author     qiao wei
 @version    1.0
 @brief      Test JavaFX property
 @history
**************************************************************************************************/
public class BookTest {

    public static void main(String[] args) {
        Book book = new Book("Harnessing JavaFX", 9.99d, "0123456789");
        System.out.println("After creating the Book object...");

        BookTest.printDetails(book.getTitleProperty());
//        printDetails(book.getPriceProperty());
//        printDetails(book.getISBNProperty());

//        book.setTitle("JavaFX 8.0");
        /** book.setPrice(22.49d);*/
        StringProperty property = book.getTitleProperty();
        property.set("Test");
        

        System.out.println("\nTitle changed to JavaFX 8.0, and Price is 22.49" );
        System.out.println("After changing the Book object...\n");

        printDetails(book.getTitleProperty());
//        printDetails(book.getPriceProperty());
//        printDetails(book.getISBNProperty());
        
//        TestClass tc = new TestClass("Harnessing JavaFX", 9.99d, "0123456789");
    }
    
    /**********************************************************************************************
     @class      BookTest
     @date       2022/1/26 16:21
     @author     qiao wei
     @version    1.0
     @brief      Print book's details
     @param      property book property
    **********************************************************************************************/
    private static void printDetails(ReadOnlyProperty<?> property) {
        // Get the object's property implementing from the property interface
        String name = property.getName();
        Object bean = property.getBean();
        Object value = property.getValue();
        
        String beanClassName = (null == bean) ? "null" : bean.getClass().getSimpleName();
        String propClassName = property.getClass().getSimpleName();

        System.out.print(propClassName);
        System.out.print("[Name = " + name);
        System.out.print(", Bean Class = " + beanClassName);
        System.out.println(", Value = " + value + "]");

        System.out.println("propClass = " + propClassName);
    }
}

运行结果:

After creating the Book object...
SimpleStringProperty[Name = title, Bean Class = Book, Value = Harnessing JavaFX]
propClass = SimpleStringProperty

Title changed to JavaFX 8.0, and Price is 22.49
After changing the Book object...

SimpleStringProperty[Name = title, Bean Class = Book, Value = Test]
propClass = SimpleStringProperty

从结果上看,使用属性并没有带来什么新的特性,相较于 String,double 步骤多,反而麻烦。但是属性有 2 种事件监听,分别是失效事件 invalidated 和改变事件 changed,分别可以对数据的改变做出反应,通知数据的监听者,这是 String 等类型数据没有的,数据更新注意两者的区别。

// 无效事件方法,继承自Observable接口
void addListener​(InvalidationListener listener)

// 改变事件方法,继承自ObservableValue接口
void addListener​(ChangeListener<? super T> listener)

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");
        
        // At this point counter property is invalid and further changes to its value will not 
        // generate invalidation events
        System.out.println("\nBefore 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");

        // 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("\nBefore changing the counter value-3");
        counter.set(102);
        System.out.println("After changing the counter value-3");

        // Try to set a different value
        System.out.println("\nBefore changing the counter value-4");
        counter.set(103);
        System.out.println("After changing the counter value-4");
    }
    
    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

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   
     * @return  
     * @throws
     *********************************************************************************************/
    private static void fireChangedEvent(IntegerProperty prop, int newNumber, int counter) {
        System.out.println("\nBefore changing the counter value-" + counter);
        
        // Set new value
        prop.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   prop 触发事件的实例,在这里是changedFunction方法中的实例property
     * @param   oldValue 触发事件前的值
     * @param   newValue 触发事件后的值
     * @return  
     * @throws
     *********************************************************************************************/
    private static void changed(ObservableValue<? extends Number> prop,
                                Number oldValue,
                                Number newValue) {
        System.out.println("Number changed : ");
        System.out.println("Old = " + oldValue + ", New = " + newValue);
    }
}

运行结果:

Before changing the counter value-1
Number changed : 
Old = 100, New = 101
After changing the counter value-1

Before changing the counter value-2
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
Number changed : 
Old = 102, New = 104
After changing the counter value-4

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值