Как использовать javafx.beans.binding.Bindings.select (...) для краткой привязки значений - PullRequest
11 голосов
/ 22 марта 2012

Обзор

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

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

Проблема

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

Документация и примеры по 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 Ответ

2 голосов
/ 27 марта 2012

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

public static class MoPoJo {

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

...