我有一个需要时间来加载所有内容的项目,因此我创建了一个启动画面,通过进度条告诉用户完全加载和显示UI需要多长时间,但我遇到了问题。
当我创建我的启动时,这会正确显示,但我会创建并初始化Principal框架,所有内容都会冻结,直到完全加载为止。
所以,我尝试使用SwingWorker
在一个线程中加载我的Principal框架(并且它可以工作)但是在未知的NullPointerException
之后并且阅读了很多我发现这是一个可怕的< / strong>想法,因为我没有在EDT中创建我的UI,所以在这里我被卡住了。
我知道我必须在事件调度线程(EDT)中进行Swing调用,并且在SwingWorkers中进行非摇摆重工作但是初始化我的主体框架的Swing组件也是一项繁重的工作,我该怎么办?
我在这里已经阅读了一些问题,特别是this,我想我明白了,但我有疑问。举个例子:
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
阅读this site说:
Swing框架管理EDT上的组件绘制,更新和事件处理程序。
创建一个新组件是Swing Call吗?如果是,如果new MainFrame()
将需要一些时间,因为项目有很多要初始化的组件,我该怎么办?
如何告诉Splash类似“程序加载50%”的内容?
Swing Call的含义是什么?如何正确使用invokeLater
和SwingWorker
?也许解决方案太明显或者已经有了答案,但我看不到它,如果是这种情况我会道歉。
谢谢!
答案 0 :(得分:3)
你走在正确的轨道上。但请勿使用invokeAndWait
(如果必须) - 请使用invokeLater
:
<强> invokeAndWait 强>
在AWT事件派发线程上执行doRun.run()同步。
<强>的invokeLater 强>
导致doRun.run()在AWT事件派发线程上执行异步。
考虑块封装doLater
在EDT线程上运行,doOutside
中包含的代码在另一个线程中调用(这就是你不阻止UI的原因):
修改强>:
正如评论中所指出的,我添加了对我将要使用的概念的解释。
doLater {
// here goes the code
}
是一个概念:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// here goes the code
}
});
和
doOutside {
// here goes the code
}
是一个概念:
new Thread(new Runnable() {
@Override
public void run() {
// here goes the code
}
}).start();
doLater {
final MainFrame m = new MainFrame();
doOutside {
// handle heavy operation
final int result = 1;
doLater {
m.setResult(result);
}
}
}
结论:以某种方式触及Swing的所有内容都必须在EDT上运行。 如果您想更新百分比:
doLater {
final MainFrame m = new MainFrame();
doOutside {
// handle progress
for(int i = 0; i < someSize; ++i) {
final int progress = i;
doLater {
m.getProgressBar().setProgress(progress);
}
}
}
}
我希望你现在明白这个概念。 SwingWorker只是做了doOutside
=== doInBackground
&amp; doLater
=== done
/ progress
顺便说一下。上面的代码是一个真实的代码:Groovy中的lookup Griffon
框架。