2011-10-02 108 views
2

我有一個JFrame,其中CardLayout設置爲其佈局管理器。這裏有兩個JPanel的子類。一個是面板,WordsLoadingPanel,它顯示文本「加載單詞...」,並有一個JProgressBar。另一個必須實際加載單詞。這需要一段時間(對於100個單詞大約10-14秒;這是一個非常有選擇性的算法),所以我想向用戶保證程序仍在工作。我使面板中的加載算法觸發了屬性更改firePropertyChange(String, int, int),並且WordsLoadingPanel正在捕獲更改 - 我知道這是因爲我添加了此事件的偵聽器以執行println,並且它可以工作。但是,當我將println更改爲實際更改JProgressBar的值時,它什麼也不做。我知道我正在改變這個值,因爲如果我在算法啓動之前設置了它的值,它將起作用,它在循環的最後一次迭代中起作用。我猜這是因爲我的算法正在消耗計算能力,不會讓JProgressBar更新。等待Swing在繼續之前完成更新JProgressBar

所以,我的問題是:如何讓我的算法等待Swing(這將是AWT調度線程?)在繼續之前完成更新進度欄?我已經試過:

  • 在循環
  • 在每個循環迭代Thread.sleep(1000L)的每次迭代Thread.yield,在一個try/catch
  • 把一切在循環中SwingUtilities.invokeLater(Runnable)
  • 只把CPU密集型算法在一個SwingUtilities.invokeLater(Runnable)

編輯:爲了進一步支持我的假設的CPU吃算法(聽起來像一個孩子的故事...),當我將JProgressBar設置爲不確定時,只在算法完成後纔開始移動

有沒有人有任何建議?

謝謝!

回答

5

要在後臺執行昂貴的操作,請考慮使用SwingWorker類。該文檔提供了有關如何使用它在獨立線程中執行與用戶界面交互的任務的示例,其中包括JProgressBar中的進度顯示。

如果你無法理解類是如何工作的,考慮:

  • SwingWorker是一個通用類,它有兩個參數:T,並且V
  • doInBackground方法返回T,並在單獨執行線。
  • 由於Swing只能在事件派發線程中操作,因此您不得在doInBackground中操作Swing。
  • process方法將List<V>作爲參數,並在事件調度線程上異步調用。
  • publish方法需要V...參數併發送它們以便在process方法中處理。

結論:

  • T是如果任何計算的結果的類型。
  • V是操縱用戶界面所需要的數據的類型。
  • 你的算法應該在doInBackground完全運行。
  • 用戶界面應該在process方法中操作。
  • 您的算法應該使用publish將數據發送到process方法。
+0

謝謝,我會研究這個! – wchargin

+0

雖然我仍然對「SwingWorker」的工作原理感到困惑。我有一個'SwingWorker ,Void>'帶有'ArrayList doInBackground()'和一個'void process(List chunks)'。什麼是「列表」的說法?何時調用「進程」?我似乎無法理解您從我提供的鏈接(文檔)或維基百科。你能再解釋一下嗎?謝謝! – wchargin

+0

也請記住,這不是一個大的任務,這是一個小百的任務(約1/4秒每個)。 – wchargin

2

好的,我已經解決了。對於任何可能有類似問題的人,我的解決方案是將開始算法的方法從同步執行到異步執行(使用new Thread(Runnable).start)。所以,我的代碼現在是

EventQueue.invokeLater(new Runnable() { 
    @Override 
    public void run() { 
     new Thread(new Runnable() { 
      public void run() { 
       window.keyboardTrainingPanel.initialize();         
      } 
     }).start(); 
    } 
}); 

我希望這可以幫助別人!但是,如果有更好的方法來做到這一點,請隨時通知我。

+2

你不想直接從另一個線程更新你的UI。擺動框架設計爲單線程。你想要什麼用的SwingWorker類生成一個後臺線程你,但可以讓你發佈更新回到UI線程從中你可以安全地更新進度條。在線閱讀ORACLE Java教程,或者在Java中使用多線程編程的任何其他資源。 –

+1

給你正確的解決方案,使用SwingWorker。 –

+1

@HovercraftFullOfEels:是的,我會這樣做;然而,請不要低估我的回答 - 我在Matheus發佈了他的15秒之前發佈了他的回覆(可以通過在「回答...之前」文本上盤旋)來判斷。 – wchargin

相關問題