Java 加载图像时,JProgressBar不会在for循环中更新
我正在编写一个小工具,将一些过滤器应用于大量图像。我想在加载图像时添加进度条。 为此,我在这里编写了以下简单代码:Java 加载图像时,JProgressBar不会在for循环中更新,java,swing,event-dispatch-thread,jprogressbar,Java,Swing,Event Dispatch Thread,Jprogressbar,我正在编写一个小工具,将一些过滤器应用于大量图像。我想在加载图像时添加进度条。 为此,我在这里编写了以下简单代码: //Set up Progressbar int pictureCount = 0; for (File file : chooser.getSelectedFile().listFiles(isImage)) { pictureCount++; }
//Set up Progressbar
int pictureCount = 0;
for (File file : chooser.getSelectedFile().listFiles(isImage)) {
pictureCount++;
}
progressBar.setMinimum(0);
progressBar.setMaximum(pictureCount);
//Load all the Images and updating Progressbar
for (File file : chooser.getSelectedFile().listFiles(isImage)) {
BufferedImage bi = ImageIO.read(file);
tilesNew.add(bi);
progressBar.setValue(progressBar.getValue() + 1);
}
不幸的是,progressbar仅在循环结束时更新。所以它显示整个时间的0%,然后在程序加载所有图像几秒钟后直接显示100%
到目前为止,我已经尝试使用
循环中的
frame.revalidate()
,frame.repaint()
和Thread.sleep()
。都没有成功。我很久没有使用Swing了,
但是,似乎您在做一些在任何GUI平台上常见的错误
您的代码似乎在主(UI)线程中读取大文件
当主线程不忙时,UI将被更新。
但是,主线程在处理图像时总是很忙
您应该创建一个新的线程
,该线程处理文件和图像,然后创建的线程应该将其传递给主线程,以便在每次需要更新进程栏
时更新UI
以下是Swing
中支持多线程的一些帮助工具:下面是一个使用JProgressBar的快速演示
- 我用定时器来模拟做一些工作
- 更新进度条时,将调用
,我将重新绘制ChangeListener
- 确保您没有在EDT中读取文件和更新进度条
Thread.sleep(150)
不起作用不幸的是,progressbar仅在循环结束时更新-这表示您正在事件调度线程(EDT)
上执行代码,这意味着GUI在循环完成之前无法响应事件或重新绘制自身。您需要在单独的线程上执行代码。阅读上的Swing教程中的部分。它将向您展示如何使用SwingWorker
,这样您就不会阻止EDT。我使用了链接中描述的Invoke-Later方法。工作得很有魅力。将for循环打包到新线程中。然后在其中创建一个新线程,用于调用相关程序进行更新。@Samuel我认为从技术上讲,您只需要一个新线程
和两个新可运行线程
s。将for
循环打包到新的Runnable
中,该循环是新线程的参数。在那里,将与UI组件相关的代码(如使用progressBar
的语句或显示Swing组件或任何UI组件的图像)包装在新的Runnable
中,这是SwingUtilities.invokeLater()的参数。可以在任何线程中读取文件或处理图像,但是UI组件只能在主(UI)线程中更新。这就是为什么要使用SwingUtilities.invokeLater()
。SwingUtilities.invokeLater()中的runnable将自动传递给主线程并在主线程中执行。
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.Timer;
public class ProgressBarDemo extends JPanel {
JFrame frame;
final static int WIDTH = 200;
final static int HEIGHT = 30;
public ProgressBarDemo() {
frame = new JFrame();
setPreferredSize(new Dimension(WIDTH, HEIGHT));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new ProgressBarDemo().startUp();
}
public void startUp() {
JProgressBar p = new JProgressBar(0, 100);
// every 200 milliseconds, add one to the JProgressBar
Timer t =
new Timer(200, (ae) -> p.setValue(p.getValue() + 1));
// invoked when the JProgressBar changes. Calls repaint.
p.addChangeListener((ce) -> frame.repaint());
add(p);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
t.start();
}
}