我有一个线程,它通过使用SwingUtilities.invokeLater在我的JFrame上显示更新。线程的速度是可调的,当它设置为全速(更新之间没有睡眠)时,我的程序变得非常慢。我想问题是我的线程生成了太多的SwingUtilities.invokeLater事件,JFrame的线程无法使用。那么我可以在我的线程上做些什么来删除以前添加但未消耗的事件?或者我应该使用其他方法来更新JFrame而不使用SwingUtilities.invokeLater?
提前致谢。
答案 0 :(得分:4)
SwingWorker
这可能是一个完美的工作。您可以发布增量更新,SwingWorker
将批处理以解决性能问题:
因为在Event Dispatch Thread上异步调用了process方法,所以在执行process方法之前可能会对publish方法进行多次调用。出于性能目的,所有这些调用都合并为一个带有连接参数的调用。
您希望在EDT上运行的代码,您可以通过实施process()
来添加。更新列表将在参数中传递给您。
答案 1 :(得分:3)
听起来你想避免使事件调度线程饱和。 How to Use Swing Timers中讨论的课程javax.swing.Timer
包括setCoalesce()
,其中“合并了多个待审ActionEvent
次攻击”。它可能是您更新速度的另一种方式。
如上所述here,SwingWorker
限制为33 Hz。
答案 2 :(得分:1)
你能用简单的重绘()吗?这样做的好处是多个调用合并为一个。
(详细说明)
假设您不断更新GPS位置并将其显示在两个文本字段中。你的线程进行更新:
run() {
while (keepGoing) {
Point myLocation = computeMyLocation();
locationModel.setLocation(myLocation);
locationComponent.repaint();
}
}
然后,在MyLocationComponent
中@Override
public void paintComponent(Graphics g) {
Point myLocation = locationModel.getLocation();
// you'd really want a NumberFormat
latitudeTextArea.setText(String.valueOf(myLocation.y));
longitudeTextArea.setText(String.valueOf(myLocation.x));
super.paintComponent(g);
}
优点是这会从视图中分离模型(如果您将线程视为控制器,这是MVC),并且所有线程都应该工作 - 不需要任何invokeLater()。一个缺点是您的线程需要知道需要更新的所有JComponents。在“真实”场景中,您可能会从触发重新绘制的侦听器触发事件,无论是来自“控制器”(您的线程)还是来自模型。
注意:正如@trashgod在LocationModel中指出的那样,getLocation()
和setLocation()
方法应为synchronized
,以便立即显示更新。