我在FXML文件中的Label和相关控制器中的IntegerProperty之间设置了数据绑定。问题是,虽然标签在初始化时被设置为正确的值,但是当属性的值发生变化时它不会更新。
FXML文件
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<GridPane xmlns:fx="http://javafx.com/fxml"
fx:controller="application.PaneController" minWidth="200">
<Label id="counterLabel" text="${controller.counter}" />
<Button translateX="50" text="Subtract 1"
onAction="#handleStartButtonAction" />
</GridPane>
控制器
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
public class PaneController implements Initializable
{
private IntegerProperty counter;
public int getCounter()
{
return counter.get();
}
public void setCounter(int value)
{
counter.set(value);
}
public PaneController()
{
counter = new SimpleIntegerProperty(15);
}
@Override
public void initialize(URL url, ResourceBundle resources)
{
}
@FXML
private void handleStartButtonAction(ActionEvent event)
{
setCounter(getCounter() - 1);
System.out.println(getCounter());
}
}
期望
每按一次“减1”按钮,计数器将减1,counterLabel将自动更新。
现实
计数器减1,但counterLabel仍然停留在15(初始值)。
问题
我的印象(例如,来自this forum post)我所做的事情应该起作用。我错过了什么?
答案 0 :(得分:33)
您需要将一个特定于JavaFX的访问者 variableName 属性添加到控制器:
public IntegerProperty counterProperty() {
return counter;
}
编辑:更多细节。
API文档并未提及此JavaFX的JavaBeans体系结构。只是在这里介绍一下(Using JavaFX Properties and Binding),但同样没有关于它的必要性。
所以让我们挖掘一些源代码吧! :)
直截了当,我们首先开始研究FXMLLoader code。我们注意到绑定表达式的前缀为
public static final String BINDING_EXPRESSION_PREFIX = "${";
此外,在第279行,FXMLLoader确定if (isBindingExpression(value))
然后创建绑定,实例化BeanAdapter
并获取propertyModel:
BeanAdapter targetAdapter = new BeanAdapter(this.value);
ObservableValue<Object> propertyModel = targetAdapter.getPropertyModel(attribute.name);
如果我们查看BeanAdapter #getPropertyModel()
,
public <T> ObservableValue<T> getPropertyModel(String key) {
if (key == null) {
throw new NullPointerException();
}
return (ObservableValue<T>)get(key + BeanAdapter.PROPERTY_SUFFIX);
}
在追加BeanAdapter#get()
后委托给String PROPERTY_SUFFIX = "Property";
在get()方法中,只需通过反射调用getter(counterProperty或getCounter或isCounter),返回结果。如果getter不存在,则返回null。换句话说,如果JavaBean中不存在“counterProperty()”,则在我们的情况下返回null。在这种情况下,由于FXMLLoader中的语句if (propertyModel instanceof Property<?>)
,未执行绑定。因此,没有“counterProperty()”方法没有绑定。
如果未在bean中定义getter会发生什么?再次从BeanAdapter#get()
代码我们可以说,如果找不到“getCounter()”,则null返回并且调用者只是将其忽略为no-op imo。