我有一个程序,需要很长时间才能加载。因此,我想开发一个启动画面,可以向用户提供有关正在加载的内容的反馈。一个带有图像,标签和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已被锁定,它不会移动,直到程序的其余部分启动它才会按预期开始移动。
我在这里缺少什么?我所做的所有搜索似乎都没有提到这个问题,大多数“自定义启动画面”实现与我自己的方式非常类似。
答案 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线程通常是来自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