java - 如何同步Java和JavaFX线程?

标签 java multithreading javafx charts

我正在尝试在JavaFX中创建一个图表,将其拍照并将其放入PDF中,但我无法在拍照之前绘制图形数据。显然这张照片是在绘制数据之前拍摄的。在示例中,我在框架顶部显示图片,在框架底部显示图表。

同步 Java 和 JavaFX 的最佳方式是什么?

enter image description here enter image description here

    import java.awt.Dimension;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.concurrent.CountDownLatch;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javafx.application.Platform;
    import javafx.collections.FXCollections;
    import javafx.embed.swing.JFXPanel;
    import javafx.embed.swing.SwingFXUtils;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.SnapshotParameters;
    import javafx.scene.chart.Axis;
    import javafx.scene.chart.BarChart;
    import javafx.scene.chart.CategoryAxis;
    import javafx.scene.chart.NumberAxis;
    import javafx.scene.chart.XYChart;
    import javafx.scene.image.WritableImage;
    import javafx.scene.layout.StackPane;
    import javax.imageio.ImageIO;

    public class JFXBarChart extends JFXPanel{
        private Scene scene;
        private BarChart<String,Number> chart;
        private String[] seriesColors;
        private byte[] imageBytes = null;

        public JFXBarChart(String[] xAxisCategories) {
            Axis<String> xAxisCategory = new CategoryAxis(FXCollections.observableList(Arrays.asList(xAxisCategories)));
            chart = new BarChart<>(xAxisCategory, new NumberAxis(0.0,10.0,1.0));
            chart.setPrefSize(300, 300);
            setPreferredSize(new Dimension(300, 300));
            chart.setTitle("Chart");
            imageBytes = new byte[0];
            Platform.runLater(()->createScene());
        }

        private void createScene(){
            StackPane stackPane = new StackPane(); 
            StackPane.setAlignment(chart, Pos.TOP_RIGHT);
            stackPane.getChildren().addAll(chart);
            scene = new Scene(stackPane);  
            setScene(scene);
        }    

        public JFXBarChart setAllData(String serieName, final String[] x, final double[] y, CountDownLatch latch) {
            if (y.length == x.length) {
                Platform.runLater(() -> {
                    XYChart.Series<String, Number> currentSeries = new XYChart.Series<>();
                    XYChart.Data<String, Number>[] data = new XYChart.Data[y.length];
                    for (int i = 0; i < y.length; i++) {
                        XYChart.Data<String, Number> nodeData = new XYChart.Data<>(x[i], y[i]);
                        currentSeries.getData().add(nodeData);
                        data[i] = nodeData;
                    }
                    currentSeries.setName(serieName);
                    int newIndex = chart.getData().size();
                    chart.getData().add(newIndex, currentSeries);
                    latch.countDown();
                });
            }
            return this;
        }


        public byte[] getImageByteArray() {
            return imageBytes;
        }

        public void convertChartToImageByteArray(CountDownLatch latch){
            Platform.runLater(() -> {
                try {
                    ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
                    WritableImage wi = new WritableImage((int) chart.getPrefWidth(), (int) chart.getPrefHeight());
                    chart.snapshot(new SnapshotParameters(), wi);
                    ImageIO.write(SwingFXUtils.fromFXImage(wi, null), "png", byteOutputStream);
                    byteOutputStream.flush();
                    imageBytes = byteOutputStream.toByteArray();
                    byteOutputStream.close();
                } catch (IOException ex) {
                    Logger.getLogger(JFXPanelBarChart.class.getName()).log(Level.SEVERE, null, ex);
                }finally{
                    latch.countDown();
                }
            });
        }
    }




import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import java.awt.BorderLayout;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GeneratePDF {

    private JFXBarChart chartLabel;
    private JFXBarChart chartPDF;

    public GeneratePDF() {}

    public JLabel getLabel(){
        byte[] array = new byte[0];
        try {
            array = createChart(chartLabel);
        } catch (InterruptedException ex) {
            Logger.getLogger(GeneratePDF.class.getName()).log(Level.SEVERE, null, ex);
        }
        java.awt.Image img = null;
        try {
            img = ImageIO.read(new ByteArrayInputStream(array));
        } catch (IOException ex) {
            Logger.getLogger(GeneratePDF.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return new JLabel(new ImageIcon(img));
    }

    public void createPdf(String path) throws FileNotFoundException{
        File file  = new File(path);
        OutputStream fos = new FileOutputStream(file);
        PdfWriter writer = new PdfWriter(fos);
        PdfDocument pdf = new PdfDocument(writer);
        PageSize ps = new PageSize(612, 792);
        Document document = new Document(pdf, ps);
        byte[] array = new byte[0];
        try {
            array = createChart(chartPDF);
        } catch (InterruptedException ex) {
            Logger.getLogger(GeneratePDF.class.getName()).log(Level.SEVERE, null, ex);
        }
        Image imgPDF = new Image(ImageDataFactory.create(array));
        document.add(imgPDF);
        document.close();
    }

    private byte[] createChart(JFXBarChart chart) throws InterruptedException {
        CountDownLatch latch1 = new CountDownLatch(1);
        chart = new JFXBarChart(new String[]{"a", "b"})
                .setAllData("Serie1", new String[]{"a", "b"}, new double[]{5.5, 6.5}, latch1);
        latch1.await();
        CountDownLatch latch2 = new CountDownLatch(1);
        chart.convertChartToImageByteArray(latch2);
        latch2.await();
        byte[] array = chart.getImageByteArray();

        return array;
    }

    public JFXBarChart getPanelChart(){
        CountDownLatch latch = new CountDownLatch(1);
        chartPDF = new JFXBarChart(new String[]{"a", "b"})
                .setAllData("Serie1", new String[]{"a", "b"}, new double[]{5.5, 6.5}, latch);
        return chartPDF;
    }

    public static void main(String[] args) {
        GeneratePDF pdfObject = new GeneratePDF();
        JFrame frame = new JFrame();
        frame.setSize(600, 600);

        frame.getContentPane().add(pdfObject.getPanelChart(), BorderLayout.CENTER);
        frame.getContentPane().add(pdfObject.getLabel(), BorderLayout.NORTH);
        frame.setVisible(true);
        try {
            pdfObject.createPdf("E:\\Example.pdf");
        } catch (FileNotFoundException ex) {
            Logger.getLogger(GeneratePDF.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

最佳答案

我会使用这篇文章中的方法:( JavaFX thread synchronization with Java thread )

new Thread() {
    @Override
    public void run() {
        createPicture();
        Platform.runLater(new Runnable() {
          @Override
          public void run() {
            updateChart();
          }
        });
    }
}.start();

关于java - 如何同步Java和JavaFX线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37719155/

相关文章:

java - 从内存读取和从磁盘读取一样吗?

multithreading - x86_64 CPU 是否使用相同的缓存线通过共享内存在两个进程之间进行通信?

C# 任务在using block中的返回方法

java - 除了javafx中的小动画时间线,还有什么解决办法吗?

JavaFX 时钟数转换

java - 如何获取购物车中的多个商品

在服务器端压缩图像的Java代码

java - 添加到集合时防止重复

java - 最后返回 "happen after"吗?

java - 尽快从 PGM 或 TIFF 创建 JavaFX 图像