JavaBean 包装与 JavaFX 属性

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

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

预计这会触发对 的调用。但这似乎不起作用。我错过了什么?property.set("Foobar")bean.setName


答案 1

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

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

new SimpleStringProperty(bean, "name")

是:

  • bean:属性所属的豆类(如果有)
  • name:属性的名称

在 的方法中可能很有用,因为您可以检索从属性本身更改的属性的“owning bean”。可以类似地使用(如果您有相同的侦听器注册了多个属性,则可以找出哪个属性已更改:尽管我从不使用此模式)。beanChangeListenerchanged(...)name

因此,将 a 作为对象的可观察属性的典型用法如下所示: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 支持 s,则将向 bean 注册 a。对 Java Bean 属性的任何更改都将通过转换为 JavaFX 属性更改进行转换。因此,如果底层JavaBean支持s,则通过以下方式更改为bean。PropertyChangeListenerJavaBeanStringPropertyPropertyChangeListenernameJavaBeanStringPropertyPropertyChangeListener

bean.setName(...);

将导致任何 s (或 s) 注册与被通知的更改。ChangeListenerInvalidationListenerJavaBeanStringProperty

因此,例如,如果 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 不支持 s,则对 bean via 的更改将不会传播到在 中注册的 s 或 s。PropertyChangeListenerbean.setName(...)ChangeListenerInvalidationListenerJavaBeanStringProperty

因此,如果豆子只是

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

答案 2

推荐