setString JProgressBar более одного раза - PullRequest
2 голосов
/ 14 марта 2012

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

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, но безрезультатно.Итак, как мне это сделать?

1 Ответ

4 голосов
/ 15 марта 2012

Вы должны понимать, что в коде нет паузы (и не должно быть) между вашим звонком на

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