【问题标题】:JProgressBar will not update until process is completedJProgressBar 在进程完成之前不会更新
【发布时间】:2013-06-09 23:21:07
【问题描述】:

我知道这里有很多JProgressBar 问题,但是通过所有答案,我似乎无法诊断出我的问题。我正在使用一些地址验证软件处理文件。我单击处理按钮,我需要我的JProgressBar 来更新每个处理的文件。 这是按钮:

private JButton getJButton0() {
...
   jButton0.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
         jButton0ActionActionPerformed(event);
         t.start();
      }
...

根据大家的建议,我在一个线程中使用了setValue() 方法

Thread t = new Thread(){
    public void run() {
    SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        jProgressBar0.setValue(BulkProcessor.getPercentComplete());
    }
});
try {
    Thread.sleep(100);
} catch (InterruptedException e) {
}
...

BulkProcessor.getPercentComplete() 是我从另一个类调用的方法,它代表完成百分比。我已经测试了这个方法,它可以正确更新。问题是进度条在文件完成处理之前不会更新,然后会跳转到 100%。如果这是一个重复的问题,我深表歉意,但我在这个网站上做了一些认真的挖掘,但没有运气。非常感谢任何帮助。

编辑:

每个推荐的副本,我都试过这个:

public void update(){
   new SwingWorker<Void,Void>() {
   protected Void doInBackground() throws Exception {
   jProgressBar0.setValue(BulkProcessor.getPercentComplete());
   return null;
 };
 }.execute();
}

然后尝试在actionPerformed() 下调用这个update() 方法(将t.start()update() 切换)。我仍然有同样的问题。

编辑

根据 user1676075 的建议,但同样的问题:

    public static void update(){
       new SwingWorker<Void,Integer>() {
       protected Void doInBackground() throws Exception {
           do
           {
           percentComplete = BulkProcessor.getPercentComplete();
           publish(percentComplete);
           Thread.sleep(100);
           } while(percentComplete < 100);

        return null;
       }
       @Override
    protected
       void process(List<Integer> progress)
       {
           jProgressBar0.setValue(progress.get(0));
       }
     }.execute();
   }

编辑

这是我的 BulkProcessor 类的代码

 private String getOutputLine( String searchString, String inputLine )
throws QasException
{
 ..(code for processing lines)..
 countRecord++;
    percentComplete = (int) Math.round((countRecord/totalRecord)*100);

totalRecord 在我的BulkProcessor 类的主类中更新

 public static void main( String input, String output ){
    count.clear();
    try{
        String inputFile = input;
        String outputFile = output;
        LineNumberReader  lnr = new LineNumberReader(new FileReader(new File(input)));
        lnr.skip(Long.MAX_VALUE);
        totalRecord = lnr.getLineNumber() + 1; //line count in file
        BulkProcessor bulk = new BulkProcessor(inputFile, outputFile, ConfigManager.DFLT_NAME);
        bulk.process();
    }catch(Exception e ){
        e.printStackTrace();
    }

}

【问题讨论】:

  • 不要阻塞 EDT(事件调度线程)——当这种情况发生时,GUI 将“冻结”。而不是调用 Thread.sleep(n) 实现 Swing Timer 用于重复任务或 SwingWorker 用于长时间运行的任务。有关详细信息,请参阅Concurrency in Swing。 ..好的,这是我根据标题发表的评论。但是.. Thread.sleep(100); 里面 SwingWorker?那是拟人化的怪异!为了尽快获得更好的帮助,请发帖SSCCE
  • 这是duplicate
  • 请参阅上面的编辑,我基于 Uwe Plonus 的重复链接
  • for example,有些在JTable标签下,有SwingWoker和Runnable@Thread的例子
  • 不同的只要线程正确交互就不是问题

标签: java swing swingworker event-dispatch-thread jprogressbar


【解决方案1】:

看起来您正在混合使用。请参阅 SwingWorker 文档,顶部示例:http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html

理想情况下,您应该在 SwingWorker 的 doInBackground 方法中更新 BulkProcessor,这将调用 setProgress,jProgressBar 将像示例中那样监听这些进度更新。

如果这对您不起作用,它似乎不仅仅基于上述内容,请从按钮按下事件启动 SwingWorker。实现 SwingWorker 方法有点像这样(伪代码):

new SwingWorker<Void,Integer>()
{
  doInBackground()
  {
    do
    {
      percentComplete = BulkProcessor.getPercentComplete();
      publish(percentCompete);
      Thread.sleep(100);
    } while (percentComplete < 100);
  }

  @Override
  process(List<Integer> progress)
  {
     jProgressBar0.setValue(progress.get(0));
  }
}.execute();

您需要添加错误处理并检查完整和失败的情况,但这应该可以帮助您开始并到达您想要的位置。 doInBackground 在后台线程中运行,因此不会阻塞任何内容,而 process() 在 swing 工作线程上运行,因此会发布更新。

【讨论】:

  • 你在while循环中完成的百分比是指我的getPercentComplete()吗?
  • 另外,不需要返回类型吗?
  • 需要进行一些清理。我只是想抓住要点。你真的不需要返回任何东西(虽然你确实需要一个返回类型,是的,尽管 Void/null 是有效的)。 publish(Integer) 和 process(Integer) 是处理状态更新的主要方法。 process() 实际上会得到 List 并且您只需要项目 0。是的,至于完成百分比,您需要一些方法来知道何时停止检查和发布进度更新。但大概你有这些信息(检查进度
  • 在您的示例中,从不读取 process 方法(查看我上次编辑使用的代码)
  • 查看我的编辑:1) 将 while 循环更改为 do-while,并读取循环中 inside 的批量处理器值。 2)在process()方法中添加@Override注解,确保你得到正确的签名(应该是一个整数列表,你只关心第一个)。
【解决方案2】:

您可能犯的错误是调用 t.start();在jButton0ActionPerformed(event); 之后,这使得在执行操作后线程将启动。因此进度条的值不会按预期更新。

你需要在 jButton0ActionPerformed(event); 中启动线程然后更新其中的值。

【讨论】:

  • 你说得对,我之前确实注意到了这一点,但是我没有在我的帖子中更新它,抱歉。
【解决方案3】:

只是一种预感,但是...

    percentComplete = (int) Math.round((countRecord/totalRecord)*100);

你确定这不是整数运算吗?我不知道totalRecord的类型,所以不能肯定。

我猜一切正常,只是进度一直是 0,直到完成,它神奇地是 100。这是因为 int 除以 int 不会有小数值(即 99/100 = = 0, 100/100 == 1)。这完全符合您遇到的症状。

尝试将上面的行替换为:

   percentComplete = (int) Math.round((countRecord/(double) totalRecord)*100);

看到它我是对的。 :-)

【讨论】:

  • 我做了一个 system.out.print(percentComplete) 并在控制台中打印出我想要的值 (1,3,4,5,......100)。所以我认为这不是问题。
  • 另外,totalRecord 是一个 double
【解决方案4】:

您是否尝试过使用PropertyChangeListener-interface?

计算将由 Swingworker-thread 完成,main-gui 将实现此接口。一些示例代码

@Override
public void actionPerformed(ActionEvent e) {
    this.myButton.setEnabled(false);
    MyWorkerThread thread = new MyWorkerThread(); //Data-processing
    thread.addPropertyChangeListener(this.mainguiframe); //Separation of concern
    thread.execute();
}

使用 swing-worker-thread 的“setProgress”方法,如果发生了什么事,main-gui-thread 会收到通知。

@Override
public void propertyChange(PropertyChangeEvent property) {
     Integer currentValue = new Integer(0);
     currentValue = (Integer) property.getNewValue();
     this.progressBar.setValue(currentValue.intValue());
}

Swing 不是线程安全的。这不是最好的解决方案,但也许它可以帮助您。如果有什么可怕的错误,请发表评论。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多