2

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

  • 有一个SplashScreen在加载信息时暂停的应用程序
  • 能够在多个线程下运行SplashScreen
  • 在所有线程完成之前,让 Update-able的进度条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 的线程等。CountDownLatch 实际上以我想要处理的方式工作,但我无法更新 GUI。使用时,SwingWorkers要么invokeAndWait基本上无效(这是他们的目的),要么即使使用PropertyChangedListener. 如果其他人有一些想法,很高兴听到它们。提前致谢。

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

4

2 回答 2

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,每个都传递一个索引号。processordone方法然后调用类似这样的方法来更新整体进度条。

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 毫秒)时间时才会出现。

于 2011-03-02T18:30:16.010 回答
0

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

try {
   SwingUtilities.invokeAndWait( new Runnable() {
     public void run() {
//update state of the progress bar here
     }
   });
 } catch (InterruptedException e) {
 } catch (InvocationTargetException e) { }
于 2011-03-02T07:20:46.720 回答