使用快照方法创建WritableImage对象,而不在JavaFX中扩展javafx.application.Application

时间:2017-01-17 17:21:36

标签: javafx

如何使用keyTypeWritableImage上的快照方法创建javafx.scene.shape.Rectangle对象而不延伸javafx.scene.chart.BarChart

获得以下异常

javafx.application.Application
Exception in thread "main" java.lang.IllegalStateException: Not on FX application thread; currentThread = main
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:238)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:400)
    at javafx.scene.Node.snapshot(Node.java:1698)

没有扩展public class Example1 { public static void main(String[] args) throws Exception { new Example1 ().manipulatePdf(); } protected void manipulatePdf() throws Exception { image1(); image2(); } private WritableImage image1() { Rectangle rectangle = new Rectangle(); rectangle.setX(50); rectangle.setY(50); rectangle.setWidth(300); rectangle.setHeight(20); rectangle.setStroke(Color.WHITE); LinearGradient linearGrad = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, new Stop(0f, Color.rgb(255, 0, 0, 1)), new Stop(0.25f, Color.rgb(255, 255, 0, 1)), new Stop(0.5f, Color.rgb( 255, 255, 255, 1)), new Stop(0.75f, Color.rgb(124, 252, 0, 1)), new Stop(1.0f, Color.rgb(0, 255, 0, 1))); rectangle.setFill(linearGrad); WritableImage img = new WritableImage((int) rectangle.getWidth(), (int) rectangle.getHeight()); rectangle.snapshot(null, img); return img; } private WritableImage image2 () { BarChart chart = new BarChart(new CategoryAxis(), new NumberAxis()); Random rng = new Random(); Series series = new Series(); series.setName("Data"); for (int i = 1; i <= 10; i++) { series.getData().add(new Data("Group " + i, rng.nextDouble())); } chart.getData().add(series); WritableImage img = chart.snapshot(null, null); return img; } } ,计划使用javafx

创建图像对象

2 个答案:

答案 0 :(得分:1)

我不知道您的代码,但根据您获得的异常,您的代码在错误的线程中运行。您的代码需要在JavaFX应用程序线程中运行:

Platform.runLater(new Runnable() {
        @Override
        public void run() {
            // your code goes here
        }
    });

答案 1 :(得分:0)

documentation for Node.snapshot(...)中所述:

  

投掷

     

IllegalStateException - 如果在JavaFX应用程序线程以外的线程上调用此方法。

因此,您只能在FX应用程序线程上执行此方法。这意味着您必须从已在FX应用程序线程上执行的方法调用snapshot(),或者您必须将调用包含在snapshot()中的Platform.runLater(...)。当然,后一种选择只有在FX应用程序线程运行时才有效,这意味着必须初始化FX工具包。

因此,你无法在“无头”中做到这一点。你试图做的模式。您需要完整实现JavaFX工具包,并对其进行初始化并仍在运行。

启动FX Application工具包的方法是从Application.launch(...)的子类调用Application,或者指定Application的具体子类。

请注意,如何拨打Application.launch()

存在限制

首先,它将一直阻止,直到FX应用程序退出,因此您需要在后台线程中调用它。这将涉及在后台线程上调用launch(),然后阻塞,直到FX Toolkit初始化完成后再继续。

其次,您只能在JVM的生命周期内调用launch()一次。这意味着如果您的应用程序需要FX工具包,您可能应该在应用程序启动时启动它并在应用程序关闭时退出它。

最后,还要注意,根据上面链接的snapshot(...)文档,

  

为了使CSS和布局正常运行,节点必须是场景的一部分(场景可以附加到舞台,但不一定是)。

解决FX工具包启动问题&#34;手动&#34;是在回复this question时发布的,我将在此背景下重复。

请注意,执行下面的应用程序会将几个.png文件写入您的驱动器(在工作目录中,即从您运行此文件的任何位置)。您可以使用它们来验证它是否正常工作。

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;

import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class StandaloneSnapshot {
    public static void main(String[] args) throws Exception {

        // start FX toolkit in background thread:
        new Thread(() -> Application.launch(FXStarter.class)).start();

        // block until FX toolkit initialization is complete:
        FXStarter.awaitFXToolkit();

        new  StandaloneSnapshot().manipulatePdf();

        // exit JavaFX toolkit:
        Platform.exit();
    }

    public static class FXStarter extends Application {

        private static final CountDownLatch latch = new CountDownLatch(1);

        public static void awaitFXToolkit() throws InterruptedException {
           latch.await();
        }

        @Override
        public void init() {
            latch.countDown();
        }

        @Override
        public void start(Stage primaryStage) {
            // no-op
        }
    }

    protected void manipulatePdf() throws Exception {

        WritableImage img1 = image1(); 
        // do something with the image:
        BufferedImage bImg1 = SwingFXUtils.fromFXImage(img1, new BufferedImage((int)img1.getWidth(), (int) img1.getHeight(), BufferedImage.TYPE_INT_ARGB));
        ImageIO.write(bImg1, "png", new File("rect.png"));

        WritableImage img2 = image2();
        // do something with the image:
        BufferedImage bImg2 = SwingFXUtils.fromFXImage(img2, new BufferedImage((int)img2.getWidth(), (int) img2.getHeight(), BufferedImage.TYPE_INT_ARGB));
        ImageIO.write(bImg2, "png", new File("chart.png"));
    }

    private WritableImage image1() throws Exception {

        Rectangle rectangle = new Rectangle();
        rectangle.setX(50);
        rectangle.setY(50);
        rectangle.setWidth(300);
        rectangle.setHeight(20);

        rectangle.setStroke(Color.WHITE);

        LinearGradient linearGrad = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE,           
                new Stop(0f, Color.rgb(255, 0, 0, 1)), new Stop(0.25f,
                        Color.rgb(255, 255, 0, 1)), new Stop(0.5f, Color.rgb(
                        255, 255, 255, 1)), new Stop(0.75f, Color.rgb(124, 252,
                        0, 1)), new Stop(1.0f, Color.rgb(0, 255, 0, 1)));
        rectangle.setFill(linearGrad);

        FutureTask<WritableImage> task = new FutureTask<>(() -> {
            new Scene(new Pane(rectangle));
            WritableImage img = new WritableImage((int) rectangle.getWidth(),
                (int) rectangle.getHeight());
            rectangle.snapshot(null, img);
            return img;
        });

        Platform.runLater(task);

        // wait for FX Application Thread to return image, and return the result:
        return task.get();

    }

    private WritableImage image2 () throws Exception {

        BarChart<String, Number> chart = new BarChart<>(new CategoryAxis(), new NumberAxis());
        Random rng = new Random();
        Series<String, Number> series = new Series<>();
        series.setName("Data");
        for (int i = 1; i <= 10; i++) {
            series.getData().add(new Data<>("Group " + i, rng.nextDouble()));
        }
        chart.getData().add(series);

        FutureTask<WritableImage> task = new FutureTask<>(() -> {
            new Scene(chart);
            WritableImage img = chart.snapshot(null, null);
            return img;
        });

        Platform.runLater(task);
        return task.get();
    }
}

生成的图像是

enter image description here

enter image description here