简体   繁体   English

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

[英]Exception when using Swing components in a JavaFX application - javafx.embed.singleThread flag doesn't works

I am working on a Java application where I am using a JavaFX stage with embedded Swing components in it.我正在开发一个 Java 应用程序,我在其中使用带有嵌入式 Swing 组件的 JavaFX 阶段。 Step by step I will be changing these Swing components to JavaFX components, but at this moment, I need to compile and run the application under these conditions.我将逐步将这些 Swing 组件更改为 JavaFX 组件,但此时,我需要在这些条件下编译和运行应用程序。

To do this, I've set the flag javafx.embed.singleThread to "true" to avoid the common error thrown when trying to use JavaFX and Swing in the same application.为此,我将标志javafx.embed.singleThread设置为“true”,以避免在同一应用程序中尝试使用 JavaFX 和 Swing 时引发的常见错误。 By doing this, when I run the application from the IDE (I am using IntelliJ) everything works fine, but when I generate the artifact to create the application JAR, running the application from the command prompt (I am using Windows) this is the error thrown:通过这样做,当我从 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

I've been reading about merging the JavaFX and Swing threads, and everywhere I search I see the same answer, to set the javafx.embed.singleThread to "true".我一直在阅读有关合并 JavaFX 和 Swing 线程的文章,在我搜索的任何地方,我都会看到相同的答案,将javafx.embed.singleThread设置为“true”。 But in my case, this is not working.但就我而言,这是行不通的。 Maybe there is something I didn't realize and is needed to have this JAR file running?也许有什么我没有意识到并且需要运行这个 JAR 文件?

It is not the first time I create JAR files, but it is the first time I do this using an application with both JavaFX and Swing components.这不是我第一次创建 JAR 文件,但这是我第一次使用具有 JavaFX 和 Swing 组件的应用程序来执行此操作。

I cannot upload the whole project, but the exception is thrown here, at the beginning of the main method:我无法上传整个项目,但在 main 方法的开头在这里抛出了异常:

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

Thank for any help or related links provided.感谢您提供的任何帮助或相关链接。

UPDATE : I tried to use the flag as @Slaw suggest in his comment in the command prompt when starting the application .jar and it works!更新:我尝试使用@Slaw 在启动应用程序 .jar 时在命令提示符中的评论中建议的标志,并且它工作正常! Now I am trying not to set this flag in the command prompt, but in the code.现在我试图不在命令提示符中设置此标志,而是在代码中。 Here I show how my application starts and how I extend from Application class:在这里,我展示了我的应用程序如何启动以及如何从 Application 类扩展:

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();

}
...
}

I tried to set the System property flag inside the constructor, as you can see now, and also in the commented line in the start() method, but it doesn't works, I think because of the reason that @Slaw said in his comment.我试图在构造函数中设置 System 属性标志,正如您现在看到的,也在 start() 方法的注释行中设置,但它不起作用,我想是因为@Slaw 在他的评论。 The system property is not being set before the JavaFX thread runs.在 JavaFX 线程运行之前未设置系统属性。 Which would be the proper way here to set this System property by code in my case?在我的情况下,哪种方法是通过代码设置此 System 属性的正确方法?

Thank you very much for your comments!非常感谢您的评论!

From your comment :你的评论

this flag is a configuration option of the Build/Run configuration of IntelliJ.这个标志是 IntelliJ 的 Build/Run 配置的一个配置选项。

Therein lies your problem.这就是你的问题。 The Build/Run configuration you setup in IntelliJ only has meaning within the IDE.您在 IntelliJ 中设置的构建/运行配置仅在 IDE 中有意义。 Once you deploy your application the system property is no longer set, thus your check fails.部署应用程序后,系统属性不再设置,因此您的检查失败。 One solution is to specify the system property when executing your application jar:一种解决方案是在执行应用程序 jar 时指定系统属性:

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

But that's not convenient.但这并不方便。 Unfortunately, I don't believe there is a way to specify implicit system properties in, for instance, the manifest file.不幸的是,我认为没有办法在清单文件中指定隐式系统属性。 In this case, however, it should be sufficient to set the system property in code before launching the JavaFX runtime.但是,在这种情况下,在启动 JavaFX 运行时之前在代码中设置系统属性就足够了。 For example:例如:

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);
  }
}

Notice I created a main-class which does not extend Application .请注意,我创建了一个不扩展Application的主类。 This is because the main-method in a subclass of Application is invoked after the JavaFX runtime has already been initialized (despite the fact you still have to call launch ).这是因为Application子类中的 main-method 在 JavaFX 运行时已经初始化之后被调用(尽管您仍然需要调用launch )。 While I haven't tested it, I assume setting the system property would have no effect after initialization, hence the separate main-class.虽然我还没有测试过,但我认为设置系统属性在初始化后没有任何影响,因此单独的主类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM