如何在加载 Swing 并构建 GUI 时更新/绘制 JProgressBar
我有一个 GUI,在它运行的平台上构建/初始化非常繁重。因此我想在初始化时更新进度。
我有一个未装饰的小型 JDialog,其中包含 JLabel 和 JProgressBar,我想在以下位置更新它:然而,在初始化期间的特定位置,因为事件调度头(根据 Swing 规则)用于构建/初始化 GUI,所以进度当然不会更新,直到 EDT 再次空闲(即初始化完成)
。 JProgressBar 我已经使用“paintImmediately”进行重绘,但我似乎无法使其对 JLabel 和对话框本身正常工作。是否有任何简单的推荐/经过验证的方法来完成此操作?
干杯...
编辑:添加一个我正在尝试做的事情的例子;当然,大大简化了。
private JLabel progressLabel;
private JProgressBar progressBar;
public static int main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showProgressDialog();
progressLabel.setText("construct 1");
constructSomeHeavyGUI();
progressLabel.setText("construct 2");
progressBar.setValue(33);
constructSomeMoreHeavyGUI();
progressLabel.setText("construct 3");
progressBar.setValue(67);
constructEvenMoreHeavyGUI();
progressLabel.setText("done");
progressBar.setValue(100);
hideProgressDialog();
showHeavyGUI();
}
});
}
只要 EDT 繁忙并导致重绘,上面调用 progressBar.setValue()
/progressLabel.setText()
引起的重绘当然就会排队当我们全部完成之后,而不是一路更新..
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我建议通过使用 SwingWorker ,然后您可以更新JProgressBar 在 EDT 上正确,并且没有任何冻结或问题 Swing 中的并发,
还有另一种选择,即使用
Runnable#thread
,但随后您必须将 GUI 的所有输出包装到invokeLater();
例如:
编辑:
1)您展示了另一个问题,为什么要在运行时创建大量顶级容器,仅创建所需数量的容器并通过
removeAll()
重新使用它2)这里可能就是你所需要的,全部那些 JTable 中的 noreferrer">JProgressBars 是非常易于访问且可配置
3) 这是您的 paintImmediately(),这就是为什么不绘制任何 Progress 到 JLabel 但使用
JProgressBar#setValue(int);
相反,
I would suggest that by using SwingWorker , then you can update the JProgressBar correctly on EDT and without any freeze or isuees with Concurency in Swing,
there is another option by using
Runnable#thread
, but then you have to wrapp all output to the GUI intoinvokeLater();
for example:
EDIT:
1) you showed another issues, why do you create lots of Top-Level Containers on Fly/Runtime, create only required numbers of Containers and re-use that by
removeAll()
2) here is probably what you needed, all those JProgressBars in the JTable are pretty accesible and configurable
3) this is your paintImmediately(), that really reason why not painting any of Progress to the JLabel but using
JProgressBar#setValue(int);
instead,可能
constructSome*HeavyGUI()
确实需要足够长的时间才能产生影响,但更很可能是填充数据模型才是问题所在。相反,构建并显示空 GUI 元素并启动一个或多个SwingWorker
实例来编组每个元素的数据。有相关示例这里< /a> 和 这里。附录:如果问题是实例化组件,而不是加载数据模型,您可以将调用链接到
invokeLater()
,如下面评论中的建议。如果您要实例化那么多组件,请考虑flyweight 模式 。JTable
这是一个熟悉的例子。It's possible that
constructSome*HeavyGUI()
really takes long enough to matter, but it's more likely that filling in the data model(s) is the problem. Instead, construct and show the empty GUI elements and launch one or moreSwingWorker
instances to marshal each element's data. There are related examples here and here.Addendum: If the problem is instantiating components, and not loading data models, you can chain the calls to
invokeLater()
, as suggested in a comment below. If you're instantiating that many components, consider the flyweight pattern.JTable
is a familiar example.将长时间运行的代码移至单独的线程中,并使用 SwingUtilities.invokeAndWait 或 invokeLater 来更新 GUI。
Move the long running code in a separate thread and use SwingUtilities.invokeAndWait or invokeLater to update GUI.
使用
SwingUtilities.invokeLater(...)
按照@StanislavL ,或使用 SwingWorker。另请参阅:
Either use
SwingUtilities.invokeLater(...)
as suggested by @StanislavL, or use SwingWorker.See also: