java使GUI更具响应性
我的程序将物理模拟可视化(基本上)。现在,它可以工作,但可能会变得非常无响应,我想我知道为什么——在事件线程上进行了太多(读取:all)计算
当按下“播放”按钮时,会创建一个SwingTimer
,它会定期唤醒并调用updateTime()
——目前为止一切正常。问题是updateTime()
迭代每个依赖时间的对象,并告诉它以适当的数量(实时经过的时间,或每个滴答的任意时间单位)在时间上向前传播自己。这些计算以及随后的GUI更新都在事件调度线程上
因此,我希望尽可能地减少这种计算,我认为SwingWorker
是一种可行的方法,但我不确定如何将它们应用到现有代码中。我不能让现有的类扩展SwingWorker
,因为它们中的许多已经扩展了其他类
到目前为止,我最好的想法是为每个要实现的时间相关对象创建一个接口。接口将指定两种方法,calcUpdateTime()
和drawUpdateTime()
。我会将他们当前的updateTime()
方法分为物理计算(分为calc_
)和GUI更新(分为draw_
)。然后我只创建一个SwingWorker类,它在构造函数中接受TimeDependant
对象,它的doInBackground
将调用calcUpdateTime
,而done
将调用drawUpdateTime
。这样我就可以替换所有出现的
myObj.updateTime(currentTime);
与
new MySwingWorker(myObj, currentTime).execute();
我想用它来运行这个想法,因为它感觉不太对,而且它希望避免重构整个项目,只是为了发现我一开始的想法不好。另外,每个滴答声可能会产生几十个MySwingWorker
不是一个坏主意吗
谢谢你读到这里
# 1 楼答案
我使用Swing timer的体验(性能方面)很差。由于Swing中的所有事件都使用同一个线程,因此它似乎有很多意外的延迟
我还建议你相信自己的直觉,每滴答都会出现多个swing worker实例:这听起来也不对。(根据
SwingWorker
文档,它被设计为只运行一次,所以你不一定能安全地重用它)一个可能做你需要的事情的计时器是
java.util.Timer
。这有很多用于指定超时的选项,尽管这取决于计时模拟的保真度,即使这样也可能不合适。(例如:如果你想让它实时运行,但你的计算时间实际上比实时时间长,那么它应该怎么做?慢慢运行,或者开始跳过时间步?)所以,由于不知道你的计算/绘图程序具体涉及什么,我暂时建议尝试
java.util.Timer
。当它过期时(根据“实时乘法器”,在您认为合适的任何超时时间之后),运行所有的计算,然后将结果返回给EDT线程进行绘制(例如,将它们包装在SwingUtilities.invokeLater()
中)当然,如果EDT想要引用与计算线程相同的对象,这可能会引入锁定问题。理想情况下,如果calc线程可以将不可变的结果传递给EDT,就不必引入锁
(免责声明:除了一个用于GUI,一个用于计算之外,上述任何一个都没有真正考虑多个内核/处理器。如果你想并行化应用程序,这可能不是一个合适的解决方案)