JavaFX无需CSS通过代码设置LineChart折线符号自定义颜色方案咨询
JavaFX LineChart自定义折线及符号颜色方案
需求背景
用户选择自定义颜色后,需要将LineChart对应折线、折线数据点符号、图例符号同步修改为该颜色。
已实现功能
目前折线样式已经通过设置series节点样式实现,代码如下:
String rgb = String.format("%d, %d, %d", (int) (user.getColor().getRed() * 255), (int) (user.getColor().getGreen() * 255), (int) (user.getColor().getBlue() * 255)); series.nodeProperty().get().setStyle("-fx-stroke: rgba(" + rgb + ", 1);");
现存问题
默认的折线符号样式需要通过CSS预设,代码如下:
.default-color0.chart-line-symbol { -fx-background-color: #e9967a, white; } .default-color1.chart-line-symbol { -fx-background-color: #f0e68c, white; } .default-color2.chart-line-symbol { -fx-background-color: #dda0dd, white; }
但用户可选择任意颜色,无法提前预设所有CSS样式。
尝试通过lookup直接修改样式时抛出NullPointerException:
chart.lookup(".default-color0.chart-line-symbol") .setStyle("-fx-background-color: rgba(" + rgb + ", 1), white;");
将上述代码放入Platform.runLater()执行后空指针消失,但仅能修改部分数据点符号颜色,图例符号颜色始终无法修改。
空指针根因:JavaFX场景图节点渲染是异步的,执行lookup时符号节点还未完成渲染,返回null导致空指针。部分符号修改失效的根因:lookup默认仅返回第一个匹配的节点,无法批量修改所有数据点符号,也无法精准匹配对应series的图例符号。
可行解决方案
通过遍历数据点节点、单独匹配图例节点的方式实现全量样式修改,代码如下:
import javafx.application.Platform; import javafx.scene.chart.LineChart; import javafx.scene.chart.XYChart; import javafx.scene.control.Legend; import javafx.scene.Node; // 先给series设置唯一自定义样式类,避免依赖默认的default-colorN类 String seriesUniqueClass = "custom-series-" + series.getName().hashCode(); series.getNode().getStyleClass().add(seriesUniqueClass); // 1. 设置折线颜色 String rgb = String.format("%d, %d, %d", (int) (user.getColor().getRed() * 255), (int) (user.getColor().getGreen() * 255), (int) (user.getColor().getBlue() * 255)); series.getNode().setStyle("-fx-stroke: rgba(" + rgb + ", 1);"); // 2. 遍历所有数据点设置符号颜色 for (XYChart.Data<Number, Number> data : series.getData()) { Platform.runLater(() -> { if (data.getNode() != null) { data.getNode().setStyle("-fx-background-color: rgba(" + rgb + ", 1), white;"); } }); } // 3. 设置图例符号颜色 Platform.runLater(() -> { Node legendSymbol = null; // 优先通过样式类匹配图例符号 legendSymbol = chart.lookup("." + seriesUniqueClass + ".chart-line-symbol"); // 兜底:遍历图例项通过名称匹配 if (legendSymbol == null) { for (Node child : chart.getChildrenUnmodifiable()) { if (child instanceof Legend) { for (Legend.LegendItem item : ((Legend) child).getItems()) { if (item.getText().equals(series.getName())) { legendSymbol = item.getSymbol(); break; } } break; } } } if (legendSymbol != null) { legendSymbol.setStyle("-fx-background-color: rgba(" + rgb + ", 1), white;"); } });
内容的提问来源于stack exchange,提问作者Lukas
相关产品推荐
相关产品推荐

