使用JavaFX图表API绘制图表图像

时间:2016-09-28 06:23:57

标签: java javafx javafx-2 javafx-8

我只想从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

2 个答案:

答案 0 :(得分:6)

您无需显示Stage,但Node必须附加到Scene。来自doc of snapshot

  

注意:为了使CSS和布局正常运行,节点必须   成为场景的一部分(场景可能附加到舞台,但不需要   定)。

修改Scene的一个限制是它必须发生在J avaFX应用程序线程上,它具有 JavaFX Toolkit 的先决条件必须初始化。

初始化可以通过扩展Applicationlaunch方法为您完成的方法来完成,或者作为一种解决方法,您可以在JFXPanel实例> Swing Event Dispatcher Thread 。

如果要扩展Application并在start方法中执行某些代码,则确保此代码将在 JavaFX应用程序线程上执行,否则您可以使用从不同线程调用的Platform.runLater(...)块来确保相同。

以下是一个可能的示例:

该类提供了一种静态方法,用于将图表绘制到文件中,如果创建成功与否,则返回Filenull

在此方法中,通过在 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)

enter image description here

答案 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

enter image description here

结果:与PieChartSample.jar文件位于同一文件夹中

enter image description here