java Swing,如何正确更新 UI
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4921009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swing, how to properly update the UI
提问by Hectoret
What is the right way to update the UI after doing some operations on Swing?
在 Swing 上执行一些操作后,更新 UI 的正确方法是什么?
For example, after clicking a button, a method is called that may be almost instant or take some seconds. In fact, all the applicaton logic is done remotely through a web service, so it's normal to wait a little bit for the application to respond.
例如,单击按钮后,调用的方法可能几乎是即时的或需要几秒钟的时间。事实上,所有的应用逻辑都是通过一个web服务远程完成的,所以等待应用响应一点是正常的。
My eventhandler for a button may look like these:
我的按钮事件处理程序可能如下所示:
myButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
//callWebService();
//do stuff
//updateUI(); // <----- repaint? revalidate? what?
}
});
My current implementation calls the updateUI method which internally call validate() and repaint() to the parent component that holds the UI. This works, but sometimes I can see the screen flickering. Am I doing it wrong? Is there a better way to do it?
我当前的实现调用 updateUI 方法,该方法在内部将 validate() 和 repaint() 调用到保存 UI 的父组件。这有效,但有时我可以看到屏幕闪烁。我做错了吗?有没有更好的方法来做到这一点?
回答by Olivier Grégtheitroade
The right way would be to use SwingWorker, but if you want to do it manually you'll have to implement the following pattern:
正确的方法是使用 SwingWorker,但如果您想手动执行此操作,则必须实现以下模式:
@Override public void actionPerformed(java.awt.event.ActionEvent evt) {
new Thread() {
@Override public void run () {
//callWebService();
//do stuff
SwingUtilities.invokeLater(new Runnable(){
@Override public void run() {
//updateUI(); // <----- repaint? revalidate? what?
}
});
}
}.start();
}
For the repaint/revalidate question, normally call revalidate()
then repaint()
. this is, of course, only valid for component that you manually draw. For components that you reuse, just call their value change methods.
对于重绘/重新验证问题,通常调用revalidate()
then repaint()
。当然,这仅对您手动绘制的组件有效。对于您重用的组件,只需调用它们的值更改方法。
回答by Michael Berry
I'd personally use SwingWorker for this, despite some of the other comments / answers:
尽管有其他一些评论/答案,但我个人会为此使用 SwingWorker:
- Despite the fact keeping the UI responsive isn't part of the original question, it's good practice to do this anyway (I can't think of a single good reason to lock up the EDT with lengthy processing.)
- It provides a
done()
method that can be implemented which will be executed on the EDT by default when the task is complete, saving the need for manually wrapping up things ininvokeLater()
- It's more extensible, providing the framework to allow information like progress to be added easily later if it's so desired.
- 尽管保持 UI 响应不是原始问题的一部分,但无论如何这样做是一个很好的做法(我想不出一个很好的理由来通过冗长的处理来锁定 EDT。)
- 它提供了一个
done()
可以实现的方法,当任务完成时默认会在EDT上执行,省去了手动打包东西的需要invokeLater()
- 它更具可扩展性,提供了一个框架,允许以后在需要时轻松添加进度等信息。
I've seen a lot of SwingWorker hate in general recently, and I don't understand why. It's a nicely designed, extensible class specifically for purposes such as this that works well. Yes, you could wrap things up in threads and launch them and have them wrap other methods up in invokeLater()
, but why reinvent the wheel when there's a better one available for free?
我最近看到很多 SwingWorker 的仇恨,我不明白为什么。这是一个设计精美、可扩展的类,专门用于此类目的,效果很好。是的,您可以将事物封装在线程中并启动它们并让它们将其他方法封装在invokeLater()
.
回答by Tom Hawtin - tackline
Take the long running task to a different thread. Send events back to the AWT Event Dispatch Thread (EDT) to update the GUI with java.awt.EventQueue.invokeLater
.
将长时间运行的任务转移到不同的线程。将事件发送回 AWT 事件调度线程 (EDT) 以使用java.awt.EventQueue.invokeLater
.
回答by JB Nizet
You shouldn't normally have to do anything : if you use the swing components methods, or the methods of their model, the necessary events are fired and the GUI should update itself automatically.
您通常不需要做任何事情:如果您使用摆动组件方法或其模型的方法,则会触发必要的事件并且 GUI 应自动更新自身。
This won't be the case if you define your own models (and forget to fire the necessary events, but then it's a bug in your models, and it should be fixed there.
如果您定义自己的模型(并且忘记触发必要的事件,但它是模型中的一个错误,应该在那里修复它),情况就不会如此。