当前位置: 首页 > 知识库问答 >
问题:

TreeView-不允许选择某些TreeItems

宗波涛
2023-03-14

我创建了一个Treeview(javafx),它看起来像:

我现在想要的是,只有“tour”-树项是可选择的。但我不知道怎么做。

我已经用ChangeListener尝试过了,但我只能用它刷新选项卡(TabPane)的内容...刷新很好...但是可以选择“delivery”-TreeItems:(

public void showTours(List<Tour> pTours) {

    treeViewPane.getSelectionModel().selectedItemProperty().addListener(treeItemChangeListener);

    TreeItem tTreeRoot = new TreeItem<>("Root", new ImageView(Icons.getIcon24("truck_blue.png")));
    tTreeRoot.setExpanded(true);
    treeViewPane.setRoot(tTreeRoot);

    for (Tour tTour : pTours) {

        TreeItem<Object> tTourItem = new TreeItem<>(tTour);
        tTreeRoot.getChildren().add(tTourItem);

        if (tTour.getDeliveries() != null) {
            for (Delivery tDelivery : tTour.getDeliveries()) {

                TreeItem<Object> tDeliveryItem = new TreeItem<>(tDelivery);
                tTourItem.getChildren().add(tDeliveryItem);
            }
        }
    }
}

private final ChangeListener<TreeItem> treeItemChangeListener = (observable, oldValue, newValue) -> {

    if (newValue != null && newValue.getValue() instanceof Tour){
        Tour selectedTour = (Tour) newValue.getValue();
        reloadTabContent(selectedTour);
    }
};

共有1个答案

洪弘亮
2023-03-14

在JavaFX中修改任何控件中的选择行为似乎有点麻烦;但是这样做的“正确”方法是为树定义一个自定义选择模型。最简单的方法是包装默认的选择模型,并将方法调用委托给它,如果选择索引是不应该选择的项,则否决选择。

当调用select方法时,最好尽可能选择一些内容,否则键盘导航将中断。

下面是一个实现:

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class CustomTreeSelectionModelExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        TreeItem<Object> root = new TreeItem<>("Root");
        for (int i = 1 ; i <= 5 ; i++) {
            TreeItem<Object> item = new TreeItem<>(new Tour("Tour "+i));
            for (int j = 1 ; j <= 5; j++) {
                Delivery delivery = new Delivery("Delivery "+j);
                item.getChildren().add(new TreeItem<>(delivery));
            }
            root.getChildren().add(item);
        }
        TreeView<Object> tree = new TreeView<>();
        tree.setSelectionModel(new TourSelectionModel(tree.getSelectionModel(), tree));
        tree.setRoot(root);

        primaryStage.setScene(new Scene(new BorderPane(tree), 400, 400));
        primaryStage.show();
    }

    public static class TourSelectionModel extends MultipleSelectionModel<TreeItem<Object>> {

        private final MultipleSelectionModel<TreeItem<Object>> selectionModel ;
        private final TreeView<Object> tree ;

        public TourSelectionModel(MultipleSelectionModel<TreeItem<Object>> selectionModel, TreeView<Object> tree) {
            this.selectionModel = selectionModel ;
            this.tree = tree ;
            selectionModeProperty().bindBidirectional(selectionModel.selectionModeProperty());
        }

        @Override
        public ObservableList<Integer> getSelectedIndices() {
            return selectionModel.getSelectedIndices() ;
        }

        @Override
        public ObservableList<TreeItem<Object>> getSelectedItems() {
            return selectionModel.getSelectedItems() ;
        }

        @Override
        public void selectIndices(int index, int... indices) {

            List<Integer> indicesToSelect = Stream.concat(Stream.of(index), IntStream.of(indices).boxed())
                    .filter(i -> tree.getTreeItem(i).getValue() instanceof Tour)
                    .collect(Collectors.toList());


            if (indicesToSelect.isEmpty()) {
                return ;
            }
            selectionModel.selectIndices(indicesToSelect.get(0), 
                    indicesToSelect.stream().skip(1).mapToInt(Integer::intValue).toArray());

        }

        @Override
        public void selectAll() {
            List<Integer> indicesToSelect = IntStream.range(0, tree.getExpandedItemCount())
                    .filter(i -> tree.getTreeItem(i).getValue() instanceof Tour)
                    .boxed()
                    .collect(Collectors.toList());
            if (indicesToSelect.isEmpty()) {
                return ;
            }
            selectionModel.selectIndices(0, 
                    indicesToSelect.stream().skip(1).mapToInt(Integer::intValue).toArray());
        }

        @Override
        public void selectFirst() {
            IntStream.range(0, tree.getExpandedItemCount())
                .filter(i -> tree.getTreeItem(i).getValue() instanceof Tour)
                .findFirst()
                .ifPresent(selectionModel::select);
        }

        @Override
        public void selectLast() {
            IntStream.iterate(tree.getExpandedItemCount() - 1, i -> i - 1)
                .limit(tree.getExpandedItemCount())
                .filter(i -> tree.getTreeItem(i).getValue() instanceof Tour)
                .findFirst()
                .ifPresent(selectionModel::select);
        }

        @Override
        public void clearAndSelect(int index) {
            int toSelect = index ;
            int direction = selectionModel.getSelectedIndex() < index ? 1 : -1 ;
            while (toSelect >= 0 && toSelect < tree.getExpandedItemCount() && ! (tree.getTreeItem(toSelect).getValue() instanceof Tour)) {
                toSelect = toSelect + direction  ;
            }
            if (toSelect >= 0 && toSelect < tree.getExpandedItemCount()) {
                selectionModel.clearAndSelect(toSelect);
            }
        }

        @Override
        public void select(int index) {
            int toSelect = index ;
            int direction = selectionModel.getSelectedIndex() < index ? 1 : -1 ;
            while (toSelect >= 0 && toSelect < tree.getExpandedItemCount() && ! (tree.getTreeItem(toSelect).getValue() instanceof Tour)) {
                toSelect = toSelect + direction  ;
            }
            if (toSelect >= 0 && toSelect < tree.getExpandedItemCount()) {
                selectionModel.select(toSelect);
            }
        }

        @Override
        public void select(TreeItem<Object> obj) {
            if (obj.getValue() instanceof Tour) {
                selectionModel.select(obj);
            }
        }

        @Override
        public void clearSelection(int index) {
            selectionModel.clearSelection(index);
        }

        @Override
        public void clearSelection() {
            selectionModel.clearSelection();
        }

        @Override
        public boolean isSelected(int index) {
            return selectionModel.isSelected(index);
        }

        @Override
        public boolean isEmpty() {
            return selectionModel.isEmpty();
        }

        @Override
        public void selectPrevious() {
            int current = selectionModel.getSelectedIndex() ;
            if (current > 0) {
                IntStream.iterate(current - 1, i -> i - 1).limit(current)
                    .filter(i -> tree.getTreeItem(i).getValue() instanceof Tour)
                    .findFirst()
                    .ifPresent(selectionModel::select);
            }
        }

        @Override
        public void selectNext() {
            int current = selectionModel.getSelectedIndex() ;
            if (current < tree.getExpandedItemCount() - 1) {
                IntStream.range(current + 1, tree.getExpandedItemCount())
                    .filter(i -> tree.getTreeItem(i).getValue() instanceof Tour)
                    .findFirst()
                    .ifPresent(selectionModel::select);
            }
        }

    }

    public static class Tour {

        private final String name ;

        public Tour(String name) {
            this.name = name ;
        }

        public String getName() {
            return name ;
        }

        @Override
        public String toString() {
            return getName();
        }

    }

    public static class Delivery {
        private final String name;

        public Delivery(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return getName();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
 类似资料:
  • 我用Spring靴和Spring安全。 我这样添加基于url的安全性 有没有办法只授权get、post、put…在url上担任某些角色?

  • 我正在spring boot中创建一个REST api,目前我有一个映射来获取用户和特定用户的列表。 假设我的用户是这样的: 还有,在发送更新用户的请求时,请求体是否需要正确嵌套? 两者都是有效的还是2号?

  • 我已经为我的应用程序实现了shedlock,对于我们拥有的两台服务器来说,它运行良好,没有任何问题。 我们现在在另一个域上添加了两个新服务器,shedlock也会选择它们。(好吧,这就是它的本意) 我有一份工作,创建pdf文件并将其放在文件夹中。添加的新服务器无权访问这些文件夹。因此,当这两个新服务器选择作业时,我的作业将失败。 有没有可能告诉夏洛克从我的两台服务器中选择任何一台,或者不选择另外两

  • 问题内容: 鉴于以下课程 当我们验证它(例如,使用@Valid)并且如果Website.url不遵守我的自定义@ValidUrl约束时,我们将遇到约束冲突(例如,“ URL不可访问”)。 我想知道如果用户愿意,是否可以忽略该验证。 脚步: 第一次验证表格 引发约束冲突并将其显示给用户 用户选择“我知道,仍然添加”,然后重新提交 第二次验证表单,验证@ValidUrl以外的所有内容 问题答案: 您可

  • 我使用的是React路由器V4,我有此路由器的配置: 是可选的语言参数,它应该与模式匹配,例如、或不匹配。例如,应用程序利用这些路由: 另外,我还有一个额外的组件,在其中我定义了函数的路由: 因此,我希望实现的结果是,只接受允许的语言代码(和空参数),而不接受的代码将被重定向到组件。 可能吗?如何实现这一目标? 非常感谢这个例子

  • 我想问,有没有可能限制我的模板函数,使它只接受我指定的几种类型?这就是如何告诉编译器在我使用cout< 更明确地说,这就是我要做的: