2013-11-26 38 views
0

我在这个类中执行任务,对话框弹出为白色框。打印语句IS打印出我期待的进度值,但直到操作完成后才在对话框中显示出来。在对话框结束之前,我可以看到进度条闪烁一毫秒。绝对不知道怎么回事:\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(); 
      } 
     }; 
    } 
} 

编辑:试过这个改变。没有骰子。为什么我甚至没有获得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

你试图从SwingWorker类的doInBackground方法中设置进度条的状态,从后台线程出现。使用SwingWorker的全部原因是允许您在Swing GUI中执行后台进程,因此您不会从后台线程进行Swing调用,因此您不会将Swing线程与长时间的线程绑定在一起,运行一段代码。

您不应该从此后台进程进行Swing调用。而是使用发布/处理方法,因为教程将向您展示。或者更好的办法是设置SwingWorker的progress字段,并在SwingWorker上使用PropertyChangeListener来允许进度条对它作出反应。

无论如何,底线:

  • 使用的SwingWorker做后台工作。
  • 不要在SwingWorker的doInBackground方法中进行Swing调用。
  • 使用发布将数据从背景方法推送到Swing线程领域。
  • 使用处理方法来处理推送的这些数据。
  • SwingWorker具有progress属性,该属性在允许Swing代码响应背景状态变化时也很方便。
  • 如果你走这条路线,使用PropertyChangeListener。
  • 你差不多从不想使用setBounds(...)或null布局。相信我是一个写过数百个Swing程序的人,最后这个人会咬你的。
  • 它看起来好像您的类别正在使用静态方法获取其进展。再一次,这是你几乎从不想做的事情。进度字段建议状态,并且这应该是对象的实例字段的一部分,从不静态。
+0

我尝试了两个建议,他们都导致进度条只有在达到100时才会收到一个更新。我比我开始更困惑 –

+0

@MichaelGroleau:如果您已经做出更改,请将代码作为编辑发布到您的原来的问题。不要更改原始问题的代码和文本,但将新信息添加到底部。 –

+0

完成后,评论 –

2

这是一个SSCCE来演示如何更新您的JProgressBar。复制/粘贴并运行它。

请注意我们如何通过调用publish(i)来更新进度条,它将整数发送到process()方法。 SwingWorker以块结果的方式将结果发送给process()方法,但我们仅使用Integer来更新JProgressBar,因此我们只关心它的最后一个块。在这个SSCCE,我们从1-1000。如果您检查控制台,您会看到1-1000之间的很多数字会被忽略,因为我们正在更新太快而无法跟上(但没关系,这就是为什么它会以块形式提供结果)。

注意:process()方法最初是为程序员设计的,用于从其长时间运行的进程返回实时结果并更新GUI。因此,如果您正在执行数据库提取,则可以使用返回的结果更新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(); 
      } 
     } 
    } 
} 

编辑:我创建了一个图处理SwingWorker时,这应该是一个有益的参考,让你知道在哪里放置你的代码。

enter image description here

+0

尼斯SSCCE,谢谢,1+ –

+0

@HovercraftFullOfEels,你怎么看图?有用? – ryvantage

+0

它看起来非常好! –