线程中的进度条不会更新其 UI,直到主线程中的工作完成

发布于 2024-12-12 03:45:00 字数 1448 浏览 0 评论 0原文

我正在将一个大文件切成块,并希望显示进度。 当我点击startCut按钮时,执行的代码如下:

FileInputStream in = new FileInputStream(sourceFile);
int blockSize = (int)(getSelectedBlockSize() * 1024);
int totalBlock = Integer.parseInt(txtNumberOfBlock.getText());
byte[] buffer = new byte[blockSize];
int readBytes = in.read(buffer);
int fileIndex = 1;

class PBThread extends Thread
{
    @Override
    public void run()
    {
        while(true)
        {
            pbCompleteness.setValue(value);
            //value++; //place A
            System.out.println(value);
            if (value >= 100)
                break;
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
        }
    }
}
value = 0;
PBThread pbThread = new PBThread();
pbThread.start();
while(readBytes != -1)
{
    File file = new File(targetFilePath + fileIndex);
    FileOutputStream out = new FileOutputStream(file);
    out.write(buffer, 0, readBytes);
    out.close();
    value = (int)(fileIndex / (double)totalBlock * 100);// place B
    readBytes = in.read(buffer);
    fileIndex++;
}

我在B处的run方法之外更改了进度条的值,问题是--进度条只显示两种状态:0%和100%。 但是,如果我删除 B 处的代码,并更改 A 处 run 方法内进度条的值,问题就会消失。 我知道也许使用 SwingWorker 可以轻松修复它,但我确实想知道为什么会发生这种情况,尽管我更改了 run 方法中的值,但当我在 run 方法中打印出来时,它确实发生了改变了。 在更改运行方法之外的值时如何解决该问题?

i am cutting a big file into blocks, and want to display the rate of the progress.
when i click startCut Button, here is the code to execute:

FileInputStream in = new FileInputStream(sourceFile);
int blockSize = (int)(getSelectedBlockSize() * 1024);
int totalBlock = Integer.parseInt(txtNumberOfBlock.getText());
byte[] buffer = new byte[blockSize];
int readBytes = in.read(buffer);
int fileIndex = 1;

class PBThread extends Thread
{
    @Override
    public void run()
    {
        while(true)
        {
            pbCompleteness.setValue(value);
            //value++; //place A
            System.out.println(value);
            if (value >= 100)
                break;
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
        }
    }
}
value = 0;
PBThread pbThread = new PBThread();
pbThread.start();
while(readBytes != -1)
{
    File file = new File(targetFilePath + fileIndex);
    FileOutputStream out = new FileOutputStream(file);
    out.write(buffer, 0, readBytes);
    out.close();
    value = (int)(fileIndex / (double)totalBlock * 100);// place B
    readBytes = in.read(buffer);
    fileIndex++;
}

i change the value of the progressbar outside the run method at place B,the problem is that --the grogressbar only show two state: 0% and 100%.
but, if i take away the code in place B, and change the value of the progressbar inside the run method at place A, the problem will disappear.
i know maybe with SwingWorker it can be fixed easily, but i do want to know why this happen,although i change the value out the run method,when i print it out in the run method,it did changed.
how can i fix that problem while changing value outside the run method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你的往事 2024-12-19 03:45:01

问题的关键在于您正在事件调度线程之外的线程上更新组件:pbCompleteness。您可以使用 SwingUtilities.invokeLater 来自您的 run() 方法;例如

AtomicInteger value = new AtomicInteger(0);
while (true) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      pbCompleteness.setValue(value.get());
    }
  });

  // Do some work and update value.
}

,当工作线程继续运行时,这将导致事件调度线程上的 JProgressBar 被更新(并重新绘制)。请注意,为了引用“内部”匿名 Runnable 实例中的 value,我已将其更改为 AtomicInteger。这也是可取的,因为它使其线程安全。

The crux of the problem is that you're updating the component: pbCompleteness on a thread other than the Event Dispatch Thread. You can remedy this using SwingUtilities.invokeLater from within your run() method; e.g.

AtomicInteger value = new AtomicInteger(0);
while (true) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      pbCompleteness.setValue(value.get());
    }
  });

  // Do some work and update value.
}

This will cause the JProgressBar to be updated (and repainted) on the Event Dispatch thread as your worker thread continues to run. Note that in order to refer to value within the "inner" anonymous Runnable instance I have changed it to be an AtomicInteger. This is also desirable as it makes it thread-safe.

只等公子 2024-12-19 03:45:01

这里有两个问题:

  • 您正在 Swing 调度程序线程中进行长时间运行的工作,这意味着您正在阻止它处理事件。 (尝试移动窗口等 - 它会失败。)
  • 您正在从 A 点的错误线程更新 UI。听起来您目前正在摆脱这个问题,但这仍然是一个错误。

您应该使用 SwingWorkerSwingUtilities 来解决这两个问题。基本上,您不得从非 UI 线程访问 UI,并且不得在 UI 线程上执行长时间运行的工作。有关详细信息,请参阅 Swing 并发教程

You've got two problems here:

  • You're doing long-running work in the Swing dispatcher thread, which means you're stopping it from processing events. (Try moving windows around etc - it will fail.)
  • You're updating the UI from the wrong thread at point A. It sounds like you're getting away with this at the moment, but it's still a bug.

You should use SwingWorker or SwingUtilities to address both of these issues. Basically, you mustn't access the UI from a non-UI thread, and you mustn't do long-running work on a UI thread. See the Swing concurrency tutorial for more information.

画离情绘悲伤 2024-12-19 03:45:01

我找到了解决这个问题的一个非常简单的方法:D。您可以使用此代码并且非常简单地处理此错误:)。

int progress=0;
Random random = new Random();
while (progress < 100) {
 //Sleep for up to one second.
 try {
       Thread.sleep(random.nextInt(100));
} catch (InterruptedException ignore) {}
progress+=1;
progressBar.setValue(progress);
Rectangle progressRect = progressBar.getBounds();//important line 
progressRect.x = 0;
progressRect.y = 0;         
progressBar.paintImmediately(progressRect);//important line 
 }

i found a very simple way to this prob :D . you can use this code and very simlpe handel this error :).

int progress=0;
Random random = new Random();
while (progress < 100) {
 //Sleep for up to one second.
 try {
       Thread.sleep(random.nextInt(100));
} catch (InterruptedException ignore) {}
progress+=1;
progressBar.setValue(progress);
Rectangle progressRect = progressBar.getBounds();//important line 
progressRect.x = 0;
progressRect.y = 0;         
progressBar.paintImmediately(progressRect);//important line 
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文