我正在尝试在JavaFX中创建一个图表,将其拍摄并将其放入PDF中,但在拍摄之前我无法绘制图形数据。显然,这些图片是在绘制数据之前拍摄的。在示例中,我在框架顶部显示图片,在框架底部显示图表。
同步Java和JavaFX的最佳方法是什么?
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);
}
}
}
答案 0 :(得分:1)
我会使用这篇文章中的方法:(JavaFX thread synchronization with Java thread)
new Thread() {
@Override
public void run() {
createPicture();
Platform.runLater(new Runnable() {
@Override
public void run() {
updateChart();
}
});
}
}.start();