JProgressBar不会更新

时间:2013-01-11 04:51:36

标签: java swing concurrency event-dispatch-thread jprogressbar

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

public void downloadImages(List<String> 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<String> 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();
}

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

3 个答案:

答案 0 :(得分:7)

主要问题是,您通过在GUI EDT上执行长时间运行的任务来阻止Event Dispatch Thread

而是使用SwingWorker

这是一个小例子:

enter image description here

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<Void, Void> {

        /*
         * 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");
        }
    }
}

答案 1 :(得分:4)

images.size()是一个整数,i+1也是如此,所以正在发生的是小数被截断。你应该做什么,如

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

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

答案 2 :(得分:3)

Swing的两个规则......

  1. 不要阻止事件调度线程
  2. 不要从事件调度线程的外部更新任何UI组件。
  3. 我确信还有更多,但要打破其中一个或两个,并期待发生很多坏事。

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

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

    请查看Concurrency in Swing了解详情,尤其是Worker Threads and SwingWorker