Java GUI - 在异步任务完成之前,进度条不会更新

时间:2021-05-11 21:31:35

标签: java swing user-interface event-dispatch-thread jprogressbar

我正在使用 CompletableFuture 运行长时间运行的操作。同时,我使用 SwingWorker 以 5 为增量更新进度条。

namespace petShelter.Models
{
    public class PetShelterContext : DbContext
    {
        public PetShelterContext(DbContextOptions options) : base(options) { }

        public DbSet<Pet> Pets { get; set; }
        public DbSet<Owner> Owners { get; set; }

    }
}

在异步方法完成之前,进度条不会更新。我也试过在EDT线程上做这个操作,但是没有用。你所看到的基本上是我在这一点上只是尝试试错。

为什么进度条没有更新?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

停下来仔细看看Worker Threads and SwingWorker

SwingWorker 旨在允许您执行长时间运行的任务,这可能会产生中间结果,并允许您publish 将这些结果返回到事件调度线程以进行安全处理(通过process 方法)。

您“可以”publishprocess 方法中更新进度并更新进度条,但是 SwingWorker 已经提供了一个 progress 属性,您可以对其进行监控。查看 SwingWorker JavaDocs 中的许多现成示例!

运行示例

Simple Example

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;

public 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 ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                ProgressPane progressPane = new ProgressPane();
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(progressPane);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

//                progressPane.doWork();
            }
        });
    }

    public class ProgressPane extends JPanel {

        private JProgressBar progressBar;
        private JButton startButton;

        public ProgressPane() {

            setLayout(new GridBagLayout());
            progressBar = new JProgressBar();

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(progressBar, gbc);
            startButton = new JButton("Start");
            gbc.gridy = 1;
            add(startButton, gbc);

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

        }

        public void doWork() {

            Worker worker = new Worker();
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("progress".equals(evt.getPropertyName())) {
                        progressBar.setValue((Integer) evt.getNewValue());
                    }
                }
            });

            worker.execute();

        }

        public class Worker extends SwingWorker<Object, Object> {

            @Override
            protected void done() {
                startButton.setEnabled(true);
            }

            @Override
            protected Object doInBackground() throws Exception {

                for (int index = 0; index < 1000; index++) {
                    int progress = Math.round(((float) index / 1000f) * 100f);
                    setProgress(progress);

                    Thread.sleep(10);
                }

                return null;
            }
        }
    }
}

答案 1 :(得分:0)

这将更新进度条,但由于 SwingWorker 不断循环,它会立即达到 100%。

您应该通过轮询任务或(更好地)使用观察者模式从异步任务中获取实际进度值。

后一种情况可以去掉swing worker,直接在observer回调方法中更新进度条。

    SwingWorker worker = new SwingWorker() {
        @Override
        protected Object doInBackground() throws Exception {
            int val = 0;
            while (!completableFuture.isDone()) {
                if (val < 100) {
                    val += 5;
                    
                    final int prog=val;
                    SwingUtilities.invokeLater(()->{progressBar.setValue(prog); });
                }
            }
            return null;
        }
    };

这是一个完整的观察者模式示例,我使用 PropertyChangeSupport 定义了一个可观察类 ALongTask,该任务将其进度值通知给所有注册的观察者(即 PropertyChangeListener)。

package test;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

public class TestProgressBar {


    public static void main(String[] args) {
        JProgressBar progressBar = new JProgressBar();
        progressBar.setMinimum(0);
        progressBar.setMaximum(100);
        progressBar.setValue(0);
        progressBar.setStringPainted(true);
        ALongTask asyncTask=new ALongTask();
        asyncTask.addPropertyChangeListener((e)-> { SwingUtilities.invokeLater(()->{progressBar.setValue((Integer) e.getNewValue()); }); });

        CompletableFuture.supplyAsync(asyncTask);

        JFrame frame=new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(progressBar);
        frame.pack();
        frame.setVisible(true);
    }
    
    public static class ALongTask implements Supplier<Object> {
        PropertyChangeSupport support=new PropertyChangeSupport(this);
        protected int progress;
        
        public void setProgress(int progress) {
            int old=this.progress;
            this.progress=progress;
            support.firePropertyChange("progress", old, progress);
        }
        
        public void addPropertyChangeListener(PropertyChangeListener l) {
            support.addPropertyChangeListener(l);
        }
        
        public void removePropertyChangeListener(PropertyChangeListener l) {
            support.removePropertyChangeListener(l);
        }

        @Override
        public Object get() {
            for (int i=0;i<20;i++) {
                setProgress(i*5);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    return null;
                }
            }
            setProgress(100);
            return new Object();
        }
    }
}
相关问题