Java 将标签的文本属性(在 FXML 文件中)绑定到 IntegerProperty(在控制器中)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19822717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Binding a Label's text property (in an FXML file) to an IntegerProperty (in a controller)
提问by devuxer
I've set up a data binding between a Label in an FXML file and an IntegerProperty in the associated controller. The problem is that, while the label gets set to the correct value upon initialization, it is not updating when the property's value changes.
我已经在 FXML 文件中的 Label 和关联控制器中的 IntegerProperty 之间设置了数据绑定。问题是,虽然标签在初始化时被设置为正确的值,但当属性的值改变时它不会更新。
FXML file
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>
Controller
控制器
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());
}
}
Expectation
期待
Each time I push the "Subtract 1" button, the counter will decrement by 1, and the counterLabel will update automatically.
每次按下“减去 1”按钮,计数器都会减 1,并且 counterLabel 会自动更新。
Reality
现实
The counter does decrement by 1, but the counterLabel remains stuck at 15 (the initial value).
计数器确实减 1,但 counterLabel 仍然停留在 15(初始值)。
Question
题
I was under the impression (e.g., from this forum post) that what I've done should work. What am I missing?
我的印象是(例如,从这个论坛帖子)我所做的应该有效。我错过了什么?
采纳答案by Uluk Biy
You need to add a JavaFX specific accessor variableNamePropertyto the controller:
您需要向控制器添加 JavaFX 特定的访问器variableName属性:
public IntegerProperty counterProperty() {
return counter;
}
EDIT: More details.
The API documentation mentions not so much about this JavaFX's JavaBeans architecture. Just an introduction about it here (Using JavaFX Properties and Binding) but again nothing about its necessity.
编辑:更多细节。
API 文档并未过多提及此 JavaFX 的 JavaBeans 架构。这里只是介绍一下它(使用 JavaFX 属性和绑定),但同样没有关于它的必要性。
So lets dig some source code! :)
Straightforwardly, we start to look into FXMLLoader codefirst. We notice prefix for binding expression as
所以让我们挖掘一些源代码!:)
直截了当,我们首先开始研究FXMLLoader 代码。我们注意到绑定表达式的前缀为
public static final String BINDING_EXPRESSION_PREFIX = "${";
Further at line 279 FXMLLoader determines if (isBindingExpression(value))
then to create binding, instantiates BeanAdapter
and gets propertyModel:
进一步在第 279 行 FXMLLoader 确定if (isBindingExpression(value))
然后创建绑定,实例化BeanAdapter
并获取 propertyModel:
BeanAdapter targetAdapter = new BeanAdapter(this.value);
ObservableValue<Object> propertyModel = targetAdapter.getPropertyModel(attribute.name);
If we look into BeanAdapter#getPropertyModel()
,
如果我们查看BeanAdapter#getPropertyModel()
,
public <T> ObservableValue<T> getPropertyModel(String key) {
if (key == null) {
throw new NullPointerException();
}
return (ObservableValue<T>)get(key + BeanAdapter.PROPERTY_SUFFIX);
}
it delegates to BeanAdapter#get()
after appending String PROPERTY_SUFFIX = "Property";
In the get() method, simply the getter (either counterProperty or getCounter or isCounter) invoked by reflection, returning the result back. If the getter does not exist null returned back. In other words, if the "counterProperty()" does not exist in JavaBean, null returned back in our case. In this case the binding is not performed due to the statement if (propertyModel instanceof Property<?>)
in FXMLLoader. As a result, no "counterProperty()" method no bindings.
它委托给BeanAdapter#get()
后附加String PROPERTY_SUFFIX = "Property";
在 get() 方法中,简单地调用反射调用的 getter(counterProperty 或 getCounter 或 isCounter),返回结果。如果 getter 不存在,则返回 null。换句话说,如果 JavaBean 中不存在“counterProperty()”,则在我们的例子中返回 null。在这种情况下,由于if (propertyModel instanceof Property<?>)
FXMLLoader 中的语句,不会执行绑定。因此,没有“counterProperty()”方法没有绑定。
What happens if the getter is not defined in the bean? Again from the BeanAdapter#get()
code we can say that if the "getCounter()" cannot be found the null returned back and the caller just ignores it as no-op imo.
如果在 bean 中没有定义 getter 会发生什么?再次从BeanAdapter#get()
代码中我们可以说,如果找不到“getCounter()”,则返回空值,调用者只是将其作为无操作 imo 忽略。