Java 在TreeTableView中选择子级时,还要选择父级直至根级

Java 在TreeTableView中选择子级时,还要选择父级直至根级,java,javafx,javafx-8,selection,treetableview,Java,Javafx,Javafx 8,Selection,Treetableview,我们努力实现以下目标: 在JavaFXTreeTableView中选择节点时,还应选择“根路径”,即父节点、祖辈节点等。在本例中,选中表示使用不同背景颜色高亮显示,请参见图像(在本例中,用户已单击Level 2上的节点) 是否有内置功能如何实现? 我们尝试使用CSS,但没有成功。没有“内置函数”来实现这一点。在树表视图上使用行工厂创建观察选定项的行,并相应地在该行上设置伪类 例如: import java.util.ArrayList; import java.util.List; impor

我们努力实现以下目标:

在JavaFX
TreeTableView
中选择节点时,还应选择“根路径”,即父节点、祖辈节点等。在本例中,选中表示使用不同背景颜色高亮显示,请参见图像(在本例中,用户已单击Level 2上的节点)

是否有内置功能如何实现? 我们尝试使用CSS,但没有成功。

没有“内置函数”来实现这一点。在树表视图上使用行工厂创建观察选定项的行,并相应地在该行上设置伪类

例如:

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以获得更好的控制,例如为非焦点表格中的选定行设置不同的颜色等。有关默认样式的详细信息,请参阅。)

以下是上述测试应用程序的屏幕截图:


代码中存在一些问题,例如updateTreeItem是最终的,
updateStyleClass
中的
row
不存在,等等。但谢谢你的意见,也许我能做到。@MarkusWeninger是的,很抱歉。我只是直接输入,而不是在一个完整的例子中尝试。用有效的代码更新了答案。您可能忘记更新完整的代码了吗?在这里不起作用,只选择了一行。我对你的
updateStyleClass
代码也有点困惑,为什么你的
if
在里面呢?@MarkusWeninger我直接从我的IDE复制了代码;屏幕截图是在那里运行的。是否包含样式表,并确保它已实际加载?
if
块处理选择变为“no selection”的情况,这在示例应用程序中不可能发生,但更普遍的情况是(在这种情况下,如果没有保护,您将得到一个NPE)。@MarkusWeninger使用原样的代码,样式表应该位于类路径的根目录中(即使您将类放在包中)。
.tree-table-row-cell:ancestor-of-selection {
    -fx-background: -fx-selection-bar;
    -fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
}