Java 在主线程中完成工作之前,线程中的progressbar不会更新其UI
我正在将一个大文件切成块,并希望显示进度。 单击startCut按钮时,下面是要执行的代码:Java 在主线程中完成工作之前,线程中的progressbar不会更新其UI,java,swing,progress-bar,Java,Swing,Progress Bar,我正在将一个大文件切成块,并希望显示进度。 单击startCut按钮时,下面是要执行的代码: FileInputStream in = new FileInputStream(sourceFile); int blockSize = (int)(getSelectedBlockSize() * 1024); int totalBlock = Integer.parseInt(txtNumberOfBlock.getText()); byte[] buffer = new byte[blockSi
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方法之外更改了progressbar的值,问题是-grogressbar只显示两种状态:0%和100%。
但是,如果我去掉B处的代码,并在A处更改run方法中progressbar的值,问题就会消失。
我知道可能使用SwingWorker可以很容易地修复,但我确实想知道为什么会发生这种情况,尽管我在run方法中更改了值,但当我在run方法中打印出来时,它确实更改了。
在运行方法之外更改值时,如何解决该问题?问题的关键在于您正在更新事件调度线程以外的线程上的组件:PBP完整性。您可以在运行方法中使用补救措施;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.
}
这将导致在工作线程继续运行时,在事件调度线程上更新并重新绘制JProgressBar。注意,为了引用内部匿名可运行实例中的值,我将其更改为AtomicInteger。这也是可取的,因为它使线程安全。这里有两个问题: 您正在Swing dispatcher线程中执行长时间运行的工作,这意味着您正在阻止它处理事件。尝试移动窗口等-它将失败。 你在A点从错误的线程更新UI。听起来你现在似乎没有受到影响,但这仍然是一个bug。
您应该使用SwingWorker或SwingUtilities来解决这两个问题。基本上,您不能从非UI线程访问UI,也不能在UI线程上执行长时间运行的工作。有关更多信息,请参阅。我找到了一种解决此问题的非常简单的方法。您可以使用此代码并非常简单地处理此错误:
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
}
刚才,我了解了一些关于事件调度线程的知识,并且理解了您所说的,thx很多问题不是他正在更新EDT的Swing组件-这将导致NPE或可能的比赛条件。由于Swing被锁定,他正在调用EDT上的一段长时间运行的代码,可能是这一部分:whilereadBytes!=-1{…},它需要在后台线程中。我已经尝试了你的方法,仍然存在问题,我如何使用你的方法向你展示我的新代码?我如何向你展示我的新代码编辑问题,然后在每个问题的注释中通知回复者-让他们知道。我会记住你说的话。你帮了我很多忙。这很大程度上得益于你已经收到的好建议。。线程100;-不要那样做。如果GUI中需要延迟(例如用于动画),请创建一个Swing。