制作一个显示“请等待”JDialog的摇摆线程

问题是这样的:
我正在运行一个swing应用程序,在某个时刻,对话框需要插入用户名和密码并按“确定”。
我希望当用户按“确定”时,swing应用程序按此顺序执行:

  1. 打开“请等待”JDialog
  2. 进行一些操作(最终显示其他一些JDialog或JOptionPane)
  3. 当它完成操作时关闭“请等待”JDialog

这是我在okButtonActionPerformed()中编写的代码:

private void okButtonActionPerformed(java.awt.event.ActionEvent evt) { //This class simply extends a JDialog and contains an image and a jlabel (Please wait) final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false); waitDialog.setVisible(true); ... //Do some operation (eventually show other JDialogs or JOptionPanes) waitDialog.dispose() } 

这段代码显然不起作用,因为当我在同一个线程中调用waitDialog时,它会阻塞所有代码直到我不关闭它。
所以我试着在另一个线程中运行它:

 private void okButtonActionPerformed(java.awt.event.ActionEvent evt) { //This class simply extends a JDialog and contains an image and a jlabel (Please wait) final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { waitDialog.setVisible(true); } }); ... //Do some operation (eventually show other JDialogs or JOptionPanes) waitDialog.dispose() } 

但这也不起作用,因为waitDialog不会立即显示,但只有在操作完成后才能完成工作(当他们显示joption窗格时“你以…登录”)

我还尝试使用invokeAndWait而不是invokeLater,但在这种情况下它会抛出exception:

 Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread 

我能怎么做?

考虑使用SwingWorker进行后台工作,然后在SwingWorker的done()方法或(我的首选项)中添加到SwingWorker的PropertyChangeListener中关闭对话框。

例如,

 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 mySwingWorker = new SwingWorker(){ @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); } } 

笔记:

  • 一个关键的概念是设置所有内容,添加PropertyChangeListener,运行SwingWorker,所有这些都显示模式对话框之前 ,因为一旦显示模式对话框,所有来自调用代码的代码流都被冻结(如您所知) 。
  • 为什么我更喜欢PropertyChangeListener来使用done方法(正如Elias在这里得到的体面答案所示,我已经投票了) – 使用监听器提供了更多的关注点分离,更松散的耦合。 这样,SwingWorker就不必知道正在使用它的GUI代码。
 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 worker = new SwingWorker() { @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(); } }