什么是EDT?
Swing事件处理代码在称为事件调度线程的特殊线程上运行。大多数调用Swing方法的代码也都在此线程上运行。这是必需的,因为大多数Swing对象方法都不是“线程安全的”。所有与GUI相关的任务,必须在EDT上进行绘画过程的同时对GUI进行任何更新,这涉及将请求包装在事件中并将其处理到上
EventQueue。然后,将事件从队列中的同一队列中逐一分派,即先入先出。就是说,如果也就是说,如果
Event A排队到
EventQueue之前,
Event B则事件B将不会在事件A之前分派。
您执行的所有任务可能需要一段时间,可能会阻塞EDT,不会发生调度,不会进行任何更新,因此您的应用程序将冻结。您将不得不杀死它以摆脱这种冻结状态。
在您的程序中,除了创建您的代码
Jframe并使之从主线程可见(我们也不应该这样做):
while(true) { if (up) { player.moveUp(); } else if (down) { player.moveDown(); } repaint(); try { Thread.sleep(20); } catch (InterruptedException ex) { Logger.getLogger(Spaceshooter.class.getName()).log(Level.SEVERE, null, ex); } }您正在
repaint()从该线程发布请求,该线程紧随其后发送到睡眠状态。
SwingUtilities.invokeLater():
Swing提供了一个很好的功能
SwingUtilities.invokeLater(newRunnable(){}),repaint可以将请求发布到EDT。您要做的就是写:
SwingUtilities.invokeLater(new Runnable() { public void run() { repaint(); } });现在要提些其他事情:
- 我们不应该使用来实现GUI组件
Runnable
。创建另一个类Runnable
,在其中进行计算,然后用于SwingUtilities
发布组件更新请求。 - 我们不应该
Jframe
直接在其上进行定制绘画。Jframe是顶级组件。它更像是一个包含整个应用程序的容器。如果要自定义绘画,请使用自定义组件MyCanvas extends JComponent
。 - 我们不应该覆盖
paint()
功能。相反,paintComponent(g)
它将很好地满足我们自定义绘画的目的。 - 学习将Swing Timer类用于及时重复的GUI渲染任务。
教程资源和参考:
- 事件调度线程
- 事件队列
- 如何使用摇摆计时器
- 课程:执行自定义绘画



