简体   繁体   English

JProgressBar不会更新

[英]JProgressBar wont update

I'm trying to add a JProgressBar to my program, but it wont update! 我正在尝试将JProgressBar添加到我的程序中,但它不会更新! The value only changes once it reasons 100%. 只有在100%的原因后,该值才会更改。 Here's my method. 这是我的方法。

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

        }
    }
}

Changing the progress bar value is at the bottom of the method above. 更改进度条值位于上述方法的底部。

And here is how I call that method. 以下是我称之为该方法的方法。

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

EDIT: The above was not the problem at all, the problem one the program was using Integer Division and not decimal. 编辑:上面的问题根本不是问题,程序使用整数除法而不是小数。

The main problem is, you are blocking the Event Dispatch Thread , by doing a long running task on the GUI EDT. 主要问题是,您通过在GUI EDT上执行长时间运行的任务来阻止事件调度线程

Rather use SwingWorker . 而是使用SwingWorker

Here is a small example: 这是一个小例子:

在此输入图像描述

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

images.size() is an integer, and so is i+1 , so what's happening is the decimal is getting truncated. images.size()是一个整数, i+1也是如此,所以发生的是十进制被截断。 What you should be doing so something like 你应该做什么这样的事情

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

What this'll do is it'll ensure that i+1 is being divided by a decimal capable data-type, which'll return the more inclusive data type (double in this case), and then it'll divide a double by an int which'll be no problem because it'll still return a double because it's more inclusive. 这样做是为了确保i+1被一个支持十进制的数据类型划分,它将返回更具包容性的数据类型(在这种情况下为double),然后它将除以一个int,这将没有问题,因为它仍然会返回一个双倍,因为它更具包容性。 We then cast that to an int because that's the data type setValue() wants. 然后我们将它转​​换为int,因为这是setValue()想要的数据类型。

Two rules of Swing... Swing的两条规则......

  1. Don't block the Event Dispatching Thread 不要阻止事件调度线程
  2. Don't update any UI component from out side of the Event Dispatching Thread. 不要从Event Dispatching Thread的外部更新任何UI组件。

I'm sure there are more, but break either or both of these and expect lots-o-bad things to happen. 我确信还有更多,但要打破其中一个或两个,并期待发生很多不好的事情。

Swing is a single thread API. Swing是一个单线程API。 There is a single thread responsible for dispatching events, including repaint requests. 有一个线程负责调度事件,包括重绘请求。 If you block this thread (doing time consuming tasks, I/O, etc...) you will stop it from processing input from the user and dispatching repaint requests to the components - so nothing will update and your application will look like it's hung... 如果您阻止此线程(执行耗时的任务,I / O等等),您将阻止它处理来自用户的输入并将重新绘制请求分派给组件 - 因此不会更新任何内容,您的应用程序将看起来像挂起...

You need to get your image loading code OFF the EDT... 您需要将图像加载代码关闭EDT ...

Take a look at Concurrency in Swing for more details, in particular, take a look at Worker Threads and SwingWorker 有关更多详细信息,请查看Swin中的Concurrency ,特别是查看Worker Threads和SwingWorker

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM