java - 实例化 JavaFX 窗口

标签 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(); }

不幸的是,构造函数不接受任何参数,当我尝试在此对象中设置任何值时,什么也没有发生。这是为什么?

最佳答案

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

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

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

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

// 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>充当图像缓冲区,一个线程生成图像,一个线程使用图像。

关于java - 实例化 JavaFX 窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27827779/

相关文章:

javascript - Ruby on Rails 键盘快捷键

java - Netbeans 调试器在没有断点的情况下停止事件

java - 如何在 Torque Clusterr 上查看 .jar 作业的进度

java - 重绘导致组件溢出

java - Android Studio 上的待办事项列表-无法解决方法

java - Netbeans:从 javax.swing 项目声明转到其在 UI 设计选项卡中的显示

java - 如何在没有 native 安装程序的情况下为使用 JavaFX 的应用程序制作可运行的 jar

JavaFX 任务调度和并发

java - 从Firebase Android中的子节点获取父节点

java - JTable 关注整行而不是单元格