对于我正在做的事情,我需要将javafx.scene.control.ComboBox
的成员设置为Map#keySet()
集的成员。
ComboBox中可用的选项需要在更新Map的键时更新。 (基本上,我想使用ComboBox从Map中选择成员,这些成员将在运行时更新。)
很遗憾,ComboBox#itemsProperty().bind(ObservableValue<>)
和ComboBox#itemsProperty().set(ObservableList<>)
都不会使用Set&lt;&gt;,因此将itemsProperty连接到Map#keySet
的直接路径无效。
基本上:
我怎样才能使ComboBox的项目成为Map的keySet的成员?
同样,我需要的行为是ComboBox
的项目将反映我KeySet
的{{1}}。 (Map
可以是Map
的任何实现。)
编辑:问题似乎是在Map
中创建ObservableList
- 在本例中为Collection
- 而不仅仅是一个副本,而是一个引用Set
,Set
将反映ObservableList
的内容。
答案 0 :(得分:3)
如果您有ObservableMap
,则可以为其添加监听器。例如:
ComboBox<String> comboBox = ... ;
ObservableMap<String, Something> map = ... ;
map.addListener((MapChangeListener.Change<? extends String, ? extends Something> c) ->
comboBox.getItems().setAll(map.keySet()));
您也可以使用绑定来执行此操作,但我认为它不是更清洁:
comboBox.itemsProperty().bind(Bindings.createObjectBinding(() ->
FXCollections.observableArrayList(map.keySet()),
map);
这是一个SSCCE,展示了这两种技术:
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class BindItemsToKeySet extends Application {
@Override
public void start(Stage primaryStage) {
ObservableMap<Integer, Item> itemLookupById = FXCollections.observableHashMap();
ComboBox<Integer> listenerCombo = new ComboBox<>();
ComboBox<Integer> bindingCombo = new ComboBox<>();
itemLookupById.addListener((MapChangeListener.Change<? extends Integer, ? extends Item> c) ->
listenerCombo.getItems().setAll(itemLookupById.keySet())
);
bindingCombo.itemsProperty().bind(Bindings.createObjectBinding(() ->
FXCollections.observableArrayList(itemLookupById.keySet()),
itemLookupById));
TextField textField = new TextField();
textField.setOnAction(e -> {
if (textField.getText().isEmpty()) {
return ;
}
Item item = new Item(textField.getText());
itemLookupById.put(item.getId(), item);
textField.clear();
});
textField.setTooltip(new Tooltip("Type an item name and press enter"));
VBox root = new VBox(10,
textField,
listenerCombo,
bindingCombo);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 250, 350));
primaryStage.show();
}
public static class Item {
private final int id ;
private final String name ;
private final static AtomicInteger nextID = new AtomicInteger(1000);
public Item(String name) {
this.id = nextID.incrementAndGet();
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
launch(args);
}
}