Java - 如何将 JProgressBar 与 SwingWorker 一起使用

Posted

技术标签:

【中文标题】Java - 如何将 JProgressBar 与 SwingWorker 一起使用【英文标题】:Java - How to use JProgressBar with SwingWorker 【发布时间】:2013-10-14 16:52:22 【问题描述】:

我正在创建一个带有下载器的 Java 应用程序。我的问题是,进度条不起作用。我希望我的进度条显示下载进度但失败了。这是我的代码的一部分。进度条刚刚停留在 0%...

下载.class

public void startDownload()

    ExecutorService executor = Executors.newSingleThreadExecutor();
    FutureTask<Void> verDownloader = new FutureTask<Void>(vd);
    FutureTask<Void> launcher = new FutureTask<Void>(dd);
    executor.execute(verDownloader);
    executor.execute(launcher);
    executor.shutdown();
 

VersionDownloader.class

public class VersionDownloader implements Callable<Void>, PropertyChangeListener

    @Override
    public Void call() throws Exception
    
                    done = false;
                    final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
                    
                        @Override
                        protected Void doInBackground() throws Exception
                        
                            try
                            
                                URL fileURL = new URL(url);
                                org.apache.commons.io.FileUtils.copyURLToFile(fileURL, path);
                            
                            catch(Exception e)
                            

                            
                            return null;
                        

                        @Override
                        public void done()
                        
                            done = true;

                            try
                            
                                Thread.sleep(1000);
                            
                            catch (InterruptedException e)
                            
                                e.printStackTrace();
                            
                        

                    ;
                    worker.execute();
                    worker.addPropertyChangeListener(this);
                    worker.get();
                
            
        
        catch(Exception e)
        

        
        return null;
    

    @Override
    public void propertyChange(PropertyChangeEvent evt)
    
        if(!done)
        
            int progress_a = progress;
            //launcher.frame.progress is a JProgressBar
            launcher.frame.progress.setValue(progress_a);
        
    



是不是代码错了?

【问题讨论】:

【参考方案1】:

这类事情并不像听起来那么简单。 copyURLToFile() 将阻塞直到复制完成,所以只会给你两个事件 - 0% 和 100%。

如果您想在下载时显示进度,有一个先决条件:您必须在下载开始前知道文件长度(以便计算百分比)。您可以通过在开始复制之前发出 HTTP HEAD 请求来得到它 - 也许 - 但是响应中是否存在 Content-Length 字段取决于服务器 - 对于分块编码,您不会得到此信息(尽管您也许可以通过发出 HTTP 1.0 请求来强制某些服务器告诉您)。否则,您可以作弊并选择任意数量的字节。

一旦有了长度或近似值,您就可以

运行计时器并定期检查到目前为止下载的字节数,并将其与大小进行比较,或者 以InputStream 形式打开网址并执行您自己的循环以复制字节,并在每次循环迭代时更新进度条

无论哪种方式,请确保您使用EventQueue.invokeLater() 更新进度条的value 属性,否则您可能会遇到死锁问题 - 从除事件线程之外的任何线程修改 Swing 组件都是不安全的。

【讨论】:

文件长度=文件大小?我的下载器会解析一个 XML 文件,获取 XML 文件中URL 的内容,然后使用 Common-IO 下载。 是的,文件长度 = 文件大小。 HTTP 协议允许以两种方式发送文件 - 老式的 HTTP 1.0 下载,其中 Content-Length 标头告诉您在下载之前将下载多少字节。 HTTP 1.1 提供“分块”编码,服务器不断传递小块字节,每个字节前面都有该块中的字节数。在这种情况下,您不知道要下载的文件多长时间。所以对于分块编码,你不知道你会得到多少字节。如果您知道平均大小,您可以猜测它...... 但无论如何,如果您想显示实际进度 - 您完成了多少百分比 - 您需要某种方式在下载过程中收听并更新它。您始终可以在进度条上执行“不确定”模式,在这种情况下,不需要准确知道还有多少字节要下载。 很难为我的文件使用 InputStream 因为我必须做很多 mkdir 之类的。这就是我使用 Common-IO 的原因。你能给我一些示例代码吗?我的 XML 文件也有每个文件的&lt;Size&gt;【参考方案2】:

阅读 How to Use Progress Bars 上的 Swing 教程部分,了解使用 SwingWorker 的工作示例。

从可行的东西开始,然后根据您的特定要求进行更改。如果您仍有问题,请发布 SSCCE 来说明问题。

【讨论】:

以上是关于Java - 如何将 JProgressBar 与 SwingWorker 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

如何将JProgressbar绑定到Bean类的属性

Java Swing 之Timer配合JProgressBar的使用

如何在 jprogressbar 上添加文本?

JTable的TableColumn添加多个JProgressBar

进度条控件JProgressBar的使用

准确汇总文件大小以在 JProgressBar 中使用