使用可更新JProgressBar的Java Swing线程

时间:2011-03-02 04:47:14

标签: java multithreading swing concurrency swingworker

首先,我最近一直在使用Java的Concurrency软件包,但是我发现了一个问题,我被困在了。我想拥有,应用程序和应用程序可以有SplashScreen状态栏和其他数据的加载。所以我决定使用SwingUtilities.invokeAndWait( call the splash component here )。然后SplashScreen出现JProgressBar并运行一组线程。但我似乎无法很好地处理事情。我查看了SwingWorker并尝试将其用于此目的,但线程只是返回。这是一些伪代码。以及我正在努力实现的目标。

  • 拥有SplashScreen在加载信息时暂停的应用
  • 能够在SplashScreen
  • 下运行多个主题
  • SplashScreen更新的进度条在所有线程完成之前都不会退出。

启动启动画面

try {
    SwingUtilities.invokeAndWait( SplashScreen );
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }

启动画面构建

SplashScreen extends JFrame implements Runnable{

    public void run() {
        //run threads
        //while updating status bar
    }
}

我尝试过很多东西,包括SwingWorkers,使用CountDownLatch的Threads等等。 CountDownLatch实际上以我想要处理的方式工作但我无法更新GUI。使用SwingWorkers时,invokeAndWait基本上无效(这是他们的目的),或者即使使用PropertyChangedListener也不会更新GUI。如果其他人有一些想法,那么听听他们会很棒。提前谢谢。

我实际上已准备好发布更好的代码来帮助并找到我的解决方案。感谢所有帮助过的人。

2 个答案:

答案 0 :(得分:5)

要在后台运行一系列操作并报告进度,请使用SwingWorker

background方法执行后台处理 使用publish方法发布定期状态更新 覆盖process方法来处理更新(process总是在EDT上执行)。

progressBar = new JProgressBar();
sw = new SwingWorker<Boolean,Integer>() {
    protected Boolean doInBackground() throws Exception {
        // If any of the operations fail, return false to notify done() 
        // Do thing 1
        publish(25);  // 25% done
        // Do thing 2
        publish(50);  // 50% done
        // Do thing 3
        publish(75);  // 75% done
        // Do thing 4
        return true;
    }
    protected void process(List<Integer> chunks) {
        for (Integer i : chunks)
            progressBar.setValue(i);
    }
    protected void done() {
        try {
            boolean b = get();
            if (b)
                progressBar.setValue(100); // 100% done
            else
                // Notify the user processing failed
        }
        catch (InterruptedException ex) {
                // Notify the user processing was interrupted
        }
        catch (ExecutionException ex) {
                // Notify the user processing raised an exception
        }
    }
};

<强>附录:

这可以扩展到多个任务,只需要更改设置进度条的方法。这就是我想到的:

有一个完成计数器数组,每个任务一个。

int[] completions = new int[numTasks];
Arrays.fill(completions,0);

启动SwingWorkers,每个都传递一个索引号。然后,processdone方法会调用此类内容来更新整体进度条。

void update(int index, int percComplete) {
    completions[index] = percComplete;
    int total = 0;
    for(int comp: completions)
        total += comp/numTasks;
    overallPB.setValue(total);
}

(可选)显示每个任务的JProgressBar。

附录2:

如果任务的完成时间不同(例如,缓存命中与缓存未命中),您可能需要调查ProgressMonitor。这是一个进度对话框,仅当任务需要超过一些(可配置的,默认的500毫秒)时间时才会出现。

答案 1 :(得分:0)

无需在invokeAndWait中调用框架,但您应该像这样更新进度条状态。

try {
   SwingUtilities.invokeAndWait( new Runnable() {
     public void run() {
//update state of the progress bar here
     }
   });
 } catch (InterruptedException e) {
 } catch (InvocationTargetException e) { }