在 JavaFX 应用程序中使用 Swing 组件时出现异常 - javafx.embed.singleThread 标志不起作用



我正在开发一个Java应用程序,我正在使用一个JavaFX阶段,其中嵌入了Swing组件。我将逐步将这些Swing组件更改为JavaFX组件,但此时,我需要在这些条件下编译和运行应用程序。

为此,我将标志javafx.embed.singleThread设置为"true",以避免在同一应用程序中尝试使用JavaFX和Swing时出现常见错误。通过这样做,当我从IDE运行应用程序时(我使用IntelliJ(,一切都很好,但当我生成工件来创建应用程序JAR时,从命令提示符运行应用程序(我使用Windows(,这是抛出的错误:

Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?
at sample.Main.start(Main.java:41)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
... 1 more Exception running application sample.Main

我一直在阅读关于合并JavaFX和Swing线程的文章,无论在哪里搜索,我都会看到相同的答案,将javafx.embed.singleThread设置为"true"。但就我而言,这是行不通的。也许有一些我没有意识到的东西需要运行这个JAR文件?

这不是我第一次创建JAR文件,但这是我第一次使用同时包含JavaFX和Swing组件的应用程序来创建JAR文件。

我无法上传整个项目,但在这里抛出了异常,在主方法的开头:

if ( !EventQueue.isDispatchThread() ){
throw new IllegalStateException(
"FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?");
}

感谢您提供的任何帮助或相关链接。

更新:当启动application.jar时,我试着像@Slaw在命令提示符下的评论中建议的那样使用这个标志,它很有效!现在我试着不在命令提示符中设置这个标志,而是在代码中设置。在这里,我展示了我的应用程序是如何启动的,以及我是如何从应用程序类扩展的

public class Main extends Application {
SwingMainMenuRoundedPanel buttonsPanel = new SwingMainMenuRoundedPanel();
public Main() throws IOException {
System.setProperty("javafx.embed.singleThread", "true");
}
@Override
public void start(Stage primaryStage) throws Exception {
//System.setProperty("javafx.embed.singleThread", "true");
if ( !EventQueue.isDispatchThread() ){
throw new IllegalStateException(
"FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?");
}
//Add Swing view and interface components to the FX frame
SwingNode viewNode = addSwingNodeToFXFrame(primaryStage);
//----------------------------------------------
//Add FX view and interface components to the FX frame
//----------------------------------------------
// Auxiliary panel with provisional content
Accordion auxiliaryPanelFX = new Accordion();
// Do the lay-out using FX
HBox hbox = new HBox(viewNode, auxiliaryPanelFX);
HBox.setHgrow(viewNode, Priority.ALWAYS);
// Show the window
primaryStage.setScene(new Scene(hbox));
primaryStage.setFullScreen(true);
primaryStage.setTitle("FXApp");
primaryStage.setResizable(false);
primaryStage.show();
}
...
}

正如你现在看到的,我试图在构造函数内部设置System属性标志,也在start((方法的注释行中设置,但它不起作用,我想是因为@Slaw在评论中说的原因。在JavaFX线程运行之前,没有设置系统属性。在我的情况下,通过代码设置这个系统属性的正确方法是什么?

非常感谢您的评论!

来自您的评论:

此标志是IntelliJ的构建/运行配置的配置选项。

这就是你的问题所在。您在IntelliJ中设置的构建/运行配置仅在IDE中具有意义。部署应用程序后,系统属性将不再设置,因此检查失败。一种解决方案是在执行应用程序jar时指定系统属性:

java -Djavafx.embed.singleThread=true -jar <path-to-jar>

但这并不方便。不幸的是,我不认为有一种方法可以在例如清单文件中指定隐含的系统属性。然而,在这种情况下,在启动JavaFX运行时之前,在代码中设置系统属性就足够了。例如:

package sample; // package name taken from your stack trace
import javafx.application.Application;
public class Launcher {
public static void main(String[] args) {
System.setProperty("javafx.embed.singleThread", "true");
// "Main.class" taken from your stack trace
Application.launch(Main.class, args);
}
}

请注意,我创建了一个不扩展Application的主类。这是因为Application的子类中的主方法是在JavaFX运行时初始化后调用的(尽管您仍然需要调用launch(。虽然我还没有测试过它,但我认为设置系统属性在初始化后不会有任何效果,因此会有单独的主类。

最新更新