使用Swing动画进行计时

时间:2012-06-18 18:34:33

标签: java swing animation timer

我在Swing和角色动画方面遇到了一些问题, 我有一个带有键监听器的JFrame,当用户按下时,它在这里调用我的JPanel方法

for(int i=1;i<4;i++)
{           
    pY+=16;
    g.drawImage(perso,pX,pY,pX+50,pY+50,0+50*i,0,50+50*i,50,this 
    this.repaint();                 
}

这会激活我的角色,但速度太快,以至于我们可以看到一个东西,我该怎么做才能观看动画?

3 个答案:

答案 0 :(得分:7)

Jonas已经给出了答案(使用Swing计时器),但解释为什么你没有看到动画,以及为什么计时器是解决这个问题的最佳解决方案可能是有用的。

为什么我看不到不同的重绘

当您致电JComponent#repaint时,JComponent未重新粉饰。相反,在EDT上安排重新绘制某个组件的异步请求。如果您调用了许多repaint个调用,Swing可能会决定对这些请求进行分组并重新绘制该组件一次。

我没有立即在Oracle文档中找到这方面的官方参考(Swing painting article似乎没有提到它)。我发现这个的唯一地方是this article中的一个注释,但我很确定这是在某处记录的。

为什么使用Timer最佳解决方案

对于动画,你基本上想说:

  

我的角色应在x毫秒内移动y像素

最好,您希望在屏幕上拥有流畅的动画,因此您需要经常重新绘制。如果你记住

  • 与Swing组件的所有交互都应该在EDT上进行(事件调度线程,请参阅Concurrency in Swing文章了解更多信息)
  • 你永远不应该阻止EDT,因为这会冻结你的用户界面,这意味着你不能在EDT中“等待”,直到重绘完成或者重绘永远不会发生
  • 重新绘制请求可以进行分组,因此调用重绘x次并不能保证您的paint方法也被x次调用

克服此限制的解决方案是使用Timer。使用相同的示例(在屏幕上移动角色),您可以使用Timer更新角色的位置并安排重新绘制。由于在EDT上触发了Timer代码,因此您不会违反Swing线程规则。

在组件的paintComponent方法中,然后在当前位置绘制角色。这可能是“之前的位置+ 1”,或“之前的位置+2”(或...),具体取决于之前Timer来电与paint之间触发paint次的次数当前{{1}}来电。这可以确保角色移动的速度与系统无关。只有动画的平滑度取决于您的系统(例如:有多少重绘请求被分组)。

Jonas已经链接的Swing Timer tutorial包含更多信息。

答案 1 :(得分:3)

  1. 不要展开JFrame,创建JFrame作为本地变量

  2. 请勿使用KeyListener,请改用KeyBindings

  3. 不要直接在JFrame上绘画,使用drawImage()JLabelJComponent/JPanel

  4.   

    这会激活我的角色,但速度太快,以至于我们可以看到一个东西,我该怎么做才能观看动画?

  5. KeyListener的另一个问题,您必须设置两个KeyEvents之间的延迟

答案 2 :(得分:2)

您可以使用Swing Timer并定期更新动画。见How to Use Swing Timers