我对线程和GUI非常新鲜,因此我无法确切地知道在哪里调用这个EventQueue.invokeLater()
方法。
我是否应该在每个事件监听器和其他事件中调用它?调用这种方法的那些“东西”是什么?如果是这样,是否有任何替代方法来调用一次应用到处方法,以便它不需要一堆行来将它们塞进Event调度线程?
谢谢。
答案 0 :(得分:2)
因此我无法确切地知道在哪里调用此EventQueue.invokeLater()方法。
需要在EDT上更新Swing组件,因此如果您在单独的Thread中执行代码并且想要更新GUI组件,则只能使用invokeLater(...)。
阅读Concurrency上的Swing教程中的部分以获取更多信息。
作为一般规则,除非您使用线程,否则只需在创建GUI时使用此方法。请参阅How to Make Frames上Swing教程中的FrameDemo
部分,了解一个简单的示例,以帮助您入门。
我是否应该在每个事件监听器中调用它?
没有!
事件处理程序中的所有代码都已在Event Dispatch Thread (EDT)
上执行,因此您无需调用此方法。
答案 1 :(得分:1)
Swing不是线程安全的。这意味着所有与Swing对象的交互都应该通过事件线程来完成。 Swing也在内部执行此操作,因此每当Swing调用事件侦听器时,都将在事件线程上完成。
这意味着两件事,首先,如果您需要与Swing对象进行交互,则应在事件调度程序线程上调用您的代码。
此外,这意味着如果您的事件侦听器中的任何代码将在任何明显的时间段内运行,则应在侦听器的另一个线程上调用。如果您不这样做,那么您的UI将显示为冻结。 SwingWorker
对象可以帮助解决此问题。
答案 2 :(得分:0)
要回答有关需要检查您在某些现有答案中提出的EventQueue.isDispatchThread()
评论的问题:
不,在致电invokeLater()
之前,您无需检查您是否已经在EDT上。
如果从事件调度线程调用invokeLater - 例如,从JButton的ActionListener调用 - doRun.run()仍将延迟,直到处理完所有挂起事件。请注意,如果doRun.run()抛出未捕获的异常,则事件调度线程将展开(而不是当前线程)。
以下是invokeLater()
使用的进一步说明。
请注意ButtonDemo.java中使用invokeLater()调用createAndShowGUI()。我们必须这样做,因为main()方法没有在EDT(事件调度线程)上运行。 main()在每个Java应用程序都有自己的特殊主线程上运行。
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
但是在actionPerformed()
中,未使用invokeLater()
方法,因为我们已经在EDT上了。
//b1, b2, and b3 are all JButtons
public void actionPerformed(ActionEvent e) {
if ("disable".equals(e.getActionCommand())) {
b2.setEnabled(false);
b1.setEnabled(false);
b3.setEnabled(true);
} else {
b2.setEnabled(true);
b1.setEnabled(true);
b3.setEnabled(false);
}
}
据我所知,事件监听器方法如actionPerformed()
总是从EDT调用。 (对不起,我手边还不知道支持文档,而且我还没有足够的声誉来发布任何链接。除了阅读camickr的答案中链接的页面,请尝试谷歌搜索“java教程摇摆介绍事件监听器” 。)
因此,如果您尝试从EDT以外的线程更新Swing组件,请调用invokeLater()
。如果您使用事件监听器方法(即已在EDT上),则无需致电invokeLater()
。