使用Swing动画进行计时

use*_*513 2 java animation swing 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();                 
}
Run Code Online (Sandbox Code Playgroud)

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

Rob*_*bin 7

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

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

当你打电话JComponent#repaintJComponent不是重新绘制.相反,在EDT上安排重新绘制某个组件的异步请求.如果您调用许多repaint调用,Swing可能会决定对这些请求进行分组并仅重新绘制一次该组件.

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

为什么使用Timer最好的解决方案

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

我的角色应该xy毫秒为单位移动像素

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

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

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

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

Jonas已经链接的Swing Timer教程包含更多信息.