如何改变 AnimationTimer 的速度?
Posted
技术标签:
【中文标题】如何改变 AnimationTimer 的速度?【英文标题】:How to change AnimationTimer speed? 【发布时间】:2015-07-20 17:04:24 【问题描述】:我将AnimationTimer
用于几项任务,例如带有变化图片的动画和ProgressIndicator
动画。为了达到所需的速度,我让线程进入睡眠状态,但是当多个动画同时运行时,它们会影响彼此的速度。有没有其他方法可以改变AnimationTimer
的速度?代码示例:
private void initialize()
programButtonAnimation=new AnimationTimer()
@Override
public void handle(long now)
showClockAnimation();
;
programButtonAnimation.start();
private void showClockAnimation()
String imageName = "%s_"+"%05d"+".%s";
String picturePath="t093760/diploma/view/styles/images/pink_frames/"+String.format( imageName,"pink" ,frameCount,"png");
programButton.setStyle("-fx-background-image:url('"+picturePath+"')");
frameCount++;
try
Thread.sleep(28);
catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();
if(frameCount>=120)
programButtonAnimation.stop();
frameCount=0;
【问题讨论】:
【参考方案1】:new AnimationTimer()
int frameCount = 0;
@Override
public void handle(long currentNanoTime)
if (frameCount % 2 == 0)
// 30 fps ?
frameCount++;
可能有点老套,但可以完成工作
【讨论】:
【参考方案2】:由于我已经编写了代码,并且 James_D 更快地通知您您阻塞了 UI,我仍然想补充一点,如果您有多个不同时间的 AnimationTimer,您应该为此创建一个专用类。如果它们每个以不同的速度运行,您可以这样实现:
import javafx.animation.AnimationTimer;
public abstract class AnimationTimerExt extends AnimationTimer
private long sleepNs = 0;
long prevTime = 0;
public AnimationTimerExt( long sleepMs)
this.sleepNs = sleepMs * 1_000_000;
@Override
public void handle(long now)
// some delay
if ((now - prevTime) < sleepNs)
return;
prevTime = now;
handle();
public abstract void handle();
这意味着至少在 sleepMs 毫秒过后才调用 handle() 方法。
或者您更改参数并指定 fps,无论您需要什么。
你可以像这样使用上面的代码:
AnimationTimerExt timer = new AnimationTimerExt(100)
@Override
public void handle()
System.out.println( System.currentTimeMillis());
;
timer.start();
另外,一遍又一遍地加载图片并不是最好的选择。如果你想做动画,我建议你看看 Mike 的关于 Creating a Sprite Animation with JavaFX 的博客。
【讨论】:
【参考方案3】:AnimationTimer
的 handle
方法在 FX 应用程序线程上为渲染的每一帧调用一次。你永远不应该阻塞那个线程,所以不要在这里调用Thread.sleep(...)
。
传递给handle(...)
方法的参数是一个时间戳,以纳秒为单位。因此,如果您想限制更新,使更新不会超过一次,例如 28 毫秒,您可以使用它来执行此操作:
private void initialize()
programButtonAnimation=new AnimationTimer()
private long lastUpdate = 0 ;
@Override
public void handle(long now)
if (now - lastUpdate >= 28_000_000)
showClockAnimation();
lastUpdate = now ;
;
programButtonAnimation.start();
private void showClockAnimation()
String imageName = "%s_"+"%05d"+".%s";
String picturePath="t093760/diploma/view/styles/images/pink_frames/"+String.format( imageName,"pink" ,frameCount,"png");
programButton.setStyle("-fx-background-image:url('"+picturePath+"')");
frameCount++;
if(frameCount>=120)
programButtonAnimation.stop();
frameCount=0;
【讨论】:
更多关于使用AnimationTimer
的想法,我推荐阅读this和this
如果handle
以固定的速率被调用,比如每16ms左右,这种技术不会通过在16、32、16、16、32ms等处进行更新而引入抖动吗?
@StevensMiller 是的,在这种情况下它会影响平滑度(轻微)。我之前评论中的链接详细讨论了可能的解决方案。目前还不清楚为什么 OP 想要将其限制在 JavaFX 工具包的“自然”帧渲染速率之外。
很抱歉,我看不出这些链接如何解决这个问题。这是 Java 的一个主要问题,AFAIK 实际上并不允许真正的 vsync。其他人说 AnimationTimer 提供了 vsync,但我的实验很容易证明这一点。同样,页面翻转(有助于防止撕裂)是另一种广泛提出的非解决方案,作为实现垂直同步的一种方式。诚然,OP 是在追求别的东西,但是很多这些问题归结为无法同步锁定到刷新。你知道方法吗?
@PhilFreihofner 博客似乎不见了,但相关的代码仓库是 here以上是关于如何改变 AnimationTimer 的速度?的主要内容,如果未能解决你的问题,请参考以下文章