使用JavaFX,将ChoiceBox绑定到集合属性的最佳方法是什么?
在下面的示例中,我尝试将ChoiceBox元素绑定到name ObservableListbeans。当添加/删除项目时,此方法工作正常,但当属性值name更改时,则无效。

我希望对此有一个干净简单的解决方案,但尚未找到任何示例...

故意不使用属性实现类ExampleBean2,因为该对象可能对应于我无法控制的外部模型类。

package com.playground;

import org.controlsfx.control.PropertySheet;
import org.controlsfx.property.BeanPropertyUtils;

import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class BindingPlayGround extends Application{

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("FXPlayGround");
        Parent content = createContentPane();
        Scene scene = new Scene(content, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    protected Parent createContentPane() {
        ObservableList<BeanExample2> beans = FXCollections.observableArrayList();
        ObservableList<PropertySheet> sheets = FXCollections.observableArrayList();
        ListView<PropertySheet> listView = new ListView<PropertySheet>(sheets);
        Button addBeanButton = new Button("Add Bean");
        addBeanButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                BeanExample2 e = new BeanExample2();
                e.setName("Name-not-set");
                PropertySheet propertySheet = new PropertySheet(BeanPropertyUtils.getProperties(e));
                sheets.add(propertySheet);
                beans.add(e);
            }
        });

        VBox vBar = new VBox();
        vBar.getChildren().add(listView);
        vBar.getChildren().add(addBeanButton);
                ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
            @Override
            public Observable[] call(BeanExample2 param) {
                return new Observable[]{new SimpleStringProperty(param, "name")};
            }
        });
        Bindings.bindContent(names, beans);

        Button addChoiceBoxButton = new Button("Add ChoiceBox");
        addChoiceBoxButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                ChoiceBox<BeanExample2> choiceBox = new ChoiceBox<BeanExample2>(names);
                vBar.getChildren().add(choiceBox);
            }
        });
        vBar.getChildren().add(addChoiceBoxButton);
        return vBar;
    }

    static class BeanExample2 {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "BeanExample2{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
}

最佳答案

这里

ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
    @Override
    public Observable[] call(BeanExample2 param) {
        return new Observable[]{new SimpleStringProperty(param, "name")};
    }
});


您正在创建一个新属性,以侦听除call方法返回的值以外无法引用的更新。 BeanExample2实例和SimpleStringProperty之间的唯一关系是BeanExample2实例用作该属性的bean,除了可以通过该属性的getBean()方法使用之外,这没有任何作用。永远不会分配属性的值,更不用说对BeanExample2实例的更改进行修改了。

要正确触发ObservableList中的更新,您需要确保上述方法返回的数组中的元素实际上已收到更新通知。通常,您将属性添加到类本身:

public static class BeanExample2 {

    public final String getName() {
        return this.name.get();
    }

    private final StringProperty name = new SimpleStringProperty();

    public final void setName(String value) {
        this.name.set(value);
    }

    @Override
    public String toString() {
        return "BeanExample2{"
                + "name='" + name.get() + '\''
                + '}';
    }

    public final StringProperty nameProperty() {
        return this.name;
    }
}


并返回一个包含Callback中的属性的数组

ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
    @Override
    public Observable[] call(BeanExample2 param) {
        return new Observable[]{param.nameProperty()};
    }
});


请注意,当前ChoiceBox中似乎存在一个错误,该错误将每个中间值的条目添加到ChoiceBox

ComboBox没有此问题,可以代替ChoiceBox使用。

10-02 00:47
查看更多