TreeView-不允许选择某些TreeItem [英] TreeView - Certain TreeItems are not allowed to be selected

查看:50
本文介绍了TreeView-不允许选择某些TreeItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我现在要选择"Tour" -TreeItems. 但是我不知道怎么办.

我已经用ChangeListener尝试过,但是我只能用它刷新Tab(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);
    }
};

希望您能帮助我. 如果您可以向我展示示例代码,我将非常高兴:)

谢谢

解决方案

在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);
    }
}

I have created a Treeview (javafx), it looks like:

I want now, that only the "Tour"-TreeItems be selectable. But I don't know how.

I have tried it with a ChangeListener, but I can only with it refresh the content of a Tab (TabPane)...the refresh works fine...but the "Delivery"-TreeItems can be selected :(

code:

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);
    }
};

I hope you can help me. If you can show me example code, I will be really happy :)

Thank you

解决方案

Modifying the selection behavior in any controls in JavaFX seems to be a bit of a pain; but the "proper" way to do this is to define a custom selection model for the tree. The easiest way to do this is to wrap the default selection model, and delegate the method calls to it, vetoing selection if the selection index is for an item which shouldn't be selected.

It's a good idea to select something whenever possible when a select method is called, as otherwise keyboard navigation will break.

Here is an implementation:

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);
    }
}

这篇关于TreeView-不允许选择某些TreeItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆