如何使用主线程而不是JavaFX线程中的图表数据?

时间:2016-10-31 12:14:56

标签: java multithreading javafx charts javafx-8

我想创建一个简单的方法,绘制折线图,​​给出一个包含要显示的点的对象和一些其他图表属性(如图表标题),并将其保存为图像。

这是一个代码示例:

public class MyChartApp {

    public static void main(String[] args) throws IOException {
        ChartData chartData = generateChartData();
        WritableImage image = constructChartImage(chartData);
        save(image, "chart.png");
    }

    public static WritableImage constructChartImage(ChartData data) {
        // code to be written
    }

    private static ChartData generateChartData() {
        ChartData chartData = new ChartData();
        chartData.setValuesX(new double[]{1,2,3,4,5,6,7,8,9});
        chartData.setValuesY(new double[]{9,8,7,6,5,4,3,2,1});
        chartData.setChartTitle("My Chart");
        return chartData;
    }

    public static void save(WritableImage image, String path) throws IOException {
        BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
        ImageIO.write(bImage, "png", new File(path));
    }

    /**
     * JavaFX application used to construct the chart.
     */
    public static class MyChart extends Application {

        @Override
        public void start(Stage stage) throws Exception {

            // Somehow retrieve chartData passed to constructChartImage()
            ChartData chartData = ... 

            //defining the axes
            final NumberAxis xAxis = new NumberAxis();
            final NumberAxis yAxis = new NumberAxis();

            //creating the chart
            final LineChart<Number,Number> lineChart = 
                    new LineChart<>(xAxis,yAxis);

            lineChart.setAnimated(false);
            lineChart.setTitle(chartData.getChartTitle());

            //defining a series
            XYChart.Series series = new XYChart.Series();

            //populating the series with data
            addAll(series, chartData);

            Scene scene  = new Scene(lineChart,800,600);
            lineChart.getData().add(series);


            lineChart.applyCss();
            lineChart.layout();

            stage.setScene(scene);

            WritableImage image = scene.snapshot(null);

            // somehow pass the image object to constructChartImage().
        }

        // utility methods for adding data to the chart //

        private static void addAll(XYChart.Series series, ChartData chartData) {
            double[] valuesX = chartData.getValuesX();
            double[] valuesY = chartData.getValuesY();
            for (int i = 0; i < valuesX.length; i++) {
                add(series, valuesX[i], valuesY[i]);
            }
        }

        private static void add(XYChart.Series series, double x, double y) {
            series.getData().add(new XYChart.Data(x,y));
        }

    }

    public static class ChartData {
        private double[] valuesX;
        private double[] valuesY;
        private String chartTitle;

        public String getChartTitle() {
            return chartTitle;
        }

        public void setChartTitle(String chartTitle) {
            this.chartTitle = chartTitle;
        }

        public double[] getValuesX() {
            return valuesX;
        }

        public void setValuesX(double[] valuesX) {
            this.valuesX = valuesX;
        }

        public double[] getValuesY() {
            return valuesY;
        }

        public void setValuesY(double[] valuesY) {
            this.valuesY = valuesY;
        }
    }

}

虽然这个想法可能看似简单,但实施却并非如此。我不知道如何将图表数据从主应用程序传递到JavaFX应用程序。在JavaFX线程内生成数据(例如,使用generateChartData()方法)不是首选解决方案。

有一个类似的问题here,但建议的解决方案对我没有用。它还使用静态共享字段,我认为这不是一个好习惯。另外,我的情况比较简单,因为我不希望随时更新数据。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

如果目的只是创建一个图表并将其保存到图像文件中,那么为什么不这么做呢

public class MyChartApp extends Application {

    public static void main(String[] args) {
        launch(args);
    }


    @Override
    public void start(Stage stage) throws Exception {

        // other app code...

        MyChart myChart = new MyChart();
        ChartData chartData = myChart.generateChartData();
        WritableImage image = myChart.constructChartImage(chartData);
        myChart.save(image, "chart.png");

        // other app code...
    }

    public static class MyChart {

        public WritableImage constructChartImage(ChartData data) {
            //defining the axes
            final NumberAxis xAxis = new NumberAxis();
            final NumberAxis yAxis = new NumberAxis();

            //creating the chart
            final LineChart<Number,Number> lineChart = 
                    new LineChart<>(xAxis,yAxis);

            lineChart.setAnimated(false);
            lineChart.setTitle(chartData.getChartTitle());

            //defining a series
            XYChart.Series series = new XYChart.Series();

            //populating the series with data
            addAll(series, chartData);

            Scene scene  = new Scene(lineChart,800,600);
            lineChart.getData().add(series);


            lineChart.applyCss();
            lineChart.layout();

            WritableImage image = scene.snapshot(null);

            return image ;
        }

        private ChartData generateChartData() {
            ChartData chartData = new ChartData();
            chartData.setValuesX(new double[]{1,2,3,4,5,6,7,8,9});
            chartData.setValuesY(new double[]{9,8,7,6,5,4,3,2,1});
            chartData.setChartTitle("My Chart");
            return chartData;
        }

        public void save(WritableImage image, String path) throws IOException {
            BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
            ImageIO.write(bImage, "png", new File(path));
        }

        private void addAll(XYChart.Series series, ChartData chartData) {
            double[] valuesX = chartData.getValuesX();
            double[] valuesY = chartData.getValuesX();
            for (int i = 0; i < valuesX.length; i++) {
                add(series, valuesX[i], valuesY[i]);
            }
        }

        private void add(XYChart.Series series, double x, double y) {
            series.getData().add(new XYChart.Data(x,y));
        }

    }

    public static class ChartData {
        private double[] valuesX;
        private double[] valuesY;
        private String chartTitle;

        public String getChartTitle() {
            return chartTitle;
        }

        public void setChartTitle(String chartTitle) {
            this.chartTitle = chartTitle;
        }

        public double[] getValuesX() {
            return valuesX;
        }

        public void setValuesX(double[] valuesX) {
            this.valuesX = valuesX;
        }

        public double[] getValuesY() {
            return valuesY;
        }

        public void setValuesY(double[] valuesY) {
            this.valuesY = valuesY;
        }
    }

}