2012-03-14 49 views
2

我正在編寫一個程序,它有兩個主要階段:確定感興趣區域,然後識別該區域中的對象。我的界面有一個JProgressBar,我希望它能指出它目前正在處理的階段。我注意到,採用簡單的「線性」方法,只顯示第二條消息。所以,遵循https://stackoverflow.com/a/277048,我使用Runnables和SwingUtilities.invokeLater來設置我的進度條字符串。JProgressBar的setString不止一次

private class MarkListener implements ActionListener { 
    public void actionPerformed(ActionEvent ae) { 
     mainFrame.getGlassPane().setCursor(new Cursor(Cursor.WAIT_CURSOR)); 
     recognitionProgress.setStringPainted(true); 
     BlueMarkerTask bmt = new BlueMarkerTask(); 
     bmt.addPropertyChangeListener(PrismRunnable.this); 

     SwingUtilities.invokeLater(new Runnable(){ 
      public void run(){ 
       recognitionProgress.setString("Marking ROI..."); 
      } 
     }); 

     bmt.execute(); 

     RecognitionTask rt = new RecognitionTask(); 
     rt.addPropertyChangeListener(PrismRunnable.this); 

     SwingUtilities.invokeLater(new Runnable(){ 
      public void run(){ 
       recognitionProgress.setString("Segmenting..."); 
      } 
     }); 

     rt.execute(); 
    } 
} 

但是,這不起作用---只有「分段」保留在進度條的文本中。

我已經嘗試使用EventQueue而不是SwingUtilities,但無濟於事。那麼,我該如何解決這個問題呢?

回答

4

你必須明白,沒有停頓的代碼(也應該有)您的電話之間的

recognitionProgress.setString("Marking ROI..."); 

,並

recognitionProgress.setString("Segmenting..."); 

除了第一個位所需的毫秒的代碼來完成併到達第二位代碼,並且這兩個後臺任務可能會同時發生。

選項來解決這個問題包括:

  • 使用兩個JProgressBars,每一個任務,
  • 或從單一的SwingWorker內同時運行的任務,這樣既可以在同一個後臺線程和運行來完成
  • 或在第一個任務的屬性更改偵聽器通知您第一個任務已完成(狀態屬性返回SwingWorker.StateValue.DONE)後運行第二個任務。

例如,

public void actionPerformed(ActionEvent ae) { 
    mainFrame.getGlassPane().setCursor(new Cursor(Cursor.WAIT_CURSOR)); 
    recognitionProgress.setStringPainted(true); 
    BlueMarkerTask bmt = new BlueMarkerTask(); 
    bmt.addPropertyChangeListener(PrismRunnable.this); 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      recognitionProgress.setString("Marking ROI..."); 
     } 
    }); 

    bmt.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (pcEvt.getPropertyName().equals("state")) { 
       if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) { 
       // you'd probably have this in a method. 
       RecognitionTask rt = new RecognitionTask(); 
       rt.addPropertyChangeListener(PrismRunnable.this); 

       SwingUtilities.invokeLater(new Runnable() { 
        public void run() { 
         recognitionProgress.setString("Segmenting..."); 
        } 
       }); 

       rt.execute(); 
       } 
      } 
     } 
    }); 

    bmt.execute(); 
    } 

編輯:
注意,沒有必要排隊事件線程上JProgressBar#setString(...)方法,因爲上面所有的代碼已經在事件線程,EDT。這隻有在當前代碼從EDT中被取消時,或者在其他一些特殊情況下(這不是其中之一)時纔是必需的。

所以,你的代碼會更好,看起來像這樣:

 // ** no need to queue this on the event thread. 
    // ** we're already IN the event thread! 
    recognitionProgress.setString("Marking ROI..."); 

    bmt.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (pcEvt.getPropertyName().equals("state")) { 
       if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) { 
       // you'd probably have this in a method. 
       RecognitionTask rt = new RecognitionTask(); 
       rt.addPropertyChangeListener(PrismRunnable.this); 

       // ** no need to queue this on the event thread. 
       // ** we're already IN the event thread! 
       recognitionProgress.setString("Segmenting..."); 

       rt.execute(); 
       }