我希望在它自己的线程中有一个 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/