Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change AnimationTimer speed?

I use AnimationTimer for several tasks like animation with changing pictures and ProgressIndicator animation. To achieve needed speed I put thread to sleep, but when several animations are running simultaneously they affect each others speed. Is there any other way to change speed of AnimationTimer? Code sample:

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;
    }
}
like image 533
Alyona Avatar asked May 10 '15 00:05

Alyona


2 Answers

The AnimationTimer's handle method is invoked once for each frame that is rendered, on the FX Application Thread. You should never block that thread, so do not call Thread.sleep(...) here.

The parameter passed to the handle(...) method is a timestamp, in nanoseconds. So if you want to throttle updates so they don't happen more than once every, say 28 milliseconds, you can use this to do so:

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;
    }
}
like image 138
James_D Avatar answered Oct 07 '22 02:10

James_D


Since I already wrote the code and James_D was faster with informing you about you blocking the UI, I still like to add that if you have multiple AnimationTimers of different timings you should create a dedicated class for that. If each of them runs at a different speed, you could implement it like that:

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();

}

Which means that the handle() method is invoked at least after sleepMs milliseconds have passed.

Or you change the parameter and specify the fps, whatever you need.

You can use the above code like this:

AnimationTimerExt timer = new AnimationTimerExt(100) {

    @Override
    public void handle() {

        System.out.println( System.currentTimeMillis());

    }
};

timer.start();

Also, loading the picture over and over again is not the best choice. If you'd like to do animations, I suggest you take a look at Mike's Blog about Creating a Sprite Animation with JavaFX.

like image 21
Roland Avatar answered Oct 07 '22 01:10

Roland