实例化 JavaFX window
Instantiate JavaFX window
我想在它自己的线程中有一个 JavaFX window 对象,我可以从外部实例化和更新它(通常是每秒 10-20 个)。 window 应该可以查看图像并可以从其他类更新。
主类
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
class代表了一个完整的应用,它的start(...)
方法就是应用启动的方法(你真的应该把start(...)
方法想成相当于传统 Java 应用程序中的 main(...)
方法)。您的问题似乎暗示您认为 Application
class 代表 window; Stage
class代表一个window。但是,据我所知,您的应用程序无论如何只需要一个 window。
当您调用 Application.launch()
(或在 Java 8 中执行 JVM,指定一个 Application
subclass 作为主要 class), FX 工具包创建 Application
class 本身的实例,启动 FX 工具包和 FX 应用程序线程,并调用 Application
实例上的 start(...)
方法,传入 Stage
。你真的不应该自己实例化你的 Application
subclass;如果这样做,您将拥有一个与调用 start(...)
方法的实例不同的实例。
与几乎所有 UI 工具包一样,JavaFX 是单线程的。 "live" 场景图元素上的所有操作都必须在 JavaFX 应用程序线程上执行。您当然可以有后台线程,但如果他们需要更新 UI,他们应该安排在 FX 应用程序线程上进行更新,方法是调用 Platform.runLater(...)
或利用 javafx.concurrent
API。 ("have a JavaFX Window object in its own thread"这个短语对我来说甚至没有意义。线程没有对象,对象存在于堆上。线程只是一个独立的可执行语句序列的抽象。)
因此,如果您希望 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
中的代码分解为单独的 class。
请注意,此答案只是为了演示生成图像的线程与 UI 之间的关系。在现实生活中,您可能需要一些更复杂的代码才能充分执行此操作;您不可能足够快地生成和显示图像,因此您可能需要一个 BlockingQueue<Image>
作为图像缓冲区,一个线程生成图像,一个线程使用它们。
我想在它自己的线程中有一个 JavaFX window 对象,我可以从外部实例化和更新它(通常是每秒 10-20 个)。 window 应该可以查看图像并可以从其他类更新。
主类
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
class代表了一个完整的应用,它的start(...)
方法就是应用启动的方法(你真的应该把start(...)
方法想成相当于传统 Java 应用程序中的 main(...)
方法)。您的问题似乎暗示您认为 Application
class 代表 window; Stage
class代表一个window。但是,据我所知,您的应用程序无论如何只需要一个 window。
当您调用 Application.launch()
(或在 Java 8 中执行 JVM,指定一个 Application
subclass 作为主要 class), FX 工具包创建 Application
class 本身的实例,启动 FX 工具包和 FX 应用程序线程,并调用 Application
实例上的 start(...)
方法,传入 Stage
。你真的不应该自己实例化你的 Application
subclass;如果这样做,您将拥有一个与调用 start(...)
方法的实例不同的实例。
与几乎所有 UI 工具包一样,JavaFX 是单线程的。 "live" 场景图元素上的所有操作都必须在 JavaFX 应用程序线程上执行。您当然可以有后台线程,但如果他们需要更新 UI,他们应该安排在 FX 应用程序线程上进行更新,方法是调用 Platform.runLater(...)
或利用 javafx.concurrent
API。 ("have a JavaFX Window object in its own thread"这个短语对我来说甚至没有意义。线程没有对象,对象存在于堆上。线程只是一个独立的可执行语句序列的抽象。)
因此,如果您希望 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
中的代码分解为单独的 class。
请注意,此答案只是为了演示生成图像的线程与 UI 之间的关系。在现实生活中,您可能需要一些更复杂的代码才能充分执行此操作;您不可能足够快地生成和显示图像,因此您可能需要一个 BlockingQueue<Image>
作为图像缓冲区,一个线程生成图像,一个线程使用它们。