JavaBean包装与JavaFX属性

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

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

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

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

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

 new SimpleStringProperty(bean, "name") 

是:

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

bean可以在ChangeListenerchanged(...)方法中使用,因为您可以检索从属性本身更改的属性的“拥有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 } 

您正在寻找的function:将现有Java Bean样式属性包装在JavaFX observable属性中是由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 ,则通过bean更改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注册的ChangeListenerInvalidationListener

所以,如果豆是简单的

 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