基本不确定进度条的使用方法

6

当进行长时间下载时,我希望在框架的左下角有一个不确定进度条进行动画展示。

我查看了许多教程,但都不清楚。我只是想在后台下载文件时让它动起来。我尝试的每种方式,在下载完成之前都不能使进度条动起来。

我需要帮助知道在哪里放置我的download()调用。

class MyFunClass extends JFrame {
  JProgressBar progressBar = new JProgressBar();

  public void buttonClicked() {
    progressBar.setVisible(true);
    progressBar.setIndeterminate(true);

    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        progressBar.setIndeterminate(true);
        progressBar.setVisible(true);

        // Do I do my download() in here??

    }});

    // Do download() here???
    progressBar.setVisible(false);
  }
}

提前感谢您!



解决方案

编辑:对于将来遇到类似问题的人,这是解决基本问题的基本解决方案。这不是我的原始代码,而是一个概要。在buttonClicked()中:

public void buttonClicked() {
  class MyWorker extends SwingWorker(String, Object) {
     protected String doInBackground() {
       progressBar.setVisible(true);
       progressBar.setIndeterminate(true);

       // Do my downloading code
       return "Done."
     }

     protected void done() {
        progressBar.setVisible(false)
     }
  }

  new MyWorker().execute();

}

尽管看起来很复杂,但你应该查看http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html。你需要做的是在另一个线程(backgroundworker)中运行下载。然后主(gui)线程执行progressBar动画。你现在所做的实际上是相反的方式。 - user845279
1
请查看我的回答的编辑2以纠正一些问题。 - Hovercraft Full Of Eels
1个回答

10
您当前的代码没有创建后台线程,而是在Swing线程中尝试将代码排队从内部的Swing线程,对于此问题来说这是没有意义的(尽管偶尔可能需要这样做,但在这种情况下不是)。唯一成功的方法是使用后台线程。标准的Oracle JProgressBar教程Swing并发性都涵盖了所有这些内容。
基本的事情是,在后台线程中执行长时间运行的进程(例如由SwingWorker对象提供的进程),同时必须从Swing线程更新JProgressBar。要求我们回顾所有细节太多了,所以我能做的就是提供一个链接,但如果您仍然卡住,请查看教程,然后带着具体问题回来寻求帮助。 编辑1 您说:

我能否在buttonClicked()函数中只创建一个新的线程对象?

是的,您可以在buttonClicked() 方法中创建一个SwingWorker对象并在那里执行它。

问题是我有我的API和库,其中包含我正在开发GUI的所有功能,而将该函数调用包装在线程中似乎是一个冗长的解决方法。

很抱歉,我不知道您在这里说什么或者您认为线程会引起什么问题。buttonClicked() 方法可能必须在EDT上运行,而不是在后台线程中运行。此外,请注意,在我更复杂的Swing GUI中,我经常在不同的对象(控制器)中进行文件下载,并从GUI对象(视图)中创建SwingWorker的不同对象(模型)。这样做可能看起来更复杂,但当我使用接口允许我将所有程序组件隔离测试时,它就更容易调试、维护和增强我的程序了。

编辑2 对您的解决方案帖子进行一些更正。您发布了:

public void buttonClicked() {
  class MyWorker extends SwingWorker(String, Object) {
     protected String runInBackground() {
       progressBar.setVisible(true);
       progressBar.setIndeterminate(true);

       // ...

存在问题

  • 应该使用doInBackground()而不是runInBackground()
  • 但更重要的是,您正在从后台线程中进行Swing调用,这是绝不能做的事情(除非调用是线程安全的,即使如此也...)。

所以修改它:

public void buttonClicked() {
  progressBar.setVisible(true);
  progressBar.setIndeterminate(true);
  class MyWorker extends SwingWorker<String, Void> {
     protected String doInBackground() {

       // ...

我能否在buttonClicked()函数内部创建一个新的线程对象?问题是,我有我的API和所有功能的库,我正在开发GUI,似乎将该函数调用包装在线程中是一个冗长的解决方法。 - Bill
非常感谢您迄今为止的时间。我正在按照这种方法进行,并且一旦我使其正常工作,就会标记答案为已接受。构建一个简单GUI以配合我完好的协议库,结果需要比我最初想象的更多的时间和代码,这让我有点失落。 - Bill
@B.VB:这确实令人沮丧,但在任何语言中都是不可避免的。如果您希望GUI保持响应,则不能干扰与用户交互或绘制GUI的线程,因此必须进行后台线程处理。 - Hovercraft Full Of Eels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接