将 Label 的文本属性(在 FXML 文件中)绑定到 Integer 属性(在控制器中)

2022-09-03 09:14:14

我已经在FXML文件中的标签和关联控制器中的整数属性之间设置了数据绑定。问题在于,虽然标签在初始化时设置为正确的值,但当属性的值更改时,它不会更新。

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,计数器标签将自动更新。

现实

计数器递减 1,但计数器标签仍停留在 15(初始值)。

问题

我的印象是(例如,从这个论坛帖子中),我所做的应该有效。我错过了什么?


答案 1

您需要将 JavaFX 特定的访问器变量 NameProperty 添加到控制器:

public IntegerProperty counterProperty() {
    return counter;
}

编辑:更多细节。
API文档没有提到这个JavaFX的JavaBeans架构。这里只是介绍一下(使用JavaFX属性和绑定),但同样没有关于它的必要性。

因此,让我们挖掘一些源代码!:)
很简单,我们首先开始研究FXMLLoader代码。我们注意到绑定表达式的前缀为

public static final String BINDING_EXPRESSION_PREFIX = "${";

在第279行,FXMLLoader确定然后创建绑定,实例化并获取属性模型:if (isBindingExpression(value))BeanAdapter

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);
}

在 get
() 方法中,它只是由反射调用的 getter(counterProperty 或 getCounter 或 isCounter)委托给,返回结果。如果 getter 不存在,则返回 null。换句话说,如果 JavaBean 中不存在 “counterProperty()”,则在我们的案例中返回 null。在这种情况下,由于 FXMLLoader 中的语句,不执行绑定。因此,没有“counterProperty()”方法没有绑定。BeanAdapter#get()String PROPERTY_SUFFIX = "Property";if (propertyModel instanceof Property<?>)

如果 getter 没有在 bean 中定义,会发生什么情况?同样,从代码中我们可以说,如果找不到“getCounter()”,则返回null,并且调用方只是将其忽略为no-op imo。BeanAdapter#get()


答案 2

推荐