Make a swing thread that show a “Please Wait” JDialog

前端 未结 3 1083
不思量自难忘°
不思量自难忘° 2020-12-09 19:10

The problem is this:
I\'ve a swing application running, at a certain point a dialog requires to insert username and password and to press \"ok\".
I would like tha

相关标签:
3条回答
  • 2020-12-09 19:35

    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 project
    class 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();
       }
    }
    
    0 讨论(0)
  • 2020-12-09 19:44
    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-09 19:46

    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.
    0 讨论(0)
提交回复
热议问题