Как использовать javafx.beans.binding.Bindings.select(...) для краткой привязки значения

Обзор

Как разработчик Swing в течение десяти лет, я был в восторге от особенностей, представленных с JavaFX 2.0, особенно с богатыми, плавными, высокоуровневыми средствами привязки данных. Этот объект сам по себе стоит затрат на изучение нового API (что намного меньше, так как отказ от FX script). Это будет иметь прямое отношение к читабельности и поддержке моего кода синхронизации модели/представления.

До сих пор я обладаю большим успехом на уровне первого и базовых производных привязок, но изо всех сил пытаюсь выяснить способ "JavaFX" привязки одного значения к значению двух или более уровней косвенности в графике данных.

Проблема

Как показано в приведенном ниже примере кода, я пытаюсь использовать javafx.beans.binding.Bindings.select() для синхронизации текстового значения метки с одним из содержащиеся свойства выбранного в данный момент элемента в ComboBox. Этот код является простым примером чего-то более сложного, который я пытаюсь сделать, поэтому я понимаю, что это не сложно сделать с помощью API привязок более низкого уровня. Я хотел бы знать, возможно ли это с использованием API-интерфейса более высокого уровня, и если метод select(...) фактически отслеживает изменения косвенных свойств (т.е. Свойство update, если либо свойство прямой, либо выбранное изменение подвыражения).

Документация и примеры на select(...) являются разреженными, поэтому я надеюсь, что кто-то с передовым опытом с этим может сказать мне, пытаюсь ли я использовать 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

Bindings.select не может получить доступ к закрытому классу. Сделайте MoPoJo открытый класс, и ваш код будет работать.

public static class MoPoJo {

P.S: Я считаю, что этот факт стоит упомянуть в документах, поэтому я подал http://javafx-jira.kenai.com/browse/RT-20640 на JavaFX javadoc.