如何使用 JProgressBar 运行 方法

How to run method with JProgressBar

我有一个名为 CreateAccount 的函数。我需要它 运行 并且还需要显示进度条。当我单击按钮时,该方法将启动。我需要开始显示加载进度条。一旦方法完成,进度条也应该停在 100。如果方法有更多时间来完成工作,进度条也需要缓慢加载。

我尝试使用以下代码,但它没有将进度条与该方法同步。那我该怎么做呢?

这是我的代码:

private static int t = 0;

private void createAccountBtnActionPerformed(java.awt.event.ActionEvent evt) {                                                 
        progressBar.setValue(0);
        progressBar.setStringPainted(true);

        new Thread(new Runnable() {
            @Override
            public void run() {
                //CreateAccount();

                for (t = 0; t <= 100; t++) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            CreateAccount();
                            progressBar.setValue(t);
                        }
                    });
                    try {
                        java.lang.Thread.sleep(100);
                    }
                    catch(InterruptedException e) { }
                }
            }
        }).start();
    }

由于 Swing 的单线程特性,您不能在事件调度线程的上下文中执行长 运行ning 或阻塞操作,也不能更新 UI在事件调度线程的上下文之外。

有关详细信息,请参阅 Concurrency in Swing

这两件事你都在处理。问题是,这意味着后台线程可能会做比 UI 上显示的更多的工作,而您无能为力。最好的办法就是尽可能让 UI 保持最新

一个可能更好的解决方案可能是使用 SwingWorker,它旨在使更新 UI 更容易。有关详细信息,请参阅 Worker Threads and SwingWorker

以下示例显示了一个进度条,该进度条将 运行 持续 10 秒,每次更新之间随机延迟最多 500 毫秒。然后根据剩余时间更新进度条。

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.time.Duration;
import java.time.Instant;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public final class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JProgressBar pb;
        private JButton btn;

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            btn = new JButton("Go");
            pb = new JProgressBar();

            add(btn, gbc);
            add(pb, gbc);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    btn.setEnabled(false);
                    makeItProgress();
                }
            });
        }

        protected void makeItProgress() {
            SwingWorker<Double, Double> worker = new SwingWorker<Double, Double>() {
                @Override
                protected Double doInBackground() throws Exception {
                    Duration duration = Duration.ofSeconds(10);
                    Instant startTime = Instant.now();
                    Duration runningTime = Duration.ZERO;
                    Random rnd = new Random();
                    setProgress(0);
                    do {
                        Thread.sleep(rnd.nextInt(500));
                        Instant now = Instant.now();
                        runningTime = Duration.between(startTime, now);

                        double progress = (double) runningTime.toMillis() / (double) duration.toMillis();
                        setProgress((int) (progress * 100));
                    } while (duration.compareTo(runningTime) >= 0);
                    setProgress(100);
                    return 1.0;
                }
            };
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    SwingWorker worker = (SwingWorker) evt.getSource();
                    if (evt.getPropertyName().equals("progress")) {
                        int value = (int) evt.getNewValue();
                        pb.setValue(value);
                    } else if (evt.getPropertyName().equals("state") && worker.getState() == SwingWorker.StateValue.DONE) {
                        pb.setValue(100);
                        btn.setEnabled(true);
                    }
                }
            });
            worker.execute();
        }

    }

}

这个例子的重点是,进度和工作混合到一个操作中(SwingWorkerdoInBackground 方法),因此它们的关系更密切。 SwingWoker 然后通知 PropertyChangeListener 更新,它可以在事件调度线程

上安全地对此做出反应