Make a swing thread that show a "Please Wait" JDialog Make a swing thread that show a "Please Wait" JDialog multithreading multithreading

Make a swing thread that show a "Please Wait" JDialog


Consider using a SwingWorker to do your background work, and then closing the dialog either in the SwingWorker's done() method or (my preference) in a PropertyChangeListener that is added to the SwingWorker.

e.g.,

import java.awt.BorderLayout;import java.awt.Dialog.ModalityType;import java.awt.Window;import java.awt.event.ActionEvent;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;    import javax.swing.*;public class PleaseWaitEg {   public static void main(String[] args) {      JButton showWaitBtn = new JButton(new ShowWaitAction("Show Wait Dialog"));      JPanel panel = new JPanel();      panel.add(showWaitBtn);      JFrame frame = new JFrame("Frame");      frame.getContentPane().add(panel);      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);      frame.pack();      frame.setLocationRelativeTo(null);      frame.setVisible(true);   }}class ShowWaitAction extends AbstractAction {   protected static final long SLEEP_TIME = 3 * 1000;   public ShowWaitAction(String name) {      super(name);   }   @Override   public void actionPerformed(ActionEvent evt) {      SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>(){         @Override         protected Void doInBackground() throws Exception {            // mimic some long-running process here...            Thread.sleep(SLEEP_TIME);            return null;         }      };      Window win = SwingUtilities.getWindowAncestor((AbstractButton)evt.getSource());      final JDialog dialog = new JDialog(win, "Dialog", ModalityType.APPLICATION_MODAL);      mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {         @Override         public void propertyChange(PropertyChangeEvent evt) {            if (evt.getPropertyName().equals("state")) {               if (evt.getNewValue() == SwingWorker.StateValue.DONE) {                  dialog.dispose();               }            }         }      });      mySwingWorker.execute();      JProgressBar progressBar = new JProgressBar();      progressBar.setIndeterminate(true);      JPanel panel = new JPanel(new BorderLayout());      panel.add(progressBar, BorderLayout.CENTER);      panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);      dialog.add(panel);      dialog.pack();      dialog.setLocationRelativeTo(win);      dialog.setVisible(true);   }}

Notes:

  • A key concept is to set everything up, add the PropertyChangeListener, get the SwingWorker running, all before displaying the modal dialog, because once the modal dialog is shown, all code flow from the calling code is frozen (as you've found out).
  • Why do I prefer the PropertyChangeListener to using the done method (as Elias demonstrates in his decent answer here, which I've up-voted) -- using the listener provides more separation of concerns, looser coupling. This way the SwingWorker has to know nothing of the GUI code that is using it.


public void okButtonActionPerformed(ActionEvent e) {    final JDialog loading = new JDialog(parentComponent);    JPanel p1 = new JPanel(new BorderLayout());    p1.add(new JLabel("Please wait..."), BorderLayout.CENTER);    loading.setUndecorated(true);    loading.getContentPane().add(p1);    loading.pack();    loading.setLocationRelativeTo(parentComponent);    loading.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);    loading.setModal(true);    SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {        @Override        protected String doInBackground() throws InterruptedException             /** Execute some operation */           }        @Override        protected void done() {            loading.dispose();        }    };    worker.execute();    loading.setVisible(true);    try {        worker.get();    } catch (Exception e1) {        e1.printStackTrace();    }}


A variation of the above answer

It's an easy and replicable way to do...

//This code goes inside your button action   DialogWait wait = new DialogWait();SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>() {    @Override    protected Void doInBackground() throws Exception {        //Here you put your long-running process...        wait.close();        return null;    }};mySwingWorker.execute();wait.makeWait("Test", evt);//end//Create this class on your projectclass DialogWait {private JDialog dialog;public void makeWait(String msg, ActionEvent evt) {    Window win = SwingUtilities.getWindowAncestor((AbstractButton) evt.getSource());    dialog = new JDialog(win, msg, Dialog.ModalityType.APPLICATION_MODAL);    JProgressBar progressBar = new JProgressBar();    progressBar.setIndeterminate(true);    JPanel panel = new JPanel(new BorderLayout());    panel.add(progressBar, BorderLayout.CENTER);    panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);    dialog.add(panel);    dialog.pack();    dialog.setLocationRelativeTo(win);       dialog.setVisible(true);   }   public void close() {       dialog.dispose();   }}