JavaBean包装与JavaFX属性

war*_*awa 21 java model-view-controller model javafx javabeans

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

 SimpleStringProperty property = new SimpleStringProperty(bean, "name")
Run Code Online (Sandbox Code Playgroud)

期待这property.set("Foobar")会触发一个电话bean.setName.但这似乎不起作用.我错过了什么?

Jam*_*s_D 45

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

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

new SimpleStringProperty(bean, "name")
Run Code Online (Sandbox Code Playgroud)

是:

  • bean:属性所属的bean,如果有的话
  • name:财产的名称

bean可以在一个有用ChangeListenerchanged(...)方法,你可以检索从属性本身更改属性的'拥有豆’.该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
}
Run Code Online (Sandbox Code Playgroud)

您正在寻找的功能:将现有Java Bean样式属性包装在JavaFX observable属性中是由javafx.beans.property.adapter包中的类实现的.所以,例如,你可以做到

StringProperty nameProperty = new JavaBeanStringPropertyBuilder()
        .bean(bean)
        .name("name")
        .build();
Run Code Online (Sandbox Code Playgroud)

调用

nameProperty.set("James");
Run Code Online (Sandbox Code Playgroud)

使用此设置将有效地调用

bean.setName("James");
Run Code Online (Sandbox Code Playgroud)

如果bean支持PropertyChangeListeners,JavaBeanStringProperty则将PropertyChangeListener使用bean 注册a .name对Java Bean属性的任何更改都将通过JavaBeanStringPropertyJavaFX属性更改进行转换.因此,如果底层JavaBean支持PropertyChangeListeners,则通过更改bean

bean.setName(...);
Run Code Online (Sandbox Code Playgroud)

将导致任何ChangeListeners(或InvalidationListeners)JavaBeanStringProperty在收到变更通知时注册.

因此,例如,如果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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后是以下代码:

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());
Run Code Online (Sandbox Code Playgroud)

将产生输出:

name changed from to James 
James
Run Code Online (Sandbox Code Playgroud)

如果JavaBean不支持PropertyChangeListeners,那么对bean的更改bean.setName(...)将不会传播到ChangeListeners或InvalidationListeners注册的JavaBeanStringProperty.

所以,如果豆是简单的

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 ;
    }
}
Run Code Online (Sandbox Code Playgroud)

JavaBeanStringProperty无法观察更改,因此调用时永远不会调用更改侦听器bean.setName().所以上面的测试代码只会输出

James
Run Code Online (Sandbox Code Playgroud)