实例化JavaFX窗口

时间:2015-01-07 20:08:32

标签: java user-interface javafx

我想在它自己的线程中有一个JavaFX窗口对象,我可以从外部实例化和更新(通常每秒10-20次)。该窗口应该可以查看图像并可以从其他类更新。

主要课程

ImageViewer window = new ImageViewer("Preview");
window.show();
window.updateFrame(image);

ImageViewer类

public class ImageViewer extends Application{

private StackPane pane;
private ImageView imgView;
private Stage primaryStage;

public ImageViewer() {
}

public void start(Stage primaryStage) {
    this.primaryStage = primaryStage;
    pane = new StackPane();
    imgView = new ImageView();
    pane.getChildren().add(imgView);
    Scene scene = new Scene(pane);
    primaryStage.setScene(scene);
    primaryStage.show();
}

public void updateFrame(Image image) {
    imgView = new ImageView(image);
}

public void show() { Application.launch(); }

遗憾的是,构造函数没有采用任何参数,当我尝试在此对象中设置任何值时没有任何反应。这是为什么?

1 个答案:

答案 0 :(得分:2)

Application类表示整个应用程序,其start(...)方法是应用程序启动的方法(您应该将start(...)方法视为main(...)方法的等效方法1}}传统Java应用程序中的方法)。你的问题似乎暗示你认为Application类代表一个窗口; Stage类表示一个窗口。但是,据我所知,您的应用程序无论如何只需要一个窗口。

当你调用Application.launch()时(或者在Java 8中只执行指定Application子类作为主类的JVM),FX工具包会创建一个Application类本身的实例,启动FX工具包和FX应用程序线程,并调用start(...)实例上的Application方法,传入Stage。你真的不应该自己实例化你的Application子类;如果你这样做,你将有一个与start(...)方法被调用的实例不同的实例。

与几乎所有UI工具包一样,JavaFX是单线程的。所有操作都在" live"场景图元素必须在JavaFX应用程序线程上执行。您当然可以拥有后台线程,但如果他们需要更新UI,他们应该通过调用Platform.runLater(...)或利用javafx.concurrent API来安排在FX应用程序线程上进行更新。 (短语"在自己的线程中有一个JavaFX Window对象"对我来说甚至没有意义。线程没有对象,对象存在于堆上。线程只是抽象独立的可执行语句序列。)

因此,如果您希望JavaFX应用程序具有定期更新图像视图中图像的后台线程,您可以执行以下操作:

// imports omitted

public class MyImageUpdatingApp extends Application {

    @Override
    public void start(Stage primaryStage) {
        Label label = new Label("Main application");
        BorderPane root = new BorderPane(label);
        Scene scene = new Scene(root, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        startImageUpdateThread();
    }

    private void startImageUpdateThread() {
        ImageView imageView = new ImageView();
        BorderPane root = new BorderPane(imageView);
        Scene scene = new Scene(root, 600, 400);
        Stage imageViewWindow = new Stage()
        imageViewWindow.setScene(scene);
        imageViewWindow.show();
        final int pause = 50 ;
        Thread t = new Thread( () -> {
            while (moreImagesToGet()) {
                Image image = getNextImage() ;
                Platform.runLater( () -> imageView.setImage(image) );
                try {
                    Thread.sleep(pause);
                } catch (Exception exc) {
                    exc.printStackTrace();
                    break();
                }
            }
        });
        t.setDaemon(true); // this thread won't prevent application exit
        t.setName("Image update thread");
        t.start();
    }

    // ...
}

显然,如果您愿意,可以将startImageUpdateThread中的代码分解为单独的类。

请注意,此答案仅用于演示生成图像的线程与UI之间的关系。在现实生活中,您可能需要一些更复杂的代码才能使其充分发挥作用;您不太可能足够快地生成和显示图像,因此您可能需要BlockingQueue<Image>作为图像缓冲区,其中一个线程生成图像,另一个线程使用它们。