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();
    }
}