使用JavaFX,将ChoiceBox
绑定到集合属性的最佳方法是什么?
在下面的示例中,我尝试将ChoiceBox
元素绑定到name
ObservableList
的beans
。当添加/删除项目时,此方法工作正常,但当属性值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
使用。