[英]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.