As a follow-up to the question "JavaFX FileChooser in swing", which I have answered, I wonder if there's any possibility to simulate modal blocking call in Swing in a more elegant way. Here's the relevant code:
// a trick to emulate modality:
final JDialog modalBlocker = new JDialog();
modalBlocker.setModal(true);
modalBlocker.setUndecorated(true);
modalBlocker.setOpacity(0.0f);
final CountDownLatch modalityLatch = new CountDownLatch(1);
final FutureTask<T> task = new FutureTask<T>(() -> {
// <-- some code checking whether the task is cancelled
// and notifying that it is started
try {
return callable.call();
} finally {
// Wait until the Swing thread is blocked in setVisible():
modalityLatch.await();
// and unblock it:
SwingUtilities.invokeLater(()
-> modalBlocker.setVisible(false));
}
});
// run the task in the JavaFX thread:
Platform.runLater(task);
// <-- some code waiting until the task is started,
// canceling it if it's not
// A trick to notify the task AFTER we have been blocked
// in setVisible():
SwingUtilities.invokeLater(() -> {
// notify that we are ready to get the result:
modalityLatch.countDown();
});
modalBlocker.setVisible(true); // blocks
modalBlocker.dispose(); // release resources
try {
return task.get();
} catch (ExecutionException ex) {
// exception handling
}
The idea here is to keep Swing updating, repainting, moving progress bars and doing other visual tasks while blocking the user input, until the blocking call returns. If I did a simple return task.get()
without all this modality mess, then Swing would freeze while the task is working, which is not catastrophic, but still undesirable.
The whole thing seems to be working perfectly, at least under Windows 7, but "seems to be working perfectly" is not exactly in line with "Write once, run everywhere", is it?
I have tried to look in to JDialog/Dialog source code to figure out how modality blocks without totally freezing the GUI, but alas the code is very complicated, and worse, uses too many private features that would prevent me from doing it in my code even if I figured out how it's working.
The question is: maybe there's a more elegant way to do it that I have missed? I just need to perform a blocking call that keeps the GUI updating, but blocks all user input until the call returns.