Jonas 已经给出了答案(使用 Swing 计时器),但解释为什么您没有看到动画以及为什么计时器是解决此问题的最佳解决方案可能会很有用。
为什么我看不到不同的重绘
当您调用时JComponent#repaint
,JComponent
不会重新粉刷。相反,在 EDT 上安排了重绘某个组件的异步请求。如果您调用许多repaint
调用,Swing 可能会决定对这些请求进行分组并只重绘一次组件。
我没有立即在 Oracle 文档中找到对此的官方参考(Swing 绘画文章似乎没有提及)。我发现这一点的唯一地方是在这篇文章的注释中,但我很确定这在某处有记录。
为什么使用Timer
最佳解决方案
对于动画,您基本上想说:
我的角色应该以毫秒为单位移动x
像素y
最好是,您希望在屏幕上拥有流畅的动画,因此您需要频繁地重新绘制。如果你记住
- 与 Swing 组件的所有交互都应在 EDT 上进行(事件调度线程,有关更多信息,请参阅Swing 中的并发文章)
- 你永远不应该阻塞 EDT,因为这会冻结你的 UI,这意味着你不能在 EDT 中“等待”直到重绘完成,否则重绘永远不会发生
- 重绘请求可以分组,因此调用重绘
x
时间并不能保证您的paint
方法也被调用x
次数
克服此限制的解决方案是使用Timer
. 使用相同的示例(在屏幕上移动角色),您可以使用 aTimer
更新角色的位置并安排重绘。由于Timer
代码是在 EDT 上触发的,因此您不会违反 Swing 线程规则。
然后在组件的paintComponent
方法中,在当前位置绘制角色。这可能是“先前位置 + 1”或“先前位置 +2”(或 ...),具体取决于在先前呼叫和当前呼叫Timer
之间触发了多少次。这确保了角色移动的速度与系统无关。只有动画的流畅度取决于您的系统(例如:有多少重绘请求被分组)。paint
paint
Jonas 已经链接到的SwingTimer
教程包含更多信息。