【问题标题】:Also select parents up to the root when selecting child in TreeTableView在 TreeTableView 中选择子项时,还要选择父项直到根
【发布时间】:2018-04-11 11:40:24
【问题描述】:

我们努力做到以下几点:

当一个节点在 JavaFX TreeTableView 中被选中时,“到根的路径”也应该被选中,即父、祖父等等。在这种情况下选择意味着以不同的背景颜色突出显示,请看图片(在示例中,Level 2 上的节点已被用户单击)。

有没有内置函数如何实现呢? 我们尝试使用 CSS,但没有成功。

【问题讨论】:

    标签: java javafx javafx-8 selection treetableview


    【解决方案1】:

    没有“内置函数”可以做到这一点。在树表视图上使用行工厂来创建观察所选项目的行,并相应地在行上设置伪类。

    例如:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    import javafx.application.Application;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.css.PseudoClass;
    import javafx.scene.Scene;
    import javafx.scene.control.TreeItem;
    import javafx.scene.control.TreeTableColumn;
    import javafx.scene.control.TreeTableRow;
    import javafx.scene.control.TreeTableView;
    import javafx.stage.Stage;
    
    public class TreeTableViewHighlightSelectionPath extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            TreeTableView<Item> table = new TreeTableView<Item>();
    
            PseudoClass ancestorOfSelection = PseudoClass.getPseudoClass("ancestor-of-selection");
    
            table.setRowFactory(ttv -> new TreeTableRow<Item>() {
    
                {
                    table.getSelectionModel().selectedItemProperty().addListener(
                            (obs, oldSelection, newSelection) -> updateStyleClass());
                }
                @Override
                protected void updateItem(Item item, boolean empty) {
                    super.updateItem(item, empty);
                    updateStyleClass();
                }
    
                private void updateStyleClass() {
                    pseudoClassStateChanged(ancestorOfSelection, false);
                    TreeItem<Item> treeItem = table.getSelectionModel().getSelectedItem();
                    if (treeItem != null) {
                        for (TreeItem<Item> parent = treeItem.getParent() ; parent != null ; parent = parent.getParent()) {
                            if (parent == getTreeItem()) {
                                pseudoClassStateChanged(ancestorOfSelection, true);
                                break ;
                            }
                        }
                    }
                }
            });
    
            TreeTableColumn<Item, String> itemCol = new TreeTableColumn<>("Item");
            itemCol.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getValue().getName()));
            table.getColumns().add(itemCol);
    
            TreeTableColumn<Item, Number> valueCol = new TreeTableColumn<>("Value");
            valueCol.setCellValueFactory(cellData -> cellData.getValue().getValue().valueProperty());
            table.getColumns().add(valueCol);
    
            table.setRoot(createRandomTree());
    
            Scene scene = new Scene(table);
            scene.getStylesheets().add("style.css");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private TreeItem<Item> createRandomTree() {
            TreeItem<Item> root = new TreeItem<>(new Item("Item 1", 0));
            Random rng = new Random();
            List<TreeItem<Item>> items = new ArrayList<>();
            items.add(root);
    
            for (int i = 2 ; i <= 20 ; i++) {
                TreeItem<Item> item = new TreeItem<>(new Item("Item "+i, rng.nextInt(1000)));
                items.get(rng.nextInt(items.size())).getChildren().add(item);
                items.add(item);
            }
    
            return root ;
        }
    
        public static class Item {
            private final String name ;
            private final IntegerProperty value = new SimpleIntegerProperty();
    
            public Item(String name, int value) {
                this.name = name ;
                setValue(value);
            }
    
            public String getName() {
                return name ;
            }
    
            public IntegerProperty valueProperty() {
                return value ;
            }
    
            public final int getValue() {
                return valueProperty().get();
            }
    
            public final void setValue(int value) {
                valueProperty().set(value);
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    现在您可以在 CSS 中设置“选定节点的祖先”的样式:

    文件样式.css:

    .tree-table-row-cell:ancestor-of-selection {
        -fx-background: -fx-selection-bar;
        -fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
    }
    

    (您可能需要修改 CSS 以获得更好的控制,例如为非焦点表格中的选定行设置不同的颜色等。有关默认样式的详细信息,请参阅default stylesheet。)

    这是上面测试应用的截图:

    【讨论】:

    • 代码中存在一些问题,比如updateTreeItem是final的,updateStyleClass中的row不存在等等。不过谢谢你的意见,也许我能做到。
    • @MarkusWeninger 是的,很抱歉。我只是直接输入它,而不是在一个完整的例子中尝试它。用有效的代码更新了答案。
    • 您可能忘记更新您的完整代码了吗?在这里不起作用,只选择了一行。我也对你的updateStyleClass 代码有些困惑,为什么你的if 里面有?
    • @MarkusWeninger 我直接从我的 IDE 复制了代码;屏幕截图是从那里运行它拍摄的。您是否包含了样式表,并确保它已实际加载? if 块处理选择更改为“无选择”的情况,这在示例应用程序中不会发生,但更普遍的是(在这种情况下,您会在没有保护的情况下获得 NPE)。
    • @MarkusWeninger 在代码原样的情况下,样式表应该位于类路径的根目录中(即使您将类放在包中)。
    猜你喜欢
    • 2016-02-12
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    相关资源
    最近更新 更多