具有可更新 JProgressBar 的 Java Swing 线程

发布于 2024-10-19 20:39:59 字数 1174 浏览 3 评论 0原文

首先,我最近一直在使用 Java 的并发包,但我发现了一个我遇到的问题。我想要一个应用程序,并且该应用程序可以有一个带有状态栏和加载其他数据的 SplashScreen 。所以我决定使用SwingUtilities.invokeAndWait(在此处调用splash组件)。然后,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 的线程等等。 CountDownLatch 实际上按照我想要的方式工作,但我无法更新 GUI。使用 SwingWorkers 时,invokeAndWait 基本上无效(这就是它们的目的),或者即使使用 PropertyChangedListener 也不会更新 GUI >。如果其他人有一些想法,那么很高兴听到它们。提前致谢。

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

First off I've been working with Java's Concurrency package quite a bit lately but I have found an issue that I am stuck on. I want to have and Application and the Application can have a SplashScreen with a status bar and the loading of other data. So I decided to use SwingUtilities.invokeAndWait( call the splash component here ). The SplashScreen then appears with a JProgressBar and runs a group of threads. But I can't seem to get a good handle on things. I've looked over SwingWorker and tried using it for this purpose but the thread just returns. Here is a bit of pseudo code. and the points I'm trying to achieve.

  • Have an Application that has a SplashScreen that pauses while loading info
  • Be able to run multiple threads under the SplashScreen
  • Have the progress bar of the SplashScreen Update-able yet not exit until all threads are done.

Launching splash screen

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

Splash screen construction

SplashScreen extends JFrame implements Runnable{

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

I have tried many things including SwingWorkers, Threads using CountDownLatch's, and others. The CountDownLatch's actually worked in the manner I wanted to do the processing but I was unable to update the GUI. When using the SwingWorkers either the invokeAndWait was basically nullified (which is their purpose) or it wouldn't update the GUI still even when using a PropertyChangedListener. If someone else has a couple ideas it would be great to hear them. Thanks in advance.

I actually got ready to post better code to help out and found my solution. I thank you for all who helped.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

还不是爱你 2024-10-26 20:39:59

要在后台运行一系列操作并报告进度,请使用 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 毫秒)时才会出现。

For running a series of operations in the background and reporting progress, use SwingWorker.

The background method does the background processing.
Use the publish method to post periodic status updates.
Override the process method to handle the updates (process always executes on the 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
        }
    }
};

Addendum:

This can be extended to multiple tasks, it just requires changing how you approach setting the progress bar. Here's what comes to mind:

Have an array of completion counter, one per task.

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

Start the SwingWorkers, each passed an index number. The process or done methods then call something like this to update the overall progress bar.

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

Optionally, display a JProgressBar per task.

Addendum 2:

If the tasks vary in completion time (eg, cache hit vs cache miss), you may want to investigate ProgressMonitor. It's a progress dialog that only appears if the task takes more than some (configurable, default 500ms) amount of time.

所有深爱都是秘密 2024-10-26 20:39:59

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

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

No need to call the frame inside invokeAndWait but you should update progress bar state like this.

try {
   SwingUtilities.invokeAndWait( new Runnable() {
     public void run() {
//update state of the progress bar here
     }
   });
 } catch (InterruptedException e) {
 } catch (InvocationTargetException e) { }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文