Steven Spungin
Steven Spungin

Reputation: 29101

Blocking in JavaFX while waiting for a Swing dialog result

Background

I have a Swing application. I run JavaFx embedded inside the swing application. I run a web browser (webview) inside the JavaFx application. I add a handler to receive the web browser's confirm function. This handler is invoked in the JavaFx event thread. The handler is synchronous and returns a boolean back to the webview.

Problem

To open a Swing dialog to the user, I need to run on the Swing event thread, but only return from the JavaFx callback after the dialog is responded to.

Here is an example of my callback

engine.setConfirmHandler(()->{
   // in JavaFX context
   CountdownLatch latch = new CountdownLatch(1);

   SwingUtilities.invokeLater(()->{
      // in Swing context
      showModalDialog();
      latch.countDown();
   });

   // Wait for latch
   // HOW DO I BLOCK HERE AND STILL PROCESS EVENTS IN JAVAFX/SWING?
   return result;
});

Question

How can I delay returning from the callback, until the dialog closes, while not blocking UI events in either the JavaFX or Swing contexts?

Upvotes: 1

Views: 501

Answers (1)

Steven Spungin
Steven Spungin

Reputation: 29101

JavaFX has a way of blocking while still processing events.

Java 8

Toolkit.getToolkit().enterNestedEventLoop(key)

Java 9

Platform.enterNestedEventLoop(key)

Another thread can then exitNestedEventLoop to unblock, and as a bonus, can also return a value.

Java 8

Toolkit.getToolkit().exitNestedEventLoop(key, result)

Java 9

Platform.exitNestedEventLoop(key, result)

However, when calling exitNestedEventLoop from Swing, you must switch back to the JavaFX context.

So here's the working example (Java 8).

engine.setConfirmHandler(()->{
   // in JavaFX context

   SwingUtilities.invokeLater(()->{
      // in Swing context
      boolean result = showModalDialog();
      Platform.runLater(()->{
          // back to JavaFX context
          Toolkit.getToolkit().exitNestedEventLoop(key, result)
      })
   });

   // Wait for result
   boolean result = Toolkit.getToolkit().enterNestedEventLoop(this)
   // still in JavaFX context
   return result;
});

Upvotes: 2

Related Questions