将标签的文本属性(在 FXML 文件中)绑定到 IntegerProperty(在控制器中) [英] Binding a Label's text property (in an FXML file) to an IntegerProperty (in a controller)

查看:13
本文介绍了将标签的文本属性(在 FXML 文件中)绑定到 IntegerProperty(在控制器中)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 文件

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

Each time I push the "Subtract 1" button, the counter will decrement by 1, and the counterLabel will update automatically.

现实

计数器确实减 1,但 counterLabel 仍然停留在 15(初始值).

The counter does decrement by 1, but the counterLabel remains stuck at 15 (the initial value).

问题

我的印象是(例如,来自此论坛帖子)我所做的应该有效.我错过了什么?

I was under the impression (e.g., from this forum post) that what I've done should work. What am I missing?

推荐答案

您需要向控制器添加 JavaFX 特定的访问器 variableNameProperty:

You need to add a JavaFX specific accessor variableNameProperty to the controller:

public IntegerProperty counterProperty() {
    return counter;
}

更多详细信息.
API 文档并未过多提及此 JavaFX 的 JavaBeans 架构.这里只是一个介绍(使用 JavaFX 属性和绑定)但同样没有关于它的必要性.

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.

所以让我们挖掘一些源代码!:)
直接,我们开始研究 FXMLLoader 代码.我们注意到绑定表达式的前缀为

So lets dig some source code! :)
Straightforwardly, we start to look into FXMLLoader code first. We notice prefix for binding expression as

public static final String BINDING_EXPRESSION_PREFIX = "${";

进一步在第 279 行 FXMLLoader 确定 if (isBindingExpression(value)) 然后创建绑定,实例化 BeanAdapter 并获取 propertyModel:

Further at line 279 FXMLLoader determines if (isBindingExpression(value)) then to create binding, instantiates BeanAdapter and gets 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);
}

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

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.

如果在 bean 中没有定义 getter 会发生什么?再次从 BeanAdapter#get() 代码我们可以说,如果找不到getCounter()",则返回空值,调用者只是将其作为无操作 imo 忽略.

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.

这篇关于将标签的文本属性(在 FXML 文件中)绑定到 IntegerProperty(在控制器中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆