自定义 Java 启动屏幕“冻结”直到整个应用程序加载完毕
我有一个程序,需要很长时间才能加载。因此,我想开发一个闪屏,可以向用户提供有关正在加载的内容的反馈。一个带有图像、标签和 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 是setIndependent(true)
;
当我运行我的程序时,会显示我的 SplashScreen,但 ProgressBar 被锁定,它不会移动,直到程序的其余部分启动后它才会开始按预期移动。
我在这里缺少什么?我所做的所有搜索似乎都没有提到这个问题,并且大多数“自定义启动屏幕”实现都以与我自己非常相似的方式来解决这个问题。
I have a program, that takes a long time to load. Because of this, I wanted to develop a splash screen that can provide feedback to the user on what is being loaded. A simple JFrame with an image, label and JProgressBar.
I have been experimenting and the best results I've had are doing this in my main()
:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new SplashScreen();
}
});
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
//Code to start system
new MainFrame();
//.. etc
}
});
Both SplashScreen and MainFrame are classes extending JFrame. I am also using Substance as a Library.
SplashScreen's constructor adds a JLabel and JProgressBar to itself, packs and sets visible.
The JProgressBar is setIndeterminate(true)
;
When I run my program, my SplashScreen is displayed but the ProgressBar is locked, it doesn't move, not until the rest of the program has started does it start moving as expected.
What am I missing here? All searching I've done doesn't seem to mention this problem and most "custom splash screen" implementations go about it a very similar way to myself.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
只是为了尝试比阿兰的正确答案更笼统一点。
您的系统中有一个线程可以(合法)更新 GUI。
如果您使用该线程来初始化系统,则 guis 将不会更新。
如果您尝试从主线程更新 GUI,则一切都不会顺利。
始终注意您的 GUI 所在的线程,并确保不要在该线程上执行工作。
以这种方式考虑 GUI 更新:
非 GUI 线程通常是来自 Thread.start 的线程以及传递给“main”的线程。
GUI 线程是执行“invokeLater”以及从 GUI 事件传递给您的任何内容(按下按钮、GUI 计时器、任何 Swing 侦听器)的线程。 .)
因此,大多数情况下,当需要更新 GUI 时,您已经处于 GUI 线程中——只需注意启动顺序以及线程想要更新显示的位置即可。
Just to attempt to be a little more general than Allain's correct answer.
There is one thread in your system that can (legally) update GUIs.
If you are using that thread to initialize your system, guis will NOT update.
If you are trying to update your GUI from your main thread, nothing will go right.
Always be aware of which thread your GUI is on and be sure not to be doing work on that thread.
Think of GUI updates in this way:
Non-GUI threads are most often threads from Thread.start and the one passed to "main"
The GUI thread is the one executing your "invokeLater" and anything passed to you from a GUI event (button pressed, GUI timer, any Swing listeners.)
Because of this, most often you are already on the GUI thread when it's time to update the GUI--just watch out for startup sequencing and places where threads want to update the display.
invokeAndWait 将冻结 Swing 线程,直到给定的操作完成。因此,在创建 MainFrame 之前,您的进度条将 100% forzen。
您应该生成一个非 Swing 线程,使用 SwingUtilities.invoke(Later|AndWait) 更新启动屏幕。
invokeAndWait will freeze the Swing thread until the operation it is given completes. So, your progress bar will be 100% forzen until the MainFrame is created.
You should spawn a non-swing thread that updates the Splash Screen using SwingUtilities.invoke(Later|AndWait).
其他答案已经涵盖了大部分内容,但简而言之,您的问题是您正在 Swing 事件调度线程中运行“启动系统的代码”。所有与 GUI 相关的代码(包括组件创建)必须在 EDT 上运行,但所有其他代码不应在 EDT 上运行。尝试更改您的程序来执行此操作:
Other answers have covered most of this but in brief your problem is that you are running the "Code to start system" in the Swing event dispatch thread. All GUI-related code (including component creation) must be run on the EDT but all other code should not be run on the EDT. Try changing your program to do this:
其他人提到了为什么你的进度条被阻止,我会建议一个替代解决方案 Java6 有 javaw 和 java 启动器中内置的启动画面处理...
启动画面甚至在 JVM 和应用程序的类加载之前就会显示,然后一旦启动,应用程序就可以更新它以反映其内部加载状态,准备好后关闭。
或者,对于仅限 Windows 的解决方案,Winrun4J java 启动器 还具有启动屏幕功能。
Others have mentiones why your progress bar is blocked, I will suggest an alternative solution Java6 has splash screen handling built in to the javaw and java launchers...
The splash screen is displayed even before the JVM and the application's classes are loaded, and then once started the application can update it to reflect its internal loading state, and close it when ready.
Alternatively, for windows-only solutions, the Winrun4J java launcher also has a splash screen feature.