JavaBean用JavaFX属性包装

23

我想使用JavaFX属性进行UI绑定,但不希望它们存在于我的模型类中(参见在模型类中使用javafx.beans属性)。我的模型类有getter和setter方法,我希望基于这些方法创建属性。例如,假设有一个实例bean,具有String getName()setName(String name)方法,我会写出以下代码:

 SimpleStringProperty property = new SimpleStringProperty(bean, "name")

我原本期望 property.set("Foobar") 会触发调用 bean.setName,但似乎没起作用。我错过了什么吗?


不要完全放弃在您的模型类中使用JavaFX属性的想法。我在您链接的问题中添加了一个替代答案:这可能是值得考虑的一种方法。 - James_D
1个回答

50

Simple*Property类是对应的Property抽象类的完整独立实现,不依赖于任何其他对象。因此,例如,SimpleStringProperty本身包含一个(私有的)String字段,它保存属性的当前值。

您展示的构造函数的参数:

new SimpleStringProperty(bean, "name")
  • bean: 属性所属的bean(如果有)
  • name: 属性的名称

ChangeListenerchanged(...)方法中,bean可以用于检索已更改属性的“所属bean”,因此很有用。 name也可以类似地使用(如果您已将相同的监听器注册到多个属性,则可以确定哪个属性已更改:但我从未使用过此模式)。

因此,将SimpleStringProperty用作对象的可观察属性的典型用法如下:

public class Person {
    private final StringProperty firstName 
        = new SimpleStringProperty(this, "firstName");

    public final String getFirstName() {
        return firstName.get();
    }

    public final void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }

    public StringProperty firstNameProperty() {
        return firstName ;
    }

    // ... other properties, etc
}

您要查找的功能:将现有的Java Bean样式属性包装在JavaFX可观察属性中,这一功能由javafx.beans.property.adapter包中的类实现。因此,例如,您可以执行以下操作:

StringProperty nameProperty = new JavaBeanStringPropertyBuilder()
        .bean(bean)
        .name("name")
        .build();

呼叫

nameProperty.set("James");

使用这个设置将有效地导致调用

bean.setName("James");
如果 bean 支持 PropertyChangeListener,则 JavaBeanStringProperty 将向 bean 注册一个 PropertyChangeListener。对于 Java Bean 的 name 属性的任何更改都将被 JavaBeanStringProperty 转换为 JavaFX 属性更改。因此,如果基础的 JavaBean 支持 PropertyChangeListener,则通过 PropertyChangeListener 更改 bean。
bean.setName(...);

将会导致任何已注册到 JavaBeanStringProperty 的 ChangeListener(或 InvalidationListener)被通知更改。

例如,如果 Bean 类是

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Bean {

    private String name ;
    private final PropertyChangeSupport propertySupport ;

    public Bean(String name) {
        this.name = name ;
        this.propertySupport = new PropertyChangeSupport(this);
    }

    public Bean() {
        this("");
    }

    public String getName() {
        return name ;
    }

    public String setName(String name) {
        String oldName = this.name ;
        this.name = name ;
        propertySupport.firePropertyChange("name", oldName, name);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertySupport.addPropertyChangeListener(listener);
    }
}

那么以下的代码:

Bean bean = new Bean();
StringProperty nameProperty() = new JavaBeanStringPropertyBuilder()
        .bean(bean)
        .name("name")
        .build();
nameProperty().addListener((obs, oldName, newName) -> System.out.println("name changed from "+oldName+" to "+newName));
bean.setName("James");
System.out.println(nameProperty().get());

将生成以下输出:

name changed from to James 
James
如果JavaBean不支持PropertyChangeListener,则通过bean.setName(...)对bean的更改将不会传播到注册在JavaBeanStringProperty上的ChangeListener或InvalidationListener。
因此,如果bean只是...
public class Bean {

    public Bean() {
        this("");
    }

    public Bean(String name) {
        this.name = name ;
    }

    private String name ;

    public String getName() {
        return name ;
    }

    public void setName(String name) {
        this.name = name ;
    }
}
JavaBeanStringProperty无法观察到更改,因此更改侦听器将永远不会被调用bean.setName()。因此,上面的测试代码将仅输出:
James

1
+1 很好的解释。JavaBeanStringPropertyBuilder 将为 bean 添加 PropertyChangeListener 支持。从答案中我觉得用户应该自己为 bean 添加这个支持。 - Uluk Biy
不完全正确:JavaBeanStringProperty 不会为 bean 添加 PropertyChangeListener 支持。回答已更新以澄清。 - James_D
您介意我请求您展示一下带有和不带有PropertyChangeListener支持的Java Bean示例吗? - Uluk Biy
@James_D,谢谢。对于集合属性(如List<Client>),是否有类似优雅的解决方案? - Danila Piatov
真遗憾,为了使用这个功能,我们不得不依赖于java.desktop模块(其中包括Swing、AWT)。 - kantianethics
请查看此问题:https://stackoverflow.com/questions/53587113/javabeanproperties-in-javafx-without-pulling-in-java-desktop-swing-awt - kantianethics

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接