2013-11-28 70 views
10

問題是這樣的:
我有一個swing應用程序正在運行,在某個時候對話框需要插入用戶名和密碼並按「ok」。
我想,當用戶按下「OK」 Swing應用程序確實順序:製作顯示「Please Wait」的擺動線程JDialog

  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 in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread 

我怎樣才能做?

回答

28

考慮使用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<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); 
    } 
} 

注:

  • 的一個關鍵概念是設置好一切,添加的PropertyChangeListener,得到的SwingWorker運行時,所有顯示模態對話框,因爲一旦顯示模式對話框,來自調用代碼的所有代碼流都會被凍結(就像您發現的那樣)。
  • 爲什麼我更喜歡PropertyChangeListener使用done方法(正如Elias在他的正確答案中所表明的,我已經投票決定) - 使用偵聽器可以提供更多關注點分離,更鬆散的耦合。這樣SwingWorker就不知道正在使用它的GUI代碼。
+0

它似乎工作,謝謝(也感謝@Elias):)。 但現在還有一個小問題。當關閉主應用程序(使用dispose())時,SwingWorker線程繼續運行。我是否明確地關閉它?它是否在達到doInBackground的返回聲明時終止? – user2572526

+0

@ user2572526:是的,它會在完成時自動關閉。你怎麼知道它仍在運行? –

+0

我解決了,這不是SwingWorker的問題,它是JDialog初始化的錯誤。 (我肯定它仍然由Netbeans分析器運行)。 非常感謝您的幫助。 – user2572526

10
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(); 
    } 
} 
相關問題