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

标签 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但建议的解决方案对我不起作用。它还使用静态共享字段,我认为这不是一个好的做法。另外,我的情况比较简单,因为我不想随着时间的推移更新数据。

有什么想法吗?

最佳答案

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

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

}

关于java - 如何使用主线程而不是 JavaFX 线程中的图表数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40341989/

相关文章:

c - GTK 的线程问题

linux - 跟踪 pthread 调度

multithreading - 多线程会提高 WCF 服务中方法的性能吗?

JavaFx CSS 错误解析意外 token ':' 在 [15,21]

java - java.sql.Date 如何处理负日期?

java - 数组:对象或变量

java - 使用 Java 读取 DOCX 文件以获取字数统计?

maven - 如何将 Spring Boot 构建插件与 JavaFX 应用程序一起使用

java - 将 bash 脚本的返回代码和状态获取到 Java 文件中

java - 事件派发线程在哪里调用?