-2

Java documentation:

setVisible(true): If the dialog is not already visible, this call will not return until the dialog is hidden by calling setVisible(false) or dispose.

What if I need to change dialog contents from the constructor? e.g.

modalDialog.setVisible(true);
waitForSomeServerToGetSomeData();
modalDialog.add(jPanelWithServerData);
  • Well....don't set it visible until after the other calls? – Kayaman Aug 23 '23 at 07:46
  • Or have the dialog capable of doing the updates to itself – MadProgrammer Aug 23 '23 at 08:43
  • 2
    waitForSomeServerToGetSomeData shouldn’t be called on the Event Dispatching Thread anyway, in this case, you should be making use of SwingWorker – MadProgrammer Aug 23 '23 at 08:45
  • Your question sounds like it may in fact be an [XY Problem](http://mywiki.wooledge.org/XyProblem) where you ask "how do I fix this code" when the real solution is to use a different approach entirely (as noted above). – Hovercraft Full Of Eels Aug 23 '23 at 10:44
  • 1
    As said by others, the operation `waitForSomeServerToGetSomeData()` should not run on the event dispatch thread. If you are in a different thread, `EventQueue.invokeLater(() -> modalDialog.setVisible(true));` is the way to open the modal dialog without blocking the other thread but then, also `EventQueue.invokeLater(() -> modalDialog.add(jPanelWithServerData));` is mandatory to adhere to Swings threading policy. – Holger Aug 23 '23 at 11:05
  • 1
    You don't say what you want to update your `JDialog` with. One application is a progress monitor, which updates a `JProgressBar` while a long-running task runs. Oracle has a helpful tutorial, [Creating a GUI With Swing](https://docs.oracle.com/javase/tutorial/uiswing/index.html). Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the [How to Use Progress Bars](https://docs.oracle.com/javase/tutorial/uiswing/components/progress.html) and [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html) sections. – Gilbert Le Blanc Aug 23 '23 at 11:19
  • For [example](https://stackoverflow.com/questions/25418694/opening-jdialog-with-swingworker/25419069#25419069); [example](https://stackoverflow.com/questions/43536964/java-swingworker-dialog-is-not-shown/43537032#43537032); [example](https://stackoverflow.com/questions/33406447/executing-code-after-swingworker-execute-after-it/33406654#33406654); [example](https://stackoverflow.com/questions/72514952/java-swing-wait-message-will-not-show-up/72515391#72515391); – MadProgrammer Aug 23 '23 at 21:34
  • [example](https://stackoverflow.com/questions/32807495/how-to-return-value-from-swingworker-class-and-use-in-other-class-and-enable-men/32819321#32819321); [example](https://stackoverflow.com/questions/25395201/jframe-only-shows-components-at-first-creation/25395328#25395328); [example](https://stackoverflow.com/questions/14113644/java-global-reusable-loading-dialog/14114663#14114663) – MadProgrammer Aug 23 '23 at 21:39

1 Answers1

0

Don’t retrieve your data in the AWT event dispatch thread.

AWT and Swing are single-threaded. Most GUI frameworks are. What this means is that all painting of windows, and all processing of user input like typing and mouse clicking, is done in a single special thread created by the system. AWT and Swing call it the Event Dispatch Thread.

If you do something to hold that thread up, there will be no repainting and no response to user input during that time.

If waitForSomeServerToGetSomeData() takes ten seconds to complete, your GUI will be frozen for ten seconds. Windows cannot be closed during that time. Buttons cannot be pressed during that time. And if the user happens to switch to a different window that obscures your dialog, then tries to look at your dialog again, your dialog will be a blank gray rectangle during those ten seconds.

The solution is to perform tasks that may take a long time in a different thread:

new Thread(() -> waitForSomeServerToGetSomeData()).start();

But… you want to update the dialog as data is being read. Changes to Swing components must be done in the Event Dispatch Thread and in no other thread. To do that, there is a special method that executes code in the Event Dispatch Thread: EventQueue.invokeLater.

So your code would do something like this:

Runnable dataRetriever = () -> {
    waitForSomeServerToGetSomeData();
    EventQueue.invokeLater(() -> modalDialog.add(jPanelWithServerData));

    waitForSomeMoreData();
    EventQueue.invokeLater(() -> modalDialog.add(panelWithMoreData));
};

new Thread(dataRetriever).start();
modalDialog.setVisible(true);

There are other ways to do this. As Gilbert suggested, you may just want to use a JProgressBar. AS MadProgrammer suggested, you may benefit from using a SwingWorker, which lets you update Swing components by “publishing” the completion of each step of your long-running task.

But if it’s a fairly simple case, a Thread and some invokeLater calls are all you need.

VGR
  • 40,506
  • 4
  • 48
  • 63
  • thanks for great advice. Actually (as I understood later), the simplest solution is just to call dialog.setVisible(true); in a new Thread. Certainly, your answer has lots of advantages, but in my case a new Thread is more suitable. – Tech of the Absence Aug 24 '23 at 16:52
  • As long as that new Thread is the Event Dispatch Thread, that will be okay. But as I said, if your data retrieval takes a long time, it will hang your user interface and users won’t even be able to close any dialogs or windows. – VGR Aug 24 '23 at 17:05