I am using an API in a Java library which is called from the event dispatch thread and requires me to return a fully-initialized UI component. It looks like this:
public JDialog createDialog();
But I can only populate the dialog after loading from a database, which can take 10 seconds sometimes. Normally I would do that in a background thread but since this method is called from the EDT and since I have to return the dialog, that won’t work. It’s a third-party library so I can’t change the method, but is there anything I can do to avoid blocking the EDT?
"Initialized" is not necessarily the same thing as "Populated". "Initialized" usually means that the object has been fully constructed, but may not have any data. "Populated" of course means that the data is present and any data-fetching tasks are complete. So it is possible to give your third-party library a fully initialized JDialog without any data at all.
The way I always like to solve this problem is to create a custom JDialog which displays a busy message or a progress bar or the like, and then request the data in another thread. When the data is returned, I replace the busy message with the data(On the EDT!). As to how you should perform your request in a background thread, I recommend using SwingWorkers. I like to use a private
SwingWorkerinside my custom JDialog which handles the request in thedoInBackground()method, and handles the Display-related tasks in thedone()method. Doing it this way will ensure that display-related tasks only occur on the EDT, and database-related tasks only occur OFF the EDT. If you’d like a reasonably good introduction to using SwingWorkers, check out Sun’s tutorial on worker threads. A simple example would be:A few things to remember, though: the
done()method is NOT abstract, so you aren’t required to override it. You should, though. If yourdoInBackground()implementation throws an exception, that exception will be swallowed unlessdone()has been overridden. Also, don’t make changes to your GUI from inside thedoInBackground(), unless you useSwingUtilities.invokeLater(Runnable), asdoInBackground()is executed from a different thread than the EDT and making GUI changes from a background thread is asking for strange and inexplicable bugs.When should this be used? Unlike other programming tasks, the point at which something takes too long to respond is a lot shorter in GUIs–The number I’ve usually seen written down is about 250ms. If your task takes longer than that, it should be in a background thread. In your case, 10 seconds should definitely be in a background thread, but then you already knew that 🙂
EDIT:
Seeing your comment, I see that most of my post is pretty moot. However, you can still use a SwingWorker:
Have your SwingWorker perform the data-retrieval, and in the
done()method, have it construct the JDialog from the data and hand that dialog to your third-party library.