JavaFX TreeItem css 样式用于不同的类字段



我有我自己的树填充的树视图。在类节点中,我有字段"类型",它是节点类型之一。问题是我希望每种类型的 NodeType 都有样式,例如"type1"文本颜色应该是绿色,"type2"文本颜色应该是红色。我是javaFX的新手。我找到了 james-d ( https://github.com/james-d/heterogeneous-tree-example 的解决方案,但在这个例子中,css 样式取决于类名,我该如何为类字段制作它?

树视图视图

我的理解是,您想要一个样式不同的TreeCell,该根据所述TreeCellTreeItem中包含的NodeNodeType而有所不同。全部通过CSS。我说的对吗?

假设我是对的,我能想到两种方法来实现这一点;如果有少量已知的NodeType,这两种方法都效果最好。第一个涉及使用伪类,第二个使用与JavaFXChartAPI相同的策略。


第一个选项

创建针对使用Node类型量身定制的自定义TreeCell(即适当指定通用签名)。在此自定义TreeCell中,您可以根据需要声明任意数量的静态最终字段PseudoClass;每NodeType一个.然后,观察当前TreeCell中显示的任何NodeNodeType,并相应地更新PseudoClass状态。

下面是一个假设NodeType是具有两个常量的enum的示例:HAPPYSAD

public class CustomTreeCell<T extends Node> extends TreeCell<T> {
private static final PseudoClass HAPPY = PseudoClass.getPseudoClass("happy");
private static final PseudoClass SAD = PseudoClass.getPseudoClass("sad");
// this listener will activate/deactivate the appropriate PseudoClass states
private final ChangeListener<NodeType> listener = (obs, oldVal, newVal) -> {
pseudoClassStateChanged(HAPPY, newVal == NodeType.HAPPY);
pseudoClassStateChanged(SAD, newVal == NodeType.SAD);
};
// use a weak listener to avoid a memory leak
private final WeakChangeListener<NodeType> weakListener = /* wrap listener */;
public CustomTreeCell() {
getStyleClass().add("custom-tree-cell");
itemProperty().addListener((obs, oldVal, newVal) -> {
if (oldVal != null) {
oldVal.nodeTypeProperty().removeListener(weakListener);
}
if (newVal != null) {
newVal.nodeTypeProperty().addListener(weakListener);
// need to "observe" the initial NodeType of the new Node item.
// You could call the listener manually to avoid code duplication
pseudoClassStateChanged(HAPPY, newVal.getNodeType() == NodeType.HAPPY);
pseudoClassStateChanged(SAD, newVal.getNodeType() == NodeType.SAD);
} else {
// no item in this cell so deactivate all PseudoClass's
pseudoClassStateChanged(HAPPY, false);
pseudoClassStateChanged(SAD, false);
}
});
}
}

然后在您的 CSS 文件中,您可以使用:

.custom-tree-cell:happy {
/* style when happy */
}
.custom-tree-cell:sad {
/* style when sad */
}

第二种选择

执行 JavaFXChartAPI 在处理多个数据系列时执行的操作。它的作用是根据列表中的序列索引动态更新节点style class(例如.line-chart-series-data-<index><- 可能不完全是这个)。

/*
* Create a custom TreeCell like in the first option but
* without any of the PseudoClass code. This listener should
* be added/removed from the Node item just like weakListener
* is above.
*/
ChangeListener<NodeType> listener = (obs, oldVal, newVal) -> {
// You have to make sure you keep "cell", "indexed-cell", and "tree-cell"
// in order to keep the basic modena styling.
if (newVal == NodeType.HAPPY) {
getStyleClass().setAll("cell", "indexed-cell", "tree-cell", "custom-tree-cell-happy");
} else if (newVal == NodeType.HAPPY) {
getStyleClass().setAll("cell", "indexed-cell", "tree-cell", "custom-tree-cell-sad");
} else {
getStyleClass().setAll("cell", "indexed-cell", "tree-cell"); // revert to regular TreeCell style
}
};

然后在 CSS 中:

.custom-tree-cell-happy {
/* styles */
}
.custom-tree-cell-sad {
/* styles */
}

这两个选项实际上只有在存在一小组已知类型时才可行。当您有 10+NodeTypes 时,它可能会变得无法维护。如果NodeTypes 的数量在运行时是动态的,则几乎是不可能的。

NodeType或一些中间类/数据结构知道文本应该是什么颜色并根据NodeType以编程方式设置颜色可能更容易。

注意:我快速输入了答案中的代码,没有对其进行测试。我的代码中可能存在编译器错误、运行时异常或逻辑错误。


编辑

想到了别的东西。我上面的代码假设NodeType保存在属性中,并且可以在运行时更改。如果每个NodeNodeType都是静态的(不变的),那么代码可以大大简化。无需使用任何侦听器,您可以简单地覆盖javafx.scene.control.Cell中声明的以下方法:

protected void updateItem(Node item, boolean empty)

每次在单元格上设置新项时,都会调用此方法。但是,请阅读文档,因为重写此方法需要开发人员提供某些操作(例如调用超级实现)。

最新更新