我只想从JavaFX图表API生成图表图像。我不想显示应用程序窗口,也不想启动应用程序(如果没有必要)。
public class LineChartSample extends Application {
private List<Integer> data;
@Override public void start(Stage stage) {
stage.setTitle("Line Chart Sample");
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Month");
final LineChart<String,Number> lineChart =
new LineChart<String,Number>(xAxis,yAxis);
lineChart.setTitle("Stock Monitoring, 2010");
XYChart.Series series = new XYChart.Series();
series.setName("My portfolio");
series.getData().add(new XYChart.Data("Jan", 23));
series.getData().add(new XYChart.Data("Feb", 14));
Scene scene = new Scene(lineChart,800,600);
lineChart.getData().add(series);
WritableImage image = scene.snapshot(null);
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", chartFile);
//stage.setScene(scene);
//stage.show();
}
public static void main(String[] args) {
launch(args);
}
public setData(List<Integer> data) {this.data = data;}
}
在start方法中,我实际上需要访问外部数据以构建系列数据,但是如果我将数据存储在成员变量{{1}中,则似乎无法从start方法访问外部数据调用start时,它为null。我实际上并不关心舞台和场景对象,只要图表图像可以渲染,我该如何解决问题呢?我想构建一个可以使用输入数据调用的API,并使用数据绘制图表,然后返回文件。
data
答案 0 :(得分:6)
您无需显示Stage
,但Node
必须附加到Scene
。来自doc of snapshot
:
注意:为了使CSS和布局正常运行,节点必须 成为场景的一部分(场景可能附加到舞台,但不需要 定)。
修改Scene
的一个限制是它必须发生在J avaFX应用程序线程上,它具有 JavaFX Toolkit 的先决条件必须初始化。
初始化可以通过扩展Application
类launch
方法为您完成的方法来完成,或者作为一种解决方法,您可以在JFXPanel实例> Swing Event Dispatcher Thread 。
如果要扩展Application
并在start
方法中执行某些代码,则确保此代码将在 JavaFX应用程序线程上执行,否则您可以使用从不同线程调用的Platform.runLater(...)
块来确保相同。
以下是一个可能的示例:
该类提供了一种静态方法,用于将图表绘制到文件中,如果创建成功与否,则返回File
或null
。
在此方法中,通过在 Swing EDT 上创建JFXPanel
来初始化 JavaFX Toolkit ,然后创建图表 JavaFX Application Thread < / em>的。在该方法中使用两个布尔值来存储操作已完成并成功。
在completed标志切换为true之前,该方法不会返回。
注意:这个实际上只是一个(工作)示例,可以进行很多改进。
public class JavaFXPlotter {
public static File toLineChart(String title, String seriesName, List<Integer> times, List<Integer> data) {
File chartFile = new File("D:\\charttest.png");
// results: {completed, successful}
Boolean[] results = new Boolean[] { false, false };
SwingUtilities.invokeLater(() -> {
// Initialize FX Toolkit
new JFXPanel();
Platform.runLater(() -> {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setTitle(title);
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName(seriesName);
for (int i = 0; i < times.size(); i++)
series.getData().add(new XYChart.Data<Number, Number>(times.get(i), data.get(i)));
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
WritableImage image = scene.snapshot(null);
try {
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", chartFile);
results[1] = true;
} catch (Exception e) {
results[0] = true;
} finally {
results[0] = true;
}
});
});
while (!results[0]) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return (results[1]) ? chartFile : null;
}
}
以及可能的用法
List<Integer> times = Arrays.asList(new Integer[] { 0, 1, 2, 3, 4, 5 });
List<Integer> data = Arrays.asList(new Integer[] { 4, 1, 5, 3, 0, 7 });
File lineChart = JavaFXPlotter.toLineChart("Sample", "Some sample data", times, data);
if (lineChart != null)
System.out.println("Image generation is done! Path: " + lineChart.getAbsolutePath());
else
System.out.println("File creation failed!");
System.exit(0);
和生成的图片(charttest.png)
答案 1 :(得分:1)
从命令行:
INFO STDOUT - http-10.8.184.11-8080-14, WRITE: TLSv1 Handshake, length = 81
2016-10-21 07:26:37,499 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14, WRITE: SSLv2 client hello message, length = 110
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14, READ: Unknown-3.3 Alert, length = 2
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - , RECV TLSv1 ALERT:
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - fatal,
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - handshake_failure
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14, called closeSocket()
2016-10-21 07:26:37,501 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
2016-10-21 07:26:37,502 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14, called close()
2016-10-21 07:26:37,502 [http-10.8.184.11-8080-14] INFO STDOUT - http-10.8.184.11-8080-14, called closeInternal(true)
2016-10-21 07:26:37,502 [http-10.8.184.11-8080-14] ERROR STDERR - javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
2016-10-21 07:26:37,502 [http-10.8.184.11-8080-14] ERROR STDERR - at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
2016-10-21 07:26:37,502 [http-10.8.184.11-8080-14] ERROR STDERR - at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
下一步:清理并构建您的程序。 然后:在你的dist文件夹中找到你的jar文件 之后:将命令提示符导航到jar所在的dist文件夹中。 然后运行:java -jar PieChartSample.jar Banana 14 Orange 20 Grape 15
结果:与PieChartSample.jar文件位于同一文件夹中