JProgressBar不会更新

我正在尝试将JProgressBar添加到我的程序中,但它不会更新! 只有在100%的原因后,该值才会更改。 这是我的方法。

public void downloadImages(List images) { if (errorCode == 0) { for (int i = 0; i < images.size(); i++) { if (errorCode == 0) { main.progressLabel.setText("Downloading image " + Integer.toString(i + 1) + " of " + Integer.toString(images.size())); String imageStr = images.get(i); String imageName = imageStr.substring(imageStr.lastIndexOf("/") + 1); try { URL url = new URL(imageStr); InputStream in = url.openStream(); OutputStream out = new FileOutputStream(saveDirectory + imageName); byte[] b = new byte[2048]; int length; while ((length = in.read(b)) != -1) { out.write(b, 0, length); } in.close(); out.close(); } catch (MalformedURLException e) { errorCode = BAD_URL; } catch (IOException e) { errorCode = INVALID_PATH; } main.progressBar.setValue(((i+1)/images.size())*100); } } } } 

更改进度条值位于上述方法的底部。

这就是我如何称呼该方法。

 public void download() { final Downloader downloader = new Downloader(this, albumUrl.getText(), downloadPath.getText()); progressBar.setValue(0); downloadButton.setEnabled(false); new Thread(new Runnable() { public void run() { List images = downloader.getImages(downloader.getPageSource()); downloader.downloadImages(images); if (downloader.getErrorCode() == 0) { progressLabel.setText("All images have been downloaded!"); } else { String error = ""; switch (downloader.getErrorCode()) { case Downloader.BAD_URL: case Downloader.NOT_IMGUR_ALBUM: error = "The URL entered is either invalid or does not link to an Imgur album."; break; case Downloader.BLANK_URL: error = "The album URL field cannot be blank."; break; case Downloader.INVALID_PATH: error = "The system cannot find the download directory path specified."; break; case Downloader.BLANK_PATH: error = "The download directory cannot be blank."; break; case Downloader.CANNOT_READ_URL: error = "An error occoured while reading the URL."; break; case Downloader.PARSING_ERROR: error = "An error occoured while parsing the URL."; break; } JOptionPane.showMessageDialog(Main.this, error, "Error", 0); } downloadButton.setEnabled(true); } }).start(); } 

编辑:上面的问题根本不是问题,程序使用整数除法而不是小数。

images.size()是一个整数, i+1也是如此,所以发生的是十进制被截断。 你应该做什么这样的事情

main.progressBar.setValue((int)((i+1)/(double)images.size())/100))

这样做是为了确保i+1被一个支持十进制的数据类型划分,它将返回更具包容性的数据类型(在这种情况下为double),然后它将除以一个int,这将没有问题,因为它仍然会返回一个双倍,因为它更具包容性。 然后我们将它转​​换为int,因为这是setValue()想要的数据类型。

主要问题是,您通过在GUI EDT上执行长时间运行的任务来阻止事件调度线程 。

而是使用SwingWorker 。

这是一个小例子:

在此处输入图像描述

 import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Random; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingWorker; public class ProgressBarDemo extends JPanel { private JButton startButton; private JTextArea taskOutput; public ProgressBarDemo() { super(new BorderLayout()); final JProgressBar progressBar = new JProgressBar(0, 100); progressBar.setValue(0); progressBar.setStringPainted(true); taskOutput = new JTextArea(5, 20); taskOutput.setMargin(new Insets(5, 5, 5, 5)); taskOutput.setEditable(false); // Create the demo's UI. startButton = new JButton("Start"); startButton.setActionCommand("start"); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { startButton.setEnabled(false); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // Instances of javax.swing.SwingWorker are not reusuable, so // we create new instances as needed. final Task task = new Task(); task.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent pce) { if ("progress".equals(pce.getPropertyName())) { int progress = (Integer) pce.getNewValue(); progressBar.setValue(progress); taskOutput.append(String.format("Completed %d%% of task.\n", task.getProgress())); } } }); task.execute(); } }); JPanel panel = new JPanel(); panel.add(startButton); panel.add(progressBar); add(panel, BorderLayout.PAGE_START); add(new JScrollPane(taskOutput), BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); } /** * Create the GUI and show it. As with all GUI code, this must run on the * event-dispatching thread. */ private static void createAndShowGUI() { JFrame frame = new JFrame("ProgressBarDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel progressBarPanel = new ProgressBarDemo(); frame.add(progressBarPanel); frame.pack(); frame.setVisible(true); } public static void main(String[] args) { // Schedule a job for the event-dispatching thread: // creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } private class Task extends SwingWorker { /* * Main task. Executed in background thread. */ @Override public Void doInBackground() { Random random = new Random(); int progress = 0; // Initialize progress property. setProgress(0); while (progress < 100) { // Sleep for up to one second. try { Thread.sleep(random.nextInt(1000)-15); } catch (InterruptedException ignore) { } // Make random progress. progress += random.nextInt(10); setProgress(Math.min(progress, 100)); } return null; } /* * Executed in event dispatching thread */ @Override public void done() { Toolkit.getDefaultToolkit().beep(); startButton.setEnabled(true); setCursor(null); // turn off the wait cursor taskOutput.append("Done!\n"); } } } 

Swing的两条规则……

  1. 不要阻止事件调度线程
  2. 不要从Event Dispatching Thread的外部更新任何UI组件。

我确信还有更多,但要打破其中一个或两个,并期待发生很多不好的事情。

Swing是一个单线程API。 有一个线程负责调度事件,包括重绘请求。 如果您阻止此线程(执行耗时的任务,I / O等等),您将阻止它处理来自用户的输入并将重新绘制请求分派给组件 – 因此没有任何内容会更新,您的应用程序将看起来像挂起…

你需要让你的图像加载代码关闭EDT …

查看Swing中的Concurrency以获取更多详细信息,特别是查看Worker Threads和SwingWorker