Category: JavaFX

Running and controlling JavaFX applications from regular Java

The concept for JavaFX seems to be that your JavaFX Application is the control center for everything. But what if you would like to run an application as a new screen and to be able to run multiple applications and the same application multiple times? This turns out to be difficult. I spent most of a day trying to figure out how to do it and I think that I came up with a reasonable solution and so wanted to share.

Here is the main utility class and method. You create an application that you want to display i.e. x = new MyApplication(). Then you just call JavaFXUtil.runApplication(…). This will make sure JavaFX is initialized, start your application and block until it is ready to be accessed externally.

public class JavaFXUtil {
   public static void runApplication(final Application application)
           throws InterruptedException {
      InitializeFXApplication.initializeJavaFX();
      final WaitObject wait = new WaitObject();
      Platform.runLater(
              new Runnable() {
         @Override
         public void run() {
            try {
               application.init();
               Stage stage = new Stage();
               application.start(stage);
               wait.ready();
            } catch (Exception ex) {
               Logger.getLogger(JavaFXUtil.class.getName()).log(Level.SEVERE, null, ex);
            }
         }
      });
      wait.waitUntilReady();
   }
   private JavaFXUtil() {
   }
}

This utility function depends on two other helper classes:

public class InitializeFXApplication extends Application {
   private static boolean started = false;
   private static WaitObject wait = new WaitObject();
   @Override
   public void start(Stage stage) throws Exception {
      started = true;
      wait.ready();
   }
   public static void initializeJavaFX() throws InterruptedException {
      if (started) {
         return;
      }
      new Thread() {
         @Override
         public void run() {
            Application.launch(InitializeFXApplication.class);
         }
      }.start();
      wait.waitUntilReady();
      Logger.getLogger(InitializeFXApplication.class.getName()).log(Level.INFO, "JavaFX initialized");
   }
}

This is the class that makes sure JavaFX environment is initialized.

public class WaitObject {
   private CountDownLatch latch = new CountDownLatch(1);
   public void ready() {
      latch.countDown();
   }
   public void waitUntilReady() throws InterruptedException {
      latch.await();
   }
   public boolean isReady() {
      return latch.getCount() == 0;
   }
}

This is just a helper object to manage waiting for resources to be available.