英文:
Changing styles of individual lines drawn in JavaFX
问题
我需要更改图形线条的样式。目前,我已经连接了CSS文件,并找到了如何更改所需样式的方法。但这些参数仅适用于所有线条。在.java文件中,我找到了更改这些参数的能力,但我不能同时更改多个参数。我可以更改图的线条类型和点的颜色,但无法更改图例中点的颜色。以下是IDE给出的错误:
Application启动方法中的异常
java.lang.reflect.InvocationTargetException
在java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
在java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在java.base/java.lang.reflect.Method.invoke(Method.java:568)
在javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
在javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
在java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
在java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在java.base/java.lang.reflect.Method.invoke(Method.java:568)
在java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082)
由于:java.lang.RuntimeException: Application启动方法中的异常
在javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
在javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
在java.base/java.lang.Thread.run(Thread.java:833)
由于:java.lang.NullPointerException: 无法调用“javafx.scene.Node.setStyle(String)”因为“javafx.scene.Node.lookup(String)”的返回值为空
在com.example.lab2_int/com.example.lab2_int.HelloApplication.start(HelloApplication.java:290)
在javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
在javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
在javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
在java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
在javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
在javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
在javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
在javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
... 1 more
Exception running application com.example.lab2_int.HelloApplication
我的代码(我只提供必要的部分,如果您需要更多代码,请告诉我):
package com.example.lab3_int;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.Node;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
NumberAxis xAxis0 = new NumberAxis();
NumberAxis yAxis0 = new NumberAxis();
LineChart<Number, Number> lineChart0 = new LineChart<>(xAxis0, yAxis0);
XYChart.Series<Number, Number> exception_g = new XYChart.Series<>();
exception_g.setName("Exceptions");
XYChart.Series<Number, Number> w0_g = new XYChart.Series<>();
w0_g.setName("w0");
XYChart.Series<Number, Number> w1_g = new XYChart.Series<>();
w1_g.setName("w1");
XYChart.Series<Number, Number> w2_g = new XYChart.Series<>();
w2_g.setName("w2");
XYChart.Series<Number, Number> w3_g = new XYChart.Series<>();
w3_g.setName("w3");
exception_g.getData().add(new XYChart.Data<>(0,7));
exception_g.getData().add(new XYChart.Data<>(1,17));
exception_g.getData().add(new XYChart.Data<>(2,-2));
w0_g.getData().add(new XYChart.Data<>(0,11));
w0_g.getData().add(new XYChart.Data<>(1,6));
w0_g.getData().add(new XYChart.Data<>(2,0));
w1_g.getData().add(new XYChart.Data<>(0,-7));
w1_g.getData().add(new XYChart.Data<>(1,9));
w1_g.getData().add(new XYChart.Data<>(2,13));
w2_g.getData().add(new XYChart.Data<>(0,9));
w2_g.getData().add(new XYChart.Data<>(1,2));
w2_g.getData().add(new XYChart.Data<>(2,5));
w3_g.getData().add(new XYChart.Data<>(0,14));
w3_g.getData().add(new XYChart.Data<>(1,-10));
w3_g.getData().add(new XYChart.Data<>(2,5));
lineChart0.getStylesheets().add("/stylesheet.css");
lineChart0.getData().add(exception_g);
lineChart0.getData().add(w0_g);
lineChart0.getData().add(w1_g);
lineChart0.getData().add(w2_g);
lineChart0.getData().add(w3_g);
exception_g.getNode().lookup(".chart-series-line").setStyle("-fx-stroke: black;-fx-stroke-dash-array: 5 5;");
for (XYChart.Data<Number, Number> data : exception_g.getData()) {
Node symbol = data.getNode().lookup(".chart-line-symbol");
symbol.setStyle("-fx-background-color: black, white;");
}
exception_g.getNode().lookup(".chart-legend").setStyle("-fx-background-color: black, white;"); //It is this line that the ide refers to.
GridPane pane = new GridPane();
pane.add(lineChart0, 0, 0);
Scene scene = new Scene(pane, 1920, 1000);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
我决定在CSS文件中将选择器留空:
.chart-series-line:{
}
.chart-line-symbol{
}
.chart-legend{
}
除了这行(`exception_g.getNode().lookup(".chart-legend").setStyle("-fx-background-color: black, white
英文:
I need to change the styles of the graph lines. At the moment, I have connected the CSS file and found how to change styles I need. But these parameters only apply to all lines. In .java, I found the ability to change these parameters, but I can't change multiple parameters at the same time. I can change the line type of the graph and the point color, but I can't change the point color of the legend. Here is the error that the IDE gives me:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.Node.setStyle(String)" because the return value of "javafx.scene.Node.lookup(String)" is null
at com.example.lab2_int/com.example.lab2_int.HelloApplication.start(HelloApplication.java:290)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
... 1 more
Exception running application com.example.lab2_int.HelloApplication
My code(I give only the necessary parts, if you need more code, you can say about it):
package com.example.lab3_int;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.Node;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
NumberAxis xAxis0 = new NumberAxis();
NumberAxis yAxis0 = new NumberAxis();
LineChart<Number, Number> lineChart0 = new LineChart<>(xAxis0, yAxis0);
XYChart.Series<Number, Number> exception_g = new XYChart.Series<>();
exception_g.setName("Exceptions");
XYChart.Series<Number, Number> w0_g = new XYChart.Series<>();
w0_g.setName("w0");
XYChart.Series<Number, Number> w1_g = new XYChart.Series<>();
w1_g.setName("w1");
XYChart.Series<Number, Number> w2_g = new XYChart.Series<>();
w2_g.setName("w2");
XYChart.Series<Number, Number> w3_g = new XYChart.Series<>();
w3_g.setName("w3");
exception_g.getData().add(new XYChart.Data<>(0,7));
exception_g.getData().add(new XYChart.Data<>(1,17));
exception_g.getData().add(new XYChart.Data<>(2,-2));
w0_g.getData().add(new XYChart.Data<>(0,11));
w0_g.getData().add(new XYChart.Data<>(1,6));
w0_g.getData().add(new XYChart.Data<>(2,0));
w1_g.getData().add(new XYChart.Data<>(0,-7));
w1_g.getData().add(new XYChart.Data<>(1,9));
w1_g.getData().add(new XYChart.Data<>(2,13));
w2_g.getData().add(new XYChart.Data<>(0,9));
w2_g.getData().add(new XYChart.Data<>(1,2));
w2_g.getData().add(new XYChart.Data<>(2,5));
w3_g.getData().add(new XYChart.Data<>(0,14));
w3_g.getData().add(new XYChart.Data<>(1,-10));
w3_g.getData().add(new XYChart.Data<>(2,5));
lineChart0.getStylesheets().add("/stylesheet.css");
lineChart0.getData().add(exception_g);
lineChart0.getData().add(w0_g);
lineChart0.getData().add(w1_g);
lineChart0.getData().add(w2_g);
lineChart0.getData().add(w3_g);
exception_g.getNode().lookup(".chart-series-line").setStyle("-fx-stroke: black;-fx-stroke-dash-array: 5 5;");
for (XYChart.Data<Number, Number> data : exception_g.getData()) {
Node symbol = data.getNode().lookup(".chart-line-symbol");
symbol.setStyle("-fx-background-color: black, white;");
}
exception_g.getNode().lookup(".chart-legend").setStyle("-fx-background-color: black, white;"); //It is this line that the ide refers to.
GridPane pane = new GridPane();
pane.add(lineChart0, 0, 0);
Scene scene = new Scene(pane, 1920, 1000);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
I decided to leave the selectors empty in the css file:
.chart-series-line:{
}
.chart-line-symbol{
}
.chart-legend{
}
Without this line( exception_g.getNode().lookup(".chart-legend").setStyle("-fx-background-color: black, white;");
), everything works fine except for the legend, like this:
Perhaps there is some way to change the parameters of the lines directly in css. I tried use selector .chart-series-line:series(0) {...}
in CSS with the name of my axis, and with the line id, but it didn't help. Or else everything is not so simple here and it is necessary to prescribe in .java file all styles. Both solutions to this problem will work.
答案1
得分: 4
生成包含17种不同颜色系列的图表的示例。
示例生成了一个代码中的样式表,然后应用它,这样做的好处是可以在运行时更改生成函数以动态创建任何样式,但如果适合您的目的,也可以使用静态样式表。
在我写完这个之后,我注意到Slaw在评论中提出了一个类似的想法:
只需使用
.chart-series-line.series<n>
来定位线条,使用.chart-line-symbol.series<n>
来定位线条/图例符号。至少在JavaFX 20中,这对任意大的n值都有效。
请注意,默认情况下,线条是路径,所以设置
-fx-stroke
,而符号默认是区域,所以设置-fx-background-color
。
对我来说,找到正确的CSS选择器的见解是通过查看modena.css
中的选择器在LineChart代码中的应用。
多彩图表示例
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class LineChartSample extends Application {
private final String[] CHART_COLOR_NAMES = {
"blue",
"blueviolet",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"cornflowerblue",
"red",
"cyan",
"darkgreen",
"darkmagenta",
"darksalmon",
"darkseagreen",
"deeppink",
"gold",
"grey",
"indigo"
};
private static final String CSS_DATA_URL_TYPE = "data:text/css,";
private static final String LINE_CHART_SERIES_CSS_TEMPLATE =
"""
.series%d.chart-line-symbol { -fx-background-color: %s, white; }
.series%d.chart-series-line { -fx-stroke: %s; }
""";
@Override public void start(Stage stage) {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Number of Month");
final LineChart<Number,Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.getStylesheets().add(
createLineChartStyleSheet()
);
for (int i = 0; i < CHART_COLOR_NAMES.length; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName("Series " + i + " " + CHART_COLOR_NAMES[i]);
genChartData(i * 5, series);
lineChart.getData().add(series);
}
Scene scene = new Scene(lineChart,800,600);
stage.setScene(scene);
stage.show();
}
private static void genChartData(int offset, XYChart.Series<Number, Number> series) {
series.getData().add(new XYChart.Data<>(1, 23 + offset));
series.getData().add(new XYChart.Data<>(2, 14 + offset));
series.getData().add(new XYChart.Data<>(4, 24 + offset));
series.getData().add(new XYChart.Data<>(5, 34 + offset));
series.getData().add(new XYChart.Data<>(6, 36 + offset));
series.getData().add(new XYChart.Data<>(7, 22 + offset));
series.getData().add(new XYChart.Data<>(8, 45 + offset));
series.getData().add(new XYChart.Data<>(9, 43 + offset));
series.getData().add(new XYChart.Data<>(10, 17 + offset));
series.getData().add(new XYChart.Data<>(11, 29 + offset));
series.getData().add(new XYChart.Data<>(12, 25 + offset));
}
private String createLineChartStyleSheet() {
StringBuilder cssBuf = new StringBuilder(CSS_DATA_URL_TYPE);
for (int i = 0; i < CHART_COLOR_NAMES.length; i++) {
cssBuf.append(
LINE_CHART_SERIES_CSS_TEMPLATE
.formatted(
i, CHART_COLOR_NAMES[i],
i, CHART_COLOR_NAMES[i]
)
);
}
return cssBuf.toString();
}
public static void main(String[] args) {
launch(args);
}
}
用于多彩图表的静态CSS示例
如果您想要静态地而不是生成CSS,CSS将如下所示:
.series0.chart-line-symbol { -fx-background-color: blue, white; }
.series0.chart-series-line { -fx-stroke: blue; }
.series1.chart-line-symbol { -fx-background-color: blueviolet, white; }
.series1.chart-series-line { -fx-stroke: blueviolet; }
.series2.chart-line-symbol { -fx-background-color: burlywood, white; }
.series2.chart-series-line { -fx-stroke: burlywood; }
.series3.chart-line-symbol { -fx-background-color: cadetblue, white; }
.series3.chart-series-line { -fx-stroke: cadetblue; }
.series4.chart-line-symbol { -fx-background-color: chartreuse, white; }
.series4.chart-series-line { -fx-stroke: chartreuse; }
.series5.chart-line-symbol { -fx-background-color: chocolate, white; }
.series5.chart-series-line { -fx-stroke: chocolate; }
.series6.chart-line-symbol { -fx-background-color: cornflowerblue, white; }
.series6.chart-series-line { -fx-stroke: cornflowerblue; }
.series7.chart-line-symbol { -fx-background-color: red, white; }
.series7.chart-series-line { -fx-stroke: red; }
.series8.chart-line-symbol { -fx-background-color: cyan, white; }
.series8.chart-series-line { -fx-stroke: cyan; }
.series9.chart-line-symbol { -fx-background-color: darkgreen, white; }
.series9.chart-series-line { -fx-stroke: darkgreen; }
.series10.chart-line-symbol { -fx-background-color: darkmagenta, white; }
.series10.chart-series-line { -fx-stroke: darkmagenta; }
.series11.chart-line-symbol { -fx-background-color: darksalmon, white; }
.series11.chart-series-line { -fx-stroke: darksalmon; }
.series12.chart-line-symbol { -fx-background-color: darkseagreen, white; }
.series12.chart-series-line { -fx-stroke: darkseagreen; }
.series13.chart-line-symbol { -fx-background-color: deeppink, white; }
.series13.chart-series-line { -fx-stroke: deeppink; }
.series14
<details>
<summary>英文:</summary>
Example for generating a chart with 17 different colors for the series.
The example generates a stylesheet in code, then applies that, which has some flexibility because you can change the generation function to create whatever style you want dynamically at runtime. But you could use a static stylesheet instead if that fits your purpose.
After I wrote this, I noted Slaw posted a similar idea in comments:
> Just do `.chart-series-line.series<n>` to target the line and `.chart-line-symbol.series<n>` to target the line/legend symbol.
>
> That works for an arbitrarily large value of n, at least in JavaFX 20.
>
> Note the line is a Path by default, so set `-fx-stroke`, and the symbol is a Region by default, so set `-fx-background-color`.
The insight (for me) on finding the correct CSS selectors to use was by looking at how the selectors from `modena.css` are applied in [the `LineChart` code](https://github.com/openjdk/jfx/blob/de8339d45a9e070598fa0ddc91c36fe74c67a956/modules/javafx.controls/src/main/java/javafx/scene/chart/LineChart.java#L377).
[![linechart][1]][1]
**Example Many Colored Chart**
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class LineChartSample extends Application {
private final String[] CHART_COLOR_NAMES = {
"blue",
"blueviolet",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"cornflowerblue",
"red",
"cyan",
"darkgreen",
"darkmagenta",
"darksalmon",
"darkseagreen",
"deeppink",
"gold",
"grey",
"indigo"
};
private static final String CSS_DATA_URL_TYPE = "data:text/css,";
private static final String LINE_CHART_SERIES_CSS_TEMPLATE =
"""
.series%d.chart-line-symbol { -fx-background-color: %s, white; }
.series%d.chart-series-line { -fx-stroke: %s; }
""";
@Override public void start(Stage stage) {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Number of Month");
final LineChart<Number,Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.getStylesheets().add(
createLineChartStyleSheet()
);
for (int i = 0; i < CHART_COLOR_NAMES.length; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName("Series " + i + " " + CHART_COLOR_NAMES[i]);
genChartData(i * 5, series);
lineChart.getData().add(series);
}
Scene scene = new Scene(lineChart,800,600);
stage.setScene(scene);
stage.show();
}
private static void genChartData(int offset, XYChart.Series<Number, Number> series) {
series.getData().add(new XYChart.Data<>(1, 23 + offset));
series.getData().add(new XYChart.Data<>(2, 14 + offset));
series.getData().add(new XYChart.Data<>(4, 24 + offset));
series.getData().add(new XYChart.Data<>(5, 34 + offset));
series.getData().add(new XYChart.Data<>(6, 36 + offset));
series.getData().add(new XYChart.Data<>(7, 22 + offset));
series.getData().add(new XYChart.Data<>(8, 45 + offset));
series.getData().add(new XYChart.Data<>(9, 43 + offset));
series.getData().add(new XYChart.Data<>(10, 17 + offset));
series.getData().add(new XYChart.Data<>(11, 29 + offset));
series.getData().add(new XYChart.Data<>(12, 25 + offset));
}
private String createLineChartStyleSheet() {
StringBuilder cssBuf = new StringBuilder(CSS_DATA_URL_TYPE);
for (int i = 0; i < CHART_COLOR_NAMES.length; i++) {
cssBuf.append(
LINE_CHART_SERIES_CSS_TEMPLATE
.formatted(
i, CHART_COLOR_NAMES[i],
i, CHART_COLOR_NAMES[i]
)
);
}
return cssBuf.toString();
}
public static void main(String[] args) {
launch(args);
}
}
**Example Static CSS for Many Colored Chart**
If you wanted to do this statically rather than generating the CSS, the CSS would be:
.series0.chart-line-symbol { -fx-background-color: blue, white; }
.series0.chart-series-line { -fx-stroke: blue; }
.series1.chart-line-symbol { -fx-background-color: blueviolet, white; }
.series1.chart-series-line { -fx-stroke: blueviolet; }
.series2.chart-line-symbol { -fx-background-color: burlywood, white; }
.series2.chart-series-line { -fx-stroke: burlywood; }
.series3.chart-line-symbol { -fx-background-color: cadetblue, white; }
.series3.chart-series-line { -fx-stroke: cadetblue; }
.series4.chart-line-symbol { -fx-background-color: chartreuse, white; }
.series4.chart-series-line { -fx-stroke: chartreuse; }
.series5.chart-line-symbol { -fx-background-color: chocolate, white; }
.series5.chart-series-line { -fx-stroke: chocolate; }
.series6.chart-line-symbol { -fx-background-color: cornflowerblue, white; }
.series6.chart-series-line { -fx-stroke: cornflowerblue; }
.series7.chart-line-symbol { -fx-background-color: red, white; }
.series7.chart-series-line { -fx-stroke: red; }
.series8.chart-line-symbol { -fx-background-color: cyan, white; }
.series8.chart-series-line { -fx-stroke: cyan; }
.series9.chart-line-symbol { -fx-background-color: darkgreen, white; }
.series9.chart-series-line { -fx-stroke: darkgreen; }
.series10.chart-line-symbol { -fx-background-color: darkmagenta, white; }
.series10.chart-series-line { -fx-stroke: darkmagenta; }
.series11.chart-line-symbol { -fx-background-color: darksalmon, white; }
.series11.chart-series-line { -fx-stroke: darksalmon; }
.series12.chart-line-symbol { -fx-background-color: darkseagreen, white; }
.series12.chart-series-line { -fx-stroke: darkseagreen; }
.series13.chart-line-symbol { -fx-background-color: deeppink, white; }
.series13.chart-series-line { -fx-stroke: deeppink; }
.series14.chart-line-symbol { -fx-background-color: gold, white; }
.series14.chart-series-line { -fx-stroke: gold; }
.series15.chart-line-symbol { -fx-background-color: grey, white; }
.series15.chart-series-line { -fx-stroke: grey; }
.series16.chart-line-symbol { -fx-background-color: indigo, white; }
.series16.chart-series-line { -fx-stroke: indigo; }
**Example with Interactivity**
If you wish to change the styles at runtime, you can dynamically generate a new style sheet with different values and replace the existing stylesheet on the line chart with your new one. Or, you can define different style classes and change the associated style classes for the series when the series node is interacted with.
The example below demonstrates the changing style class technique.
If you hover over a line in a series, it will be highlighted. If you click on it, the style class to make the line dashed will be added or removed to indicate that the series has been selected. For simplification, the interactivity is only placed on the line, but you could also do the same for the symbols if you wished (to do that you would need to get the symbol nodes from the data and modify the style class). Adding similar interactivity to the legend would be a bit trickier as I am not sure there is enough public API to access it.
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class LineChartHighlightSample extends Application {
private static final String[] CHART_COLOR_NAMES = {
"blue",
"blueviolet",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"cornflowerblue",
"red",
"cyan",
"darkgreen",
"darkmagenta",
"darksalmon",
"darkseagreen",
"deeppink",
"gold",
"grey",
"indigo"
};
private static final String CSS_DATA_URL_TYPE = "data:text/css,";
private static final String LINE_CHART_SERIES_CSS_TEMPLATE =
"""
.series%d.chart-line-symbol { -fx-background-color: %s, white; }
.series%d.chart-series-line { -fx-stroke: %s; }
.series%d.chart-series-line:hover { -fx-effect: dropshadow(gaussian, gold, 10, 0, 0, 0); }
.series%d.chart-series-line.selected { -fx-stroke: %s; -fx-stroke-dash-array: 12 8; }
""";
private static final String SELECTED_SERIES_STYLE_CLASS = "selected";
@Override public void start(Stage stage) {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Number of Month");
final LineChart<Number,Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.getStylesheets().add(
createLineChartStyleSheet()
);
for (int i = 0; i < CHART_COLOR_NAMES.length; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName("Series " + i + " " + CHART_COLOR_NAMES[i]);
genChartData(i * 5, series);
lineChart.getData().add(series);
final int finalIdx = i;
series.getNode().setOnMouseClicked(e -> handleSeriesClicked(lineChart, finalIdx));
}
Scene scene = new Scene(lineChart,800,600);
stage.setScene(scene);
stage.show();
}
private void handleSeriesClicked(LineChart<Number, Number> lineChart, int seriesIdx) {
ObservableList<String> styleClasses =
lineChart
.getData()
.get(seriesIdx)
.getNode()
.getStyleClass();
if (styleClasses.contains(SELECTED_SERIES_STYLE_CLASS)) {
styleClasses.remove(SELECTED_SERIES_STYLE_CLASS);
} else {
styleClasses.add(SELECTED_SERIES_STYLE_CLASS);
}
}
private static void genChartData(int offset, XYChart.Series<Number, Number> series) {
series.getData().add(new XYChart.Data<>(1, 23 + offset));
series.getData().add(new XYChart.Data<>(2, 14 + offset));
series.getData().add(new XYChart.Data<>(4, 24 + offset));
series.getData().add(new XYChart.Data<>(5, 34 + offset));
series.getData().add(new XYChart.Data<>(6, 36 + offset));
series.getData().add(new XYChart.Data<>(7, 22 + offset));
series.getData().add(new XYChart.Data<>(8, 45 + offset));
series.getData().add(new XYChart.Data<>(9, 43 + offset));
series.getData().add(new XYChart.Data<>(10, 17 + offset));
series.getData().add(new XYChart.Data<>(11, 29 + offset));
series.getData().add(new XYChart.Data<>(12, 25 + offset));
}
private String createLineChartStyleSheet() {
StringBuilder cssBuf = new StringBuilder(CSS_DATA_URL_TYPE);
for (int i = 0; i < CHART_COLOR_NAMES.length; i++) {
cssBuf.append(
LINE_CHART_SERIES_CSS_TEMPLATE
.formatted(
i, CHART_COLOR_NAMES[i],
i, CHART_COLOR_NAMES[i],
i, i, CHART_COLOR_NAMES[i]
)
);
}
System.out.println(cssBuf);
return cssBuf.toString();
}
public static void main(String[] args) {
launch(args);
}
}
[1]: https://i.stack.imgur.com/vaczd.png
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论