Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
673 views
in Technique[技术] by (71.8m points)

javafx - TreeView - Certain TreeItems are not allowed to be selected

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

enter image description here

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...