簡體   English   中英

在 JavaFX 應用程序中使用 Swing 組件時出現異常 - javafx.embed.singleThread 標志不起作用

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

我正在開發一個 Java 應用程序,我在其中使用帶有嵌入式 Swing 組件的 JavaFX 階段。 我將逐步將這些 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 組件的應用程序來執行此操作。

我無法上傳整個項目,但在 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?");
    }

感謝您提供的任何幫助或相關鏈接。

更新:我嘗試使用@Slaw 在啟動應用程序 .jar 時在命令提示符中的評論中建議的標志,並且它工作正常! 現在我試圖不在命令提示符中設置此標志,而是在代碼中。 在這里,我展示了我的應用程序如何啟動以及如何從 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();

}
...
}

我試圖在構造函數中設置 System 屬性標志,正如您現在看到的,也在 start() 方法的注釋行中設置,但它不起作用,我想是因為@Slaw 在他的評論。 在 JavaFX 線程運行之前未設置系統屬性。 在我的情況下,哪種方法是通過代碼設置此 System 屬性的正確方法?

非常感謝您的評論!

你的評論

這個標志是 IntelliJ 的 Build/Run 配置的一個配置選項。

這就是你的問題。 您在 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子類中的 main-method 在 JavaFX 運行時已經初始化之后被調用(盡管您仍然需要調用launch )。 雖然我還沒有測試過,但我認為設置系統屬性在初始化后沒有任何影響,因此單獨的主類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM