5

我有一个程序,需要很长时间才能加载。正因为如此,我想开发一个闪屏,它可以向用户提供关于正在加载的内容的反馈。一个带有图像、标签和 JProgressBar 的简单 JFrame。

我一直在试验,我得到的最好结果是在我的main()

SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

        new SplashScreen();
    }
});

SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

        //Code to start system
        new MainFrame();
        //.. etc
    }
});

SplashScreen 和 MainFrame 都是扩展 JFrame 的类。我也使用物质作为图书馆。

SplashScreen 的构造函数将 JLabel 和 JProgressBar 添加到自身,打包和设置可见。JProgressBar 是setIndeterminate(true)

当我运行我的程序时,我的 SplashScreen 被显示,但 ProgressBar 被锁定,它不会移动,直到程序的其余部分开始它才开始按预期移动。

我在这里想念什么?我所做的所有搜索似乎都没有提到这个问题,而且大多数“自定义启动屏幕”实现的方式与我自己非常相似。

4

4 回答 4

3

invokeAndWait 将冻结 Swing 线程,直到给定的操作完成。因此,在创建 MainFrame 之前,您的进度条将 100% 保持不变。

您应该使用 SwingUtilities.invoke(Later|AndWait) 生成一个更新启动画面的非摆动线程。

new Thread(new Runnable() { public void run() {
  // Create MainFrame here
  SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         updateProgressHere();
      }
  });

  // Do other initialization
  SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         updateProgressHere();
      }
  });
}).start(); 
于 2010-03-01T18:38:26.070 回答
3

只是试图比艾伦的正确答案更笼统。

您的系统中有一个线程可以(合法地)更新 GUI。

如果您使用该线程来初始化您的系统,guis 将不会更新。

如果你试图从你的主线程更新你的 GUI,那么一切都不会正确。

始终注意您的 GUI 在哪个线程上,并确保不要在该线程上工作。

以这种方式考虑 GUI 更新:

  • 您的非 gui 线程会更新您正在显示的值(例如完成百分比)。
  • 它通过 invokeLater 发布更新,然后继续其他工作。
  • GUI 线程执行您的 invokeLater,它使用从非 GUI 线程传递的数据更新您的 GUI
  • 它退出的GUI线程!这允许系统的其他不相关部分在需要时更新 GUI。

非 GUI 线程通常是来自 Thread.start 的线程,并且是传递给“main”的线程

GUI 线程是执行您的“invokeLater”以及从 GUI 事件(按下按钮、GUI 计时器、任何 Swing 侦听器)传递给您的任何内容的线程。

正因为如此,当需要更新 GUI 时,您通常已经在 GUI 线程上——只需注意启动顺序和线程想要更​​新显示的位置。

于 2010-03-01T19:40:24.560 回答
1

其他人提到了为什么你的进度条被阻止了,我会建议一个替代解决方案 Java6在 javaw 和 java 启动器中内置了闪屏处理......

启动画面甚至在 JVM 和应用程序的类加载之前就显示出来,然后一旦启动,应用程序就可以更新它以反映其内部加载状态,并在准备好时关闭它。

或者,对于仅限 Windows 的解决方案,Winrun4J java 启动器还具有启动屏幕功能。

于 2010-03-01T19:27:25.177 回答
1

其他答案已经涵盖了大部分内容,但简而言之,您的问题是您正在 Swing 事件调度线程中运行“启动系统的代码”。所有与 GUI 相关的代码(包括组件创建)都必须在 EDT 上运行,但所有其他代码不应在 EDT 上运行。尝试改变你的程序来做到这一点:

SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        new SplashScreen();
    }
});
// Code to start system (nothing that touches the GUI)
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        new MainFrame();
    }
});
//.. etc
于 2010-03-02T16:39:20.927 回答