自定义Java启动屏幕“冻结”,直到整个应用程序加载完毕

时间:2010-03-01 18:33:06

标签: java swing splash-screen

我有一个程序,需要很长时间才能加载。因此,我想开发一个启动画面,可以向用户提供有关正在加载的内容的反馈。一个带有图像,标签和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的类。我也使用Substance作为图书馆。

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

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

我在这里缺少什么?我所做的所有搜索似乎都没有提到这个问题,大多数“自定义启动画面”实现与我自己的方式非常类似。

4 个答案:

答案 0 :(得分:3)

invokeAndWait将冻结Swing线程,直到它给出的操作完成。因此,在创建MainFrame之前,您的进度条将为100%forfor。

你应该使用SwingUtilities.invoke(稍后| AndWait)生成一个更新Splash Screen的非swing线程。

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(); 

答案 1 :(得分:3)

试图比Allain的正确答案更加通用。

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

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

如果您尝试从主线程更新GUI,那么任何事情都不会正确。

始终注意GUI所在的线程,并确保不在该线程上工作。

以这种方式考虑GUI更新:

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

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

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

因此,在更新GUI时,大多数情况下您已经在GUI线程上了 - 只需注意启动顺序以及线程想要更​​新显示的位置。

答案 2 :(得分:1)

其他人已经提到了为什么你的进度条被阻止了,我会建议一个替代解决方案Java6对javaw和java启动器有splash screen handling built in ......

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

或者,对于仅限Windows的解决方案,Winrun4J java launcher也具有启动画面功能。

答案 3 :(得分: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