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

Saw*_*yer 8 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;}
}
Run Code Online (Sandbox Code Playgroud)

在start方法中,我实际上需要访问外部数据以构建系列数据,但似乎没有办法从start方法访问外部数据,如果我将数据存储在成员变量中data,则在开始时它为null调用.我实际上并不关心舞台和场景对象,只要图表图像可以渲染,我该如何解决问题呢?我想构建一个可以使用输入数据调用的API,并使用数据绘制图表,然后返回该文件.

public File toLineChart(List<Integer> data) {
...
}
Run Code Online (Sandbox Code Playgroud)

DVa*_*rga 6

您不需要显示StageNode必须附加到a Scene.来自以下文件snapshot:

注意:为了使CSS和布局正常工作,节点必须是场景的一部分(场景可以附加到舞台,但不必是).

修改a的一个限制Scene是,它必须在J avaFX Application Thread上发生,它必须具有必须初始化JavaFX Toolkit的先决条件.

可以通过扩展方法为您执行此操作的Application类来完成初始化launch,或者作为一种解决方法,您可以JFXPanelSwing Event Dispatcher Thread上创建新实例.

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

这是一个可能的例子:

该类提供了一种静态方法,用于将图表绘制到文件中,并返回File或者null创建是否成功.

在此方法中,通过在Swing EDT上创建JavaFX Toolkit来初始化,然后创建图表来完成JavaFX Application Thread.在该方法中使用两个布尔值来存储操作完成并成功.JFXPanel

在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;
    }


}
Run Code Online (Sandbox Code Playgroud)

以及可能的用法

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);
Run Code Online (Sandbox Code Playgroud)

和生成的图片(charttest.png)

在此输入图像描述