2

我在使用 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();                 
}

这为我的角色设置了动画,但速度如此之快,以至于我们可以看到一个东西,我该如何查看动画?

4

3 回答 3

7

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

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

当您调用时JComponent#repaintJComponent不会重新粉刷。相反,在 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之间触发了多少次。这确保了角色移动的速度与系统无关。只有动画的流畅度取决于您的系统(例如:有多少重绘请求被分组)。paintpaint

Jonas 已经链接到的SwingTimer教程包含更多信息。

于 2012-06-18T19:53:31.843 回答
3
  1. 不要扩展JFrame,创建JFrame为局部变量

  2. 不使用KeyListenerKeyBindings改为使用

  3. 不要直接画到,JFrame用到ordrawImage()JLabelJComponent/JPanel

  4. 这为我的角色设置了动画,但速度如此之快,以至于我们可以看到一个东西,我该如何查看动画?

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

于 2012-06-18T18:48:53.617 回答
2

您可以使用 Swing Timer 并定期更新动画。了解如何使用摆动计时器

于 2012-06-18T18:41:06.253 回答