Javafx TreeView 奇怪的选择行为

问题描述 投票:0回答:1

我尽量注意通过鼠标单击或按键选择 TreeView 项目的用户不会选择容器项目。按箭头键只能在叶项上上下移动。在容器项目上单击鼠标即可选择其第一片叶子。

我的数据非常简单。有简单的字符串容器,每个容器都有一个或多个叶子。

我的代码如下:

package volker.treeviewtest;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage stage) {
        VBox root = new VBox();
        root.setStyle("-fx-font-family: Helvetica");
        
        Label label = new Label();
        
        TreeItem<String> rootItem = new TreeItem<>("Root");
        rootItem.setExpanded(true);
        TreeItem<String> bough = new TreeItem<>("Bough");
        bough.setExpanded(true);
        bough.getChildren().addAll(
                new TreeItem<>("Bud"),
                new TreeItem<>("Buddy"));

        TreeItem<String> twig =
                new TreeItem<>("Twig");
        twig.setExpanded(true);
        twig.getChildren().addAll(
                new TreeItem<>("Tic"),
                new TreeItem<>("Tac"),
                new TreeItem<>("Toe"));

        TreeItem<String> twiggy =
                new TreeItem<>("Twiggy");
        twiggy.setExpanded(true);
        twiggy.getChildren().addAll(
                new TreeItem<>("Ene"),
                new TreeItem<>("Mene"),
                new TreeItem<>("Muh"));

        bough.getChildren().addAll(twig, twiggy);

        rootItem.getChildren().add(bough);

        TreeView<String> treeView = new TreeView<>(rootItem);
        treeView.setShowRoot(false);
        
        MultipleSelectionModel<TreeItem<String>> selModel =
                treeView.getSelectionModel();
        selModel.setSelectionMode(SelectionMode.SINGLE);
        selModel.selectIndices(1);
        
        selModel.selectedItemProperty().addListener((obs, oldVal, newVal) -> {
            TreeItem<String> newSelection = newVal;
            if (!newSelection.isLeaf()) {
                if (!newSelection.isExpanded()) {
                    newSelection.setExpanded(true);
                }
                TreeItem<String> firstLeaf = newSelection.getChildren().get(0);
                if (firstLeaf.equals(oldVal)) {
                    // From first leaf of current container
                    // to last leaf of previous container
                    TreeItem<String> prev = newSelection.previousSibling();
                    if (prev == null) {
                        newSelection = oldVal;
                    } else if (prev.isLeaf()) {
                        newSelection = prev;
                    } else {
                        prev.setExpanded(true);
                        int size = prev.getChildren().size();
                        TreeItem lastLeaf = prev.getChildren().get(size - 1);
                        newSelection = lastLeaf;
                    }
                } else {
                    newSelection = firstLeaf;
                }
            }
            selModel.select(newSelection);
            label.setText(newSelection.getValue());
        });
        
        root.getChildren().addAll(treeView, label);
        
        var scene = new Scene(root, 150, 300);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}

它按预期工作。但是...例如我单击“Ene”项目,然后单击三角形以将“Twig”容器设置为折叠。然后按向上箭头键(或单击“Twiggy”容器),我发现“Twig”已展开,并按预期选择了最后一片叶子(蓝色背景),但“Twiggy”有一个蓝色边框,再按一下向上箭头键不会改变任何内容。选择侦听器不会触发。

[在此输入图片描述](https://i.sstatic.net/82eYjcJT.png)

这不是什么大事,因为按下向下箭头,然后按下向上箭头(或鼠标单击某处)就可以结束这种奇怪的行为。但我很想知道为什么会发生这种情况以及我可以采取哪些措施来防止这种情况发生。有更好的方法来实现我的目标吗?

我知道问题31267157,但它似乎对我没有帮助。

javafx select treeview listener
1个回答
0
投票

James_D 建议的 hack 对我有用:

        selModel.selectedItemProperty().addListener((obs, oldVal, newVal) -> {
        if (!newVal.isLeaf()) {
            if (!newVal.isExpanded()) {
                newVal.setExpanded(true);
            }
            TreeItem<String> firstLeaf = newVal.getChildren().get(0);
            if (firstLeaf.equals(oldVal)) {
                // From first leaf of current container
                // to last leaf of previous container
                TreeItem<String> prev = newVal.previousSibling();
                if (prev == null) {
                    newVal = oldVal;
                } else if (prev.isLeaf()) {
                    newVal = prev;
                } else {
                    prev.setExpanded(true);
                    int size = prev.getChildren().size();
                    TreeItem lastLeaf = prev.getChildren().get(size - 1);
                    newVal = lastLeaf;
                }
            } else {
                newVal = firstLeaf;
            }
        }
        TreeItem<String> newSelection = newVal;
        Platform.runLater(() -> {
            selModel.select(newSelection);
            label.setText(newSelection.getValue());
        });
    });
© www.soinside.com 2019 - 2024. All rights reserved.