2012-03-14 1 views
2

Я пишу программу, которая имеет две основные фазы: определение области интереса, а затем распознавание объектов в этом регионе. В моем интерфейсе есть один JProgressBar, и я хочу, чтобы он указывал, на какой стадии он работает. Я заметил, что при простом «линейном» подходе отображается только второе сообщение. Итак, после https://stackoverflow.com/a/277048, я использую Runnables и SwingUtilities.invokeLater для установки строки моего индикатора выполнения.setString JProgressBar более одного раза

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(); 
    } 

Edit:
Обратите внимание, что нет необходимости в очередь 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(); 
       }