Search code examples
javawindowsjava-11openjfx

JFXPanel setScene freezing with java 11


I want to integrate openjfx into my Java 11 code. Using IntelliJ IDEA 2018.2.6 on Windows 10, I created a test project and tried out below code

import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.TabPane;

public class Java11FXTestApplication {



    public static void main(String[] args) {
        JFXPanel dummyPanel;
        TabPane dummyTabPane;
        Scene dummyScene;
        System.out.println("Creating JFX Panel");
        dummyPanel = new JFXPanel();
        System.out.println("Creating  TabPane");
        dummyTabPane = new TabPane();
        System.out.println("Creating  Scene");
        dummyScene = new Scene(dummyTabPane);
        System.out.println("Setting  Scene");
        dummyPanel.setScene(dummyScene); //Freezing here
        System.out.println("Scene Created");
    }
}

this code is freezing in setScene() method call. I tried debugging it and found that it the code wait indefinitely in secondaryLoop.enter() call in JFXPanel.setScene method. any Idea why?

This code works fine in JDK-8 but not working with java-11.0.1.

I am getting nowhere with this issue, kind of stuck at the Java11 JavaFX problem. Is there something wrong with the code? or any reported issue with javafx for java11


Solution

  • You're setting the Scene on the main thread. From the documentation of JFXPanel (emphasis mine):

    There are some restrictions related to JFXPanel. As a Swing component, it should only be accessed from the event dispatch thread, except the setScene(javafx.scene.Scene) method, which can be called either on the event dispatch thread or on the JavaFX application thread.

    Wrap setScene in a Platform.runLater call (or SwingUtilities.invokeLater).

    Platform.runLater(() -> {
        dummyPanel.setScene(dummyScene);
        System.out.println("Scene Created");
    });
    

    Note that, with your current code, once main returns the JVM will continue to run. Creating a JFXPanel initializes the JavaFX runtime which won't exit until that last window is closed (only when Platform.isImplicitExit is true) or Platform.exit is called. Since your code does neither, the JavaFX runtime will keep running.


    The documentation of JFXPanel also gives an example of how it expects to be used (note nearly everything happens on either the Event Dispatch Thread or JavaFX Application Thread):

    Here is a typical pattern how JFXPanel can used:

     public class Test {
    
         private static void initAndShowGUI() {
             // This method is invoked on Swing thread
             JFrame frame = new JFrame("FX");
             final JFXPanel fxPanel = new JFXPanel();
             frame.add(fxPanel);
             frame.setVisible(true);
    
             Platform.runLater(new Runnable() {
                 @Override
                 public void run() {
                     initFX(fxPanel);
                 }
             });
         }
    
         private static void initFX(JFXPanel fxPanel) {
             // This method is invoked on JavaFX thread
             Scene scene = createScene();
             fxPanel.setScene(scene);
         }
    
         public static void main(String[] args) {
             SwingUtilities.invokeLater(new Runnable() {
                 @Override
                 public void run() {
                     initAndShowGUI();
                 }
             });
         }
     }