JavaFx TreeView css

8
我希望您能创建与下面显示的元素相似并具有相同行为的元素。
这里有一个黑色背景和顶部列表包含4个元素:“biblioteki”,“分析”等。当我们单击其中一个时,列表将展开,此项及其子项会得到浅暗色背景。此外,子列表中的选定项目会获得不同的字体(加粗和白色)。任何时候只能展开一个项目。
因此,我发现这是应用了适当样式的TreeView行为。使用以下代码使其正常工作:
    TreeView<TabMenuElement> treeView = new TreeView<>(treeRoot);
    treeView.setCellFactory(tv -> new TreeCell<TabMenuElement>() {
        @Override
        public void updateItem(TabMenuElement item, boolean empty) {
            super.updateItem(item, empty);
            setDisclosureNode(null);

            if (empty) {
                setText("");
                setGraphic(null);
            } else {
                setText(item.getName()); // appropriate text for item
                if (item.getIv() != null) {
                    setGraphic(item.getIv());
                }
            }
        }
    });
    treeView.setShowRoot(false);
TabMenuElement有一个方法getIV,用于获取ImageView(图标),如果为此元素定义了图标,则可以使用该方法。使用getName方法可以获取要显示的文本。目前看起来像这样:

enter image description here

所以我有以下问题:
  1. 如何仅更改TreeView中选定项的字体?
  2. 如何设置选定子树的背景?
  3. 如何强制只展开一个子树?
  4. 如何将顶级项目的大小设置更大?
2个回答

19

如何在TreeView中仅更改所选项目的字体?

只需在您的CSS文件中定义.tree-cell:selected的字体即可。

.tree-cell:selected {
    -fx-font-weight: bold ;
}

如何在选定的子树上设置背景?

这个有点棘手。您希望任何展开的节点以及其父节点不是根节点的节点具有不同的背景颜色(虽然您没有这样表述,但我认为它在逻辑上相当)。一个展开的节点已经有一个CSS伪类。对于“父节点不是根节点”,您需要定义自己的伪类:

PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub-tree-item");

现在观察单元格的treeItem属性,并在其更改时更新伪类状态:

treeView.setCellFactory(tv -> {
    TreeCell<TabMenuElement> cell = new TreeCell<TabMenuElement>() {
        @Override
        public void updateItem(TabMenuElement item, boolean empty) {
            super.updateItem(item, empty);
            setDisclosureNode(null);

            if (empty) {
                setText("");
                setGraphic(null);
            } else {
                setText(item.getName()); // appropriate text for item
                if (item.getIv() != null) {
                    setGraphic(item.getIv());
                }
            }
        }
    };

    cell.treeItemProperty().addListener((obs, oldTreeItem, newTreeItem) -> {
        cell.pseudoClassStateChanged(subElementPseudoClass,
            newTreeItem != null && newTreeItem.getParent() != cell.getTreeView().getRoot());
    }

    return cell ;
});

现在在你的CSS文件中可以这样写:

.tree-cell:expanded, .tree-cell:sub-tree-item {
    -fx-background-color: ... ;
}
将以下的 `ChangeListener` 添加到每个 `TreeItem` 的扩展属性中,以强制最多只能展开一棵子树:
```html

如何强制只有最多一个子树可以展开

将以下的 ChangeListener 添加到每个 TreeItem 的扩展属性中:

```
ChangeListener<Boolean> expandedListener = (obs, wasExpanded, isNowExpanded) -> {
    if (isNowExpanded) {
        ReadOnlyProperty<?> expandedProperty = (ReadOnlyProperty<?>) obs ;
        Object itemThatWasJustExpanded = expandedProperty.getBean();
        for (TreeItem<TabMenuElement> item : treeView.getRoot().getChildren()) {
            if (item != itemThatWasJustExpanded) {
                item.setExpanded(false);
            }
        }
    }
};

TreeItem<TabMenuElement> biblioteka = new TreeItem<>(...);
biblioteka.expandedProperty().addListener(expandedListener);
TreeItem<TabMenuElement> analiza = new TreeItem<>(...);
analiza.expandedProperty().addListener(expandedListener);
// etc, for all "top-level" items.

如何将顶层项目设置为更大的尺寸?

.tree-cell {
    -fx-padding: 0.75em 0em 0.75em 0em ;
}
.tree-cell:sub-tree-item {
    -fx-padding: 0.25em ;
}

(或更改字体大小或类似的内容。)

以下是一个完整的示例:

import javafx.application.Application;
import javafx.beans.property.ReadOnlyProperty;
import javafx.beans.value.ChangeListener;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class StyledUniqueExpandingTree extends Application {

    @Override
    public void start(Stage primaryStage) {
        TreeView<String> tree = new TreeView<>();
        tree.setShowRoot(false);
        TreeItem<String> root = new TreeItem<>("");
        tree.setRoot(root);

        ChangeListener<Boolean> expandedListener = (obs, wasExpanded, isNowExpanded) -> {
            if (isNowExpanded) {
                ReadOnlyProperty<?> expandedProperty = (ReadOnlyProperty<?>) obs ;
                Object itemThatWasJustExpanded = expandedProperty.getBean();
                for (TreeItem<String> item : tree.getRoot().getChildren()) {
                    if (item != itemThatWasJustExpanded) {
                        item.setExpanded(false);
                    }
                }
            }
        };

        for (int i=1; i<=4; i++) {
            TreeItem<String> item = new TreeItem<>("Top level "+i);
            item.expandedProperty().addListener(expandedListener);
            root.getChildren().add(item);
            for (int j=1; j<=4; j++) {
                TreeItem<String> subItem = new TreeItem<>("Sub item "+i+":"+j);
                item.getChildren().add(subItem);
            }
        }

        PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub-tree-item");

        tree.setCellFactory(tv -> {
            TreeCell<String> cell = new TreeCell<String>() {
                @Override
                public void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    setDisclosureNode(null);

                    if (empty) {
                        setText("");
                        setGraphic(null);
                    } else {
                        setText(item); // appropriate text for item
                    }
                }

            };
            cell.treeItemProperty().addListener((obs, oldTreeItem, newTreeItem) -> {
                cell.pseudoClassStateChanged(subElementPseudoClass,
                        newTreeItem != null && newTreeItem.getParent() != cell.getTreeView().getRoot());
            });
            return cell ;
        });

        BorderPane uiRoot = new BorderPane(tree);
        Scene scene = new Scene(uiRoot, 250, 400);
        scene.getStylesheets().add("styled-unique-expanded-tree.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

使用styled-unique-expanded-tree.css:

.tree-view, .tree-cell {
    -fx-background-color: black ;
    -fx-text-fill: white ;
}
.tree-cell:expanded, .tree-cell:sub-tree-item {
    -fx-background-color: #404040 ;
}
.tree-cell:selected {
    -fx-font-weight: bold ;
}
.tree-cell {
    -fx-padding: 0.75em 0em 0.75em 0em ;
}
.tree-cell:sub-tree-item {
    -fx-padding: 0.25em ;
}

这个工作非常好。非常感谢! 但我还有两个问题:
  1. 我希望单击时展开子树(目前只能双击才能展开)
  2. 我只有顶级元素的图标,但我希望所有级别的标签都对齐到单行(目前次级别向右移位)。 请提供建议。
- Wojtek
我测试了你的示例,发现它引起了奇怪的问题。测试时,我只是逐字复制了你的*.java和*.css文件。在我的情况下,这个问题几乎每次都能看到,但在你的应用程序中,我必须尝试几次才能看到它。以下是重现步骤:
  1. 启动应用程序
  2. 展开最低子树
  3. 垂直增加窗口大小(增加到屏幕高度)
  4. 垂直缩小窗口大小至初始大小
  5. 再次垂直增加窗口大小(增加到屏幕高度)
  6. 现在尝试几次展开3toplevel,然后再展开4toplevel - 结果是轻松的条形显示在树视图下方。
- Wojtek

1
我自己想到了如何在单击树视图时展开的方法:
    treeView.setCellFactory(tv -> new TreeCell<TabMenuElement>() {
        @Override
        public void updateItem(TabMenuElement item, boolean empty) {
            super.updateItem(item, empty);
            setDisclosureNode(null);

            if (empty) {
                setText("");
                setGraphic(null);
            } else {
                setText(item.getName()); // appropriate text for item
                setOnMouseClicked(event -> {
                    if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 1) {
                        TreeItem<TabMenuElement> ti = treeItemProperty().get();
                        ti.expandedProperty().set(true);
                    }
                    event.consume();
                });

                if (item.getIv() != null) {
                    setGraphic(item.getIv());
                } else {

                }
            }
        }
    });

我特别关注setOnMouseClicked部分。

此外,在这种情况下,所有节点具有相同的缩进可以通过设置in来实现。

.tree-cell:sub-tree-item{
     -fx-indent: 22;
}

这是关于我的情况,顶级元素的图标宽度为22。然后我只有一个子级,在那里我设置了相同的缩进。

如果您想在整个树中具有相同的缩进而没有图标,只需将所有.tree-cell的缩进设置为0即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接