【问题标题】:How to run method with JProgressBar如何使用 JProgressBar 运行方法
【发布时间】:2020-05-10 18:45:09
【问题描述】:

我有一个名为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();
    }

【问题讨论】:

  • Thread.sleep() 不能从 Swing 事件调度线程 (EDT) 使用。使用 Swing Timer
  • @AJNeufeld 根据上面的例子,OP 在他们正在创建的新 Thread 的上下文中使用 Thread.sleep
  • @MadProgrammer 好点。我的甜酒增强解析器解析错误。还以为是在invokeLater()
  • 1) 为了尽快获得更好的帮助,edit 添加minimal reproducible exampleShort, Self Contained, Correct Example。 2) 请学习常见的 Java 命名法(命名约定 - 例如EachWordUpperCaseClassfirstWordLowerCaseMethod()firstWordLowerCaseAttribute,除非它是 UPPER_CASE_CONSTANT)并始终如一地使用它。
  • SwingWorker ProgressBar的可能重复

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


【解决方案1】:

由于 Swing 的单线程特性,您不能在 Event Dispatching Thread 的上下文中执行长时间运行或阻塞操作,也不能从 Event Dispatching Thread 的上下文之外更新 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 更新,它可以在事件调度线程上安全地做出反应

【讨论】:

  • 如果我有一个名为doThis() 的方法,在哪里添加该方法? @MadProgrammer
  • 我该怎么做?
  • 您需要更改您的代码以提供进度反馈,这不是免费的。我可能会考虑用setProgress(int)创建一个interface,创建一个从SwingWorker扩展并实现interface的自定义类,然后你可以将SwingWorker的实例传递给“工作方法”,它可以do 是调用setProgress(并且由于SwingWorker 已经有一个setProgress(int) 方法,它只会调用SwingWorkers 方法,整洁)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多