2013-11-26 4 views
0

Выполняю задачу в этом классе, и диалоговое окно появляется в виде белого квадрата. Оператор печати распечатывает ожидаемые значения прогресса, но ничего не отображается в диалоговом окне до завершения операции. Я вижу, что индикатор хода выполнения отображается на миллисекунду до того, как диалог закрыт в конце. Абсолютно не знаю, что происходит: \JProgressBar невидим, но прогресс обновляется правильно

public class ProgressDialog extends JDialog { 

    private JProgressBar pb; 
    private SwingWorker<Boolean, Void> task; 

    public SwingWorker<Boolean, Void> getTask(){ 
     return task; 
    } 

    public ProgressDialog(final String call){ 
     setTitle("Working..."); 
     setLayout(new BorderLayout()); 
     setBounds(300,300,300,100); 
     pb = new JProgressBar(0, 100); 
     pb.setValue(0); 
     pb.setVisible(true); 
     pb.setStringPainted(true); 
     add(pb, BorderLayout.CENTER); 
     setVisible(true); 

     task = new SwingWorker<Boolean, Void>(){ 
      public Boolean doInBackground(){   
       switch(call){ 
       case "Category": pb.setValue(Category.getProgress()); 
       while(pb.getValue()<99){ 
        try{ 
         Thread.sleep(500); 
        } catch (InterruptedException e){ 
         Thread.currentThread().interrupt(); 
        } 
        pb.setValue(Category.getProgress()); 
        System.out.println(pb.getValue()); 
        repaint(); 
        revalidate(); 
       } 
       break; 
       } 
       return true; 
      } 
      public void done(){ 
       dispose(); 
      } 
     }; 
    } 
} 

EDIT: попробовал это изменение. нет кубиков. Почему я не получаю индикатор прогресса на 0%? Он появляется только один раз он на 100%

public class ProgressDialog extends JDialog { 

private JProgressBar pb; 
private SwingWorker<Boolean, Integer> task; 

public SwingWorker<Boolean, Integer> getTask(){ 
    return task; 
} 

public ProgressDialog(final String call){ 
    setTitle("Working..."); 
    setLayout(new BorderLayout()); 
    setBounds(300,300,300,100); 
    pb = new JProgressBar(0, 100); 
    pb.setValue(0); 
    pb.setStringPainted(true); 
    add(pb, BorderLayout.CENTER); 
    setVisible(true); 

    task = new SwingWorker<Boolean, Integer>(){ 
     public Boolean doInBackground(){   
      switch(call){ 
      case "Category": setProgress(Category.getProgress()); 
      while(pb.getValue()<99){ 
       try{ 
        Thread.sleep(500); 
       } catch (InterruptedException e){ 
        Thread.currentThread().interrupt(); 
       } 
       setProgress(Category.getProgress()); 
      } 
      break; 
      } 
      return true; 
     } 

     public void done(){ 
      //dispose(); 
     } 
    }; 

    task.addPropertyChangeListener(new PropertyChangeListener() { 
       public void propertyChange(PropertyChangeEvent evt) { 
        if ("progress".equals(evt.getPropertyName())) { 
         System.out.println((Integer)evt.getNewValue()); 
         pb.setValue((Integer)evt.getNewValue()); 
         pb.revalidate(); 
         pb.repaint(); 
        } 
       } 
      }); 
} 

}

+0

Пожалуйста, смотрите обновления для ответов, в частности, ответ и код ryvantage, который вы, вероятно, следует принять. –

ответ

3

Вы пытаетесь установить состояние прогресс бар изнутри метода doInBackground в SwingWorker, в из фонового потока - который не имеет никакого смысла , Вся причина использования SwingWorker заключается в том, чтобы разрешить вам выполнять фоновый процесс в графическом интерфейсе Swing, поэтому вы не вызываете вызовы Swing из фонового потока и так, чтобы вы не привязывали поток Swing к длинному, бегущий бит кода.

Вы не должны делать вызовы Swing из этого фонового процесса. Вместо этого используйте методы публикации/процесса, как покажут вам учебные пособия. Или, может быть, лучше, установите поле прогресса SwingWorker и используйте PropertyChangeListener в SwingWorker, чтобы позволить индикатору выполнения реагировать на него.

Несмотря на это, в нижней строке:

  • Используйте SwingWorker сделать подготовительную работу.
  • Не используйте вызовы Swing из метода doInBackground SwingWorker.
  • Используйте публикацию для перемещения данных из фонового метода в область Swing thread.
  • Используйте метод процесса для перемещения этих данных.
  • SwingWorker имеет свойство прогресса, которое также удобно использовать для того, чтобы позволить Swing-коду реагировать на изменения состояния фона.
  • Если вы идете по этому маршруту, используйте PropertyChangeListener.
  • Вы почти никогда хотите использовать setBounds(...) или нулевой макет. Поверьте мне, как кто-то, кто написал сотни программ Swing, этот вас укусит в конце.
  • Похоже, ваша Категория использует статический метод для достижения своего прогресса. Опять же, это то, что вы почти никогда не хотите делать. Поле прогресса предлагает состояние, и это должно быть частью полей экземпляра объекта, никогда не статичным.
+0

Я пробовал оба предложения, и оба они привели к тому, что индикатор прогресса получил только одно обновление после достижения 100. Я еще более смущен, чем начал –

+0

@MichaelGroleau: если вы внесли изменения, отправьте код как отредактируйте его оригинал вопрос. Не изменяйте код и текст исходного вопроса, но добавляйте новую информацию в нижнюю часть. –

+0

сделано, с комментарием –

2

Это SSCCE, чтобы продемонстрировать, как вы должны обновлять свой JProgressBar. Скопируйте/вставьте это и запустите.

Обратите внимание, как мы обновляем индикатор выполнения, вызывая publish(i), который отправляет целое число в метод process(). SwingWorker отправляет результаты на метод process() в кусках, но мы используем только Integer для обновления JProgressBar, так что все, что нам нужно, это LAST chunk. В этом SSCCE мы переходим от 1-1000.Если вы просмотрите консоль, вы увидите, что количество чисел между 1-1000 пропускается, потому что мы слишком быстро обновляемся для SwingWorker, чтобы догнать (но все в порядке. Вот почему он дает результаты в кусках).

ПРИМЕЧАНИЕ: метод process() был первоначально разработан для того, чтобы программисты возвращали результаты в режиме реального времени из своих длительных процессов и обновляли графический интерфейс. Итак, если вы делали выборку базы данных, вы можете обновить JTable с результатами, которые вы возвращаете. Тем не менее, я ненавижу это делать. Таким образом, в 99% случаев я просто использую «неопределенный» JProgressBar и жду, пока метод done() опубликует мои результаты. Тем не менее, иногда я использую «детерминированный» JProgressBar и обновляюсь, как в этом SSCCE. Никогда не использовал process() для возврата и публикации фактических данных. :) Но это то, что изначально предназначалось для этого.

import java.util.List; 
import java.util.concurrent.ExecutionException; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JProgressBar; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

/** 
* 
* @author Ryan 
*/ 
public class Test { 

    public static void main(String args[]) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       go(); 
      } 
     }); 
    } 

    public static void go() { 
     JFrame frame = new JFrame(); 
     JProgressBar jpb = new JProgressBar(); 
     jpb.setIndeterminate(false); 
     int max = 1000; 
     jpb.setMaximum(max); 
     frame.add(jpb); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     new Task(jpb, max).execute(); 
    } 

    static class Task extends SwingWorker<Void, Integer> { 

     JProgressBar jpb; 
     int max; 
     public Task(JProgressBar jpb, int max) { 
      this.jpb = jpb; 
      this.max = max; 
     } 

     @Override 
     protected void process(List<Integer> chunks) { 
      jpb.setValue(chunks.get(chunks.size()-1)); // The last value in this array is all we care about. 
      System.out.println(chunks.get(chunks.size()-1)); 
     } 

     @Override 
     protected Void doInBackground() throws Exception { 
      for(int i = 0; i < max; i++) { 
       Thread.sleep(10); // Sleep for 1/10th of a second 
       publish(i); 
      } 
      return null; 
     } 

     @Override 
     protected void done() { 
      try { 
       get(); 
       JOptionPane.showMessageDialog(jpb.getParent(), "Success", "Success", JOptionPane.INFORMATION_MESSAGE); 
      } catch (ExecutionException | InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

EDIT: Я создал диаграмму, которая должна быть полезной ссылкой при обращении SwingWorker, так что вы знаете, где разместить свой код.

enter image description here

+0

Nice SSCCE, спасибо, 1+ –

+0

@HovercraftFullOfEels, что вы думаете о диаграмме? Полезно? – ryvantage

+0

Это выглядит очень хорошо! –

Смежные вопросы