我有简单的javafx HelloWord应用程序,但是当我尝试使用Platform.runLater正确启动时,我会收到java.lang.RuntimeException。类似地,当我尝试使用lambda表达式时,我的框架不会显示出来。程序打印'开始',但挂起显示框架。
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainFrame extends Application {
public static void main(String[] args) {
Platform.runLater(new Runnable() {
@Override
public void run() {
MainFrame.launch(args);
}
});
Platform.runLater(() -> {
System.out.println("starting");
launch(args);
System.out.println("started");
});
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction((e)->System.out.println("Hello World!"));
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
这是应用程序产生的整个输出:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException:
Error: class MainFrame$1 is not a subclass of javafx.application.Application
at javafx.application.Application.launch(Unknown Source)
at MainFrame$1.run(MainFrame.java:15)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
at java.lang.Thread.run(Unknown Source)
starting
有人可以向我解释为什么我会收到异常以及为什么lambda表达式会挂起应用程序吗?
答案 0 :(得分:1)
Application.launch(args)
相当于Application.launch(TheClass.class, args)
,其中TheClass
是方法调用的直接包含类。 TheClass
必须是Application
的子类,否则会引发IllegalArgumentException
。第一个代码块中的直接封闭类是匿名内部Runnable
子类,它本身不是Application
的子类,因此您获得IllegalArgumentException
。
您认为启动JavaFX应用程序的正确方法是从FX应用程序线程调用launch()
是不正确的。事实上,FX应用程序线程在FX工具包启动之前不会运行,并且在调用launch()
之前不会发生。因此,您的第二个代码块无法执行任何操作:没有FX Application Thread可以执行launch()
。此外,launch()
方法会阻止应用程序退出(再次参见documentation);因此,即使FX应用程序线程正在运行(*),您也只是将其锁定,因为它将被阻止,等待它自己的退出。
"适当"启动JavaFX应用程序的方法只是从主线程(或任何其他线程,而不是JavaFX应用程序线程)调用launch()
:
public class MainFrame extends Application {
public static void main(String[] args) {
System.out.println("Calling launch from main thread: "+Thread.currentThread());
launch(args);
}
@Override
public void start(Stage primaryStage) {
System.out.println("start() invoked on thread: "+Thread.currentThread());
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction((e)->System.out.println("Hello World!"));
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
在此处调用launch()
将启动FX工具包,启动FX应用程序线程并创建MainFrame
的实例。然后,在FX应用程序线程上,它将创建一个Stage
并将其传递给MainFrame
实例的start()
方法。
(*)我认为您拥有代码的方式,第一次尝试调用launch()
失败将实际启动FX Toolkit,因此第二次尝试会在FX应用程序线程上调用launch()
,导致死锁,如上所述。