使用 JavaFX 属性包装 JavaBean
Posted
技术标签:
【中文标题】使用 JavaFX 属性包装 JavaBean【英文标题】:JavaBean wrapping with JavaFX Properties 【发布时间】:2014-06-24 16:27:51 【问题描述】:我想将 JavaFX 属性用于 UI 绑定,但我不想在我的模型类中使用它们(请参阅 Using javafx.beans properties in model classes)。我的模型类有 getter 和 setter,我想基于它们创建属性。例如,假设一个实例 bean
具有 String getName()
和 setName(String name)
方法,我会写
SimpleStringProperty property = new SimpleStringProperty(bean, "name")
预计property.set("Foobar")
会触发对bean.setName
的调用。但这似乎不起作用。我错过了什么?
【问题讨论】:
不要完全放弃在模型类中使用 javafx 属性的想法。我为您链接的问题添加了一个替代答案:这可能是一种值得考虑的方法。 【参考方案1】:Simple*Property
类是其对应的Property
抽象类的完整独立实现,不依赖于任何其他对象。因此,例如,SimpleStringProperty
包含一个(私有)String
字段本身,它包含属性的当前值。
你展示的构造函数的参数:
new SimpleStringProperty(bean, "name")
是:
bean
: 属性所属的bean,如果有的话
name
: 属性名称
bean
在ChangeListener
的changed(...)
方法中很有用,因为您可以检索从属性本身更改的属性的“拥有 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
s,JavaBeanStringProperty
将向 bean 注册一个 PropertyChangeListener
。对 Java Bean 的 name
属性的任何更改都将由 JavaBeanStringProperty
转换为 JavaFX 属性更改。因此,如果底层的JavaBean支持PropertyChangeListener
s,那么通过
bean.setName(...);
将导致向JavaBeanStringProperty
注册的任何ChangeListener
s(或InvalidationListener
s)收到更改通知。
所以,例如,如果 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
s,则通过 bean.setName(...)
对 bean 所做的更改将不会传播到使用 JavaBeanStringProperty
注册的 ChangeListener
s 或 InvalidationListener
s。
所以如果 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 很好的解释。 JavaBeanStringPropertyBuilder 将为 bean 添加 PropertyChangeListener 支持。从答案中我觉得用户应该将自己的支持添加到 bean 中。 不完全是:JavaBeanStringProperty
没有为 bean 添加PropertyChangeListener
支持。答案已更新以澄清。
如果我要求您也展示一个带有和不带有 PropertyChangeListener 支持的示例 Java Bean,您介意吗?
@James_D,谢谢。集合属性是否有类似的优雅解决方案,例如 List以上是关于使用 JavaFX 属性包装 JavaBean的主要内容,如果未能解决你的问题,请参考以下文章
使用 Launch4j VM 参数路径包装的 JavaFX 项目