JavaFX Listview 观察地图
JavaFX Listview Observe Map
我有一个 HashMap。我想在 ListView 中显示键。
问题是,ListView.setItems() 想要一个 ObservableList,而我只有一个 keySet()。
如何让 ListView 观察我的 Map 中的键,而不做一些笨拙的事情,比如维护两个匹配的数据结构?
我知道这不是你想要的答案,但是...我的建议是维护两个数据结构。
示例应用程序(同步数据结构)
使用右侧的 UI 向地图添加项目,随着 extension -> mimeType
地图中的键更改,您将在左侧的 ListView 中看到自动显示的键列表更新。
该解决方案侦听包装 extension -> mimetype
地图的 ObservableMap 的变化,并且当地图中的键发生变化时,将相关更新应用于支持 ListView 的 ObservableList。
在下面的示例屏幕截图中,当用户按下“添加”按钮时,png
将被添加到左侧列表中。
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
public class ObservableMapTest extends Application {
// map initializer based on
private static final Map<String, String> extensionToMimeMap =
Arrays.stream(new String[][]{
{"txt", "text/plain"},
{"html", "text/html"},
{"js", "application/javascript"},
{"css", "text/css"}
}).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));
@Override
public void start(Stage stage) throws Exception {
// create an observable wrapper for our map data.
final ObservableMap<String, String> observableExtensionToMimeMap = FXCollections.observableMap(
extensionToMimeMap
);
// create an ListView based on key items in the map.
ListView<String> extensionListView = new ListView<>();
extensionListView.getItems().setAll(extensionToMimeMap.keySet());
extensionListView.setPrefWidth(100);
// have the ListView observe the underlying map and modify its items if the key set changes.
observableExtensionToMimeMap.addListener((MapChangeListener<String, String>) change -> {
extensionListView.getItems().removeAll(change.getKey());
if (change.wasAdded()) {
extensionListView.getItems().add(change.getKey());
}
});
// layout the app.
Pane layout = new HBox(
extensionListView,
createAddExtensionPane(
observableExtensionToMimeMap
)
);
layout.setPrefHeight(150);
// display the app.
stage.setScene(new Scene(layout));
stage.show();
}
/** Helper factory function to create a UI for adding an element to an map. */
private GridPane createAddExtensionPane(Map<String, String> map) {
GridPane addExtensionPane = new GridPane();
addExtensionPane.add(new Label("Extension:"), 0, 0);
TextField extensionField = new TextField();
addExtensionPane.add(extensionField, 1, 0);
addExtensionPane.add(new Label("Mime Type:"), 0, 1);
TextField mimeTypeField = new TextField();
addExtensionPane.add(mimeTypeField, 1, 1);
Button addButton = new Button("Add");
addButton.setOnAction(event ->
map.put(
extensionField.getText(),
mimeTypeField.getText()
)
);
addExtensionPane.add(addButton, 1, 2);
addExtensionPane.setPadding(new Insets(10));
addExtensionPane.setHgap(5);
addExtensionPane.setVgap(10);
return addExtensionPane;
}
public static void main(String[] args) {
launch(args);
}
}
不将数据复制到 ObservableList 的可能替代实现是实现 ObservableList 接口,并在实现的方法中直接引用可观察地图的关键数据。这种方法实施起来非常复杂,不值得追求 (IMO)。
我有一个 HashMap。我想在 ListView 中显示键。
问题是,ListView.setItems() 想要一个 ObservableList,而我只有一个 keySet()。
如何让 ListView 观察我的 Map 中的键,而不做一些笨拙的事情,比如维护两个匹配的数据结构?
我知道这不是你想要的答案,但是...我的建议是维护两个数据结构。
示例应用程序(同步数据结构)
使用右侧的 UI 向地图添加项目,随着 extension -> mimeType
地图中的键更改,您将在左侧的 ListView 中看到自动显示的键列表更新。
该解决方案侦听包装 extension -> mimetype
地图的 ObservableMap 的变化,并且当地图中的键发生变化时,将相关更新应用于支持 ListView 的 ObservableList。
在下面的示例屏幕截图中,当用户按下“添加”按钮时,png
将被添加到左侧列表中。
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
public class ObservableMapTest extends Application {
// map initializer based on
private static final Map<String, String> extensionToMimeMap =
Arrays.stream(new String[][]{
{"txt", "text/plain"},
{"html", "text/html"},
{"js", "application/javascript"},
{"css", "text/css"}
}).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));
@Override
public void start(Stage stage) throws Exception {
// create an observable wrapper for our map data.
final ObservableMap<String, String> observableExtensionToMimeMap = FXCollections.observableMap(
extensionToMimeMap
);
// create an ListView based on key items in the map.
ListView<String> extensionListView = new ListView<>();
extensionListView.getItems().setAll(extensionToMimeMap.keySet());
extensionListView.setPrefWidth(100);
// have the ListView observe the underlying map and modify its items if the key set changes.
observableExtensionToMimeMap.addListener((MapChangeListener<String, String>) change -> {
extensionListView.getItems().removeAll(change.getKey());
if (change.wasAdded()) {
extensionListView.getItems().add(change.getKey());
}
});
// layout the app.
Pane layout = new HBox(
extensionListView,
createAddExtensionPane(
observableExtensionToMimeMap
)
);
layout.setPrefHeight(150);
// display the app.
stage.setScene(new Scene(layout));
stage.show();
}
/** Helper factory function to create a UI for adding an element to an map. */
private GridPane createAddExtensionPane(Map<String, String> map) {
GridPane addExtensionPane = new GridPane();
addExtensionPane.add(new Label("Extension:"), 0, 0);
TextField extensionField = new TextField();
addExtensionPane.add(extensionField, 1, 0);
addExtensionPane.add(new Label("Mime Type:"), 0, 1);
TextField mimeTypeField = new TextField();
addExtensionPane.add(mimeTypeField, 1, 1);
Button addButton = new Button("Add");
addButton.setOnAction(event ->
map.put(
extensionField.getText(),
mimeTypeField.getText()
)
);
addExtensionPane.add(addButton, 1, 2);
addExtensionPane.setPadding(new Insets(10));
addExtensionPane.setHgap(5);
addExtensionPane.setVgap(10);
return addExtensionPane;
}
public static void main(String[] args) {
launch(args);
}
}
不将数据复制到 ObservableList 的可能替代实现是实现 ObservableList 接口,并在实现的方法中直接引用可观察地图的关键数据。这种方法实施起来非常复杂,不值得追求 (IMO)。