JavaFX Listview观察地图

Ste*_*eve 2 java listview dictionary javafx observers

我有一个HashMap。我想在ListView中显示键。

麻烦的是,ListView.setItems()想要一个ObservableList,而我所拥有的只是一个keySet()。

如何获得ListView来观察Map中的键,而又不做一些笨拙的事情,例如维护两个匹配的数据结构?

jew*_*sea 5

我知道这不是您想要的答案,但是...我的建议是维护两个数据结构。

示例应用程序(同步数据结构)

使用右侧的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 http://stackoverflow.com/a/25829097/1155209
    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);
    }
}
Run Code Online (Sandbox Code Playgroud)

可能的不将数据复制到ObservableList中的替代实现是实现ObservableList接口,并且在实现的方法中直接引用可观察图的关键数据。这种方法实施起来非常复杂,不值得追求(IMO)。