Issue
I am working on a Java application where I am using a JavaFX stage with embedded Swing components in it. 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.
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. 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:
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". 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?
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.
I cannot upload the whole project, but the exception is thrown here, at the beginning of the main method:
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! 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:
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. The system property is not being set before the JavaFX thread runs. Which would be the proper way here to set this System property by code in my case?
Thank you very much for your comments!
Solution
From your comment:
this flag is a configuration option of the Build/Run configuration of IntelliJ.
Therein lies your problem. The Build/Run configuration you setup in IntelliJ only has meaning within the 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:
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. 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
. 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
). While I haven't tested it, I assume setting the system property would have no effect after initialization, hence the separate main-class.
Answered By - Slaw
Answer Checked By - Clifford M. (JavaFixing Volunteer)