我想在它自己的线程中有一个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(); }
遗憾的是,构造函数没有采用任何参数,当我尝试在此对象中设置任何值时没有任何反应。这是为什么?
答案 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>
作为图像缓冲区,其中一个线程生成图像,另一个线程使用它们。