【问题标题】:Timing with Swing animationSwing 动画的计时
【发布时间】:2012-06-18 18:34:32
【问题描述】:

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

这个动画我的角色但是太快了,我们可以看到一个东西,我怎么看动画?

【问题讨论】:

    标签: java swing animation timer


    【解决方案1】:

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

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

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

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

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

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

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

    最好是,您希望在屏幕上显示流畅的动画,因此您需要经常重绘。如果你牢记这一点

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

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

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

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

    【讨论】:

    • 感谢您提供的详细信息,这对我非常有用,我会尝试使用计时器
    • @mKorbel 谢谢。不幸的是,它似乎没有得到很多赞成:-(
    【解决方案2】:
    1. 不要扩展JFrame,创建JFrame作为局部变量

    2. 不要使用KeyListener,而是使用KeyBindings

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

    4. 这个动画我的角色,但是太快了,我们可以看到一个东西,我该怎么做才能看到动画?

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-05
        • 2012-04-24
        • 2011-05-14
        相关资源
        最近更新 更多