如何使用javafx.beans.binding.Bindings.select(...)进行简洁的值绑定

时间:2012-03-22 18:41:16

标签: java user-interface data-binding binding javafx-2

概述

作为一名十年的Swing开发人员,我对JavaFX 2.0引入的功能感到非常兴奋,特别是丰富,流畅,高级的数据绑定工具。仅此设施值得学习新API的成本(自放弃FX脚本以来,这个成本要少得多)。它将对我的模型/视图同步代码的可读性和可维护性产生直接影响。

到目前为止,我在第一级和基本派生绑定方面取得了巨大成功,但我正在努力找出将一个值绑定到数据图中两个或更多个间接值的“JavaFX方式”。

问题

如下面的代码示例所示,我正在尝试使用javafx.beans.binding.Bindings.select()将Label的文本值与ComboBox中当前所选项的一个包含属性同步。这段代码是我想要做的更复杂的一个简单例子,所以我理解用较低级别的绑定API做这件事并不难。我想知道是否可以使用更高级别的流畅API,以及select(...)方法是否实际跟踪间接属性的更改(即直接属性或所选子属性更改时更新属性)。 / p>

select(...)上的文档和示例很少,所以我希望有这方面经验的人可以告诉我,如果我尝试按照设计使用API​​,或者是否有其他方法可以使用高级绑定API,做我想做的事。

示例代码

这是演示代码。运行时,会有一个包含两个项目的ComboBox,然后是两个标签。第一个标签显示所选项目的toString()版本。第二个标签尝试显示所选项目的一个属性,但仅显示null

import static javafx.beans.binding.Bindings.*;
import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/** Testing cascading binding change triggers. */
public class SandboxTest extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        VBox root = new VBox(8);
        root.setStyle("-fx-padding: 8;");
        Scene s = new Scene(root);

        stage.setWidth(200);
        stage.setScene(s);

        ComboBox<MoPoJo> list = new ComboBox<SandboxTest.MoPoJo>();

        list.itemsProperty().set(FXCollections.observableArrayList(new MoPoJo("foo", "bar"), new MoPoJo("baz", "bat")));

        Label direct = new Label();
        direct.setTooltip(new Tooltip("Selected item to string"));
        Label withSelect = new Label();
        withSelect.setTooltip(new Tooltip("Second property of selected item"));

        direct.textProperty().bind(convert(list.getSelectionModel().selectedItemProperty()));
        withSelect.textProperty().bind(convert(select(list.getSelectionModel().selectedItemProperty(), "two")));

        root.getChildren().addAll(list, direct, withSelect);
        stage.show();
    }

    private static class MoPoJo {
        private StringProperty _one = new SimpleStringProperty();
        private StringProperty _two = new SimpleStringProperty();
        private StringProperty _name = new SimpleStringProperty();

        public MoPoJo(String o, String t) {
            _one.set(o);
            _two.set(t);
            _name.bind(format("{ %s, %s }", oneProperty(), twoProperty()));
        }

        public StringProperty oneProperty() {
            return _one;
        }

        public StringProperty twoProperty() {
            return _two;
        }

        public ReadOnlyStringProperty nameProperty() {
            return _name;
        }

        @Override
        public String toString() {
            return nameProperty().get();
        }
    }

}

1 个答案:

答案 0 :(得分:2)

Bindings.select无法访问私有类。使MoPoJo成为公共类,您的代码将起作用。

public static class MoPoJo {

P.S:我相信这个事实值得在文档中提及,所以我在JavaFX javadoc上提交了http://javafx-jira.kenai.com/browse/RT-20640