【问题标题】:JavaFX Listview Observe MapJavaFX Listview 观察地图
【发布时间】:2015-06-06 17:30:44
【问题描述】:

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

问题是,ListView.setItems() 想要一个 ObservableList,而我只有一个 keySet()。

我怎样才能让 ListView 观察我的 Map 中的键,而不做一些笨重的事情,比如维护两个匹配的数据结构?

【问题讨论】:

    标签: java listview dictionary javafx observers


    【解决方案1】:

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

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

    使用右侧的 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);
        }
    }
    

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

    【讨论】:

    • 这是一个很棒的详细答案。谢谢!
    猜你喜欢
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多