JavaFX z Arią - powrót do strony głównej

JavaFX: AnimationTimer. Kontrolowanie czasu trwania i liczby ramek

Klasa Listing14c_04a

Ściągnij klasę Listing14c_04a

Sprawdzamy ile czasu trwa animacja, w której nie kontrolujemy czasu trwania ani liczby ramek.

package rozdzial14c;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

import java.time.Duration;
import java.time.Instant;

public class Listing14c_04a extends Application {
    private double radius = 10.0;
    private Circle circle;
    private Instant start;

    @Override
    public void start(Stage stage) {
        StackPane root = new StackPane();
        circle = new Circle(radius);
        circle.setFill(Color.DARKCYAN);
        root.getChildren().add(circle);
        AnimationTimer timer = new MyTimer();
        timer.start();
        start=Instant.now();
        Scene scene = new Scene(root, 300, 300);
        stage.setTitle("AnimationTimer");
        stage.setScene(scene);
        stage.show();
    }

    private class MyTimer extends AnimationTimer {
        @Override
        public void handle(long now) {
            System.out.println(now);
            radius += 0.5;
            circle.radiusProperty().set(radius);
            if (radius >= 80.0) {
                radius = 10.0;
                circle.radiusProperty().set(radius);
                stop();
                Instant end = Instant.now();
                long millis = Duration.between(start,
                        end).toMillis();
                System.out.println("Czas trwania: "+ millis);
            }
        }
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}

Po uruchomieniu klasy, uruchomieniu i zatrzymaniu stopera zobaczymy przeskakujące nanoczasy oraz wynik:

10254468416861
10254484909798
10254532553914
10254548911015
10254564971088
10254580917359
10254596908004
10254612922496
10254628917366
10254644908313
10254660930049
10254676902583
10254692904698
10254708908323
10254724963263
10254740927646
10254756933082
10254772933688
10254788918900
10254804931882
10254820884493
10254836928868
10254852897779
10254868900499
10254884910764
10254900933406
10254916918014
10254949011293
10254964967827
10254980973263
10254996959380
10255012983531
10255028998325
10255044964217
10255060939165
10255076943696
10255092972676
10255109004676
10255124962116
10255140998342
10255156964536
10255172941295
10255190000821
10255204901455
10255220918965
10255236896932
10255252974512
10255268995946
10255284960329
10255300930448
10255316918980
10255348978450
10255365012865
10255380954307
10255396953705
10255412987214
10255429006233
10255445002312
10255461007446
10255477352170
10255492992660
10255508989643
10255525026171
10255540982705
10255556996895
10255573010783
10255588961281
10255604981206
10255620938344
10255636930197
10255652930803
10255668967028
10255684953145
10255700929603
10255717040085
10255748990887
10255764996323
10255781032850
10255797203101
10255813750070
10255829002672
10255844958905
10255860966152
10255876960117
10255893044941
10255908990006
10255924990310
10255941007820
10255957010841
10255973058839
10255989002696
10256004961947
10256020988513
10256036939916
10256052967388
10256069007839
10256084971619
10256100930267
10256132980380
10256149057054
10256165059472
10256181028383
10256197054345
10256213021747
10256229035031
10256245012092
10256261040771
10256276997909
10256292978895
10256308989764
10256324988559
10256341027199
10256357013618
10256373009395
10256388999134
10256405007588
10256420971669
10256436940279
10256453048044
10256468962621
10256485016958
10256500937572
10256532997948
10256549073717
10256565015461
10256580982862
10256596978941
10256613027240
10256628998868
10256645018491
10256661030266
10256677047475
10256693100906
10256709055630
10256725065895
10256741064086
10256757039638
10256773046583
10256788992855
10256805059568
Czas trwania: 2497
Klasa Listing14c_04b

Ściągnij klasę Listing14c_04b

Kontrolujemy czas trwania animacji. Kontrolujemy płynność animacji rozszerzając klasę Interpolator.

package rozdzial14c;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.time.Duration;
import java.time.Instant;

public class Listing14c_04b extends Application {
    private double radius;
    private Circle circle;
    private long duration;
    private Linear interp;

    @Override
    public void start(Stage stage) {
        StackPane root = new StackPane();
        circle = new Circle(radius);
        duration = 2000;//ms
        circle.setFill(Color.DARKCYAN);
        interp = new Linear();
        root.getChildren().add(circle);
        AnimationTimer timer = new MyTimer();
        timer.start();
        Scene scene = new Scene(root, 300, 300);
        stage.setTitle("AnimationTimer");
        stage.setScene(scene);
        stage.show();
    }

    private class MyTimer extends AnimationTimer {
        Instant start = Instant.now();
        @Override
        public void handle(long now) {
            long elapsed = Duration.between(start,
                    Instant.now()).toMillis();
            if(elapsed <= duration) {
                double radiusStart = 10.0;
                double radiusEnd = 80;
                double r = interp.interpolate(radiusStart, radiusEnd,
                        (double) elapsed / (double) duration);
                circle.radiusProperty().set(r);
            }else{
                radius = 10.0;
                circle.radiusProperty().set(radius);
                stop();
                Instant end = Instant.now();
                long millis = Duration.between(start, end).toMillis();
                System.out.println("Czas trwania: "+ millis);
            }
        }
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}
Klasa Linear

Ściągnij klasę Linear.zip

package rozdzial14c;

import javafx.animation.Interpolator;

public class Linear extends Interpolator {
    @Override
    protected double curve(double v) {
        return v;
    }
}

Po uruchomieniu klasy Listing_14c_04b na konsoli zobaczymy:

Czas trwania: 2015
Klasa Listing14_35c

Ściągnij klasę Listing14c_04c

Kontrolujemy czas trwania aplikacji. Ograniczamy liczbę ramek przez zastosowanie Thread.sleep().

package rozdzial14c;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.time.Duration;
import java.time.Instant;

public class Listing14c_04c extends Application {
    private double radius;
    private Circle circle;
    private long duration;
    private Linear interp;

    @Override
    public void start(Stage stage) {
        StackPane root = new StackPane();
        circle = new Circle(radius);
        duration = 2000;//ms
        circle.setFill(Color.DARKCYAN);
        interp = new Linear();
        root.getChildren().add(circle);
        AnimationTimer timer = new MyTimer();
        timer.start();
        Scene scene = new Scene(root, 300, 300);
        stage.setTitle("AnimationTimer");
        stage.setScene(scene);
        stage.show();
    }

    private class MyTimer extends AnimationTimer {
        Instant start = Instant.now();
        int counter = 0;
        @Override
        public void handle(long now) {
            long elapsed = Duration.between(start,
                    Instant.now()).toMillis();
            counter++;
            if(elapsed <= duration) {
                double radiusStart = 10.0;
                double radiusEnd = 80;
                double r = interp.interpolate(radiusStart, radiusEnd,
                        (double) elapsed / (double) duration);
                circle.radiusProperty().set(r);
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                radius = 10.0;
                circle.radiusProperty().set(radius);
                stop();
                Instant end = Instant.now();
                long millis = Duration.between(start, end).toMillis();
                System.out.println("Czas trwania: "+ millis);
                System.out.println("Counter: "+ counter);
            }
        }
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}

Po uruchomieniu klasy na konsoli zobaczymy:

Czas trwania: 2020
Counter: 56
Klasa Listing14c_04d

Ściągnij klasę Listing14c_04d

Sprawdzamy poprzednie rozwiązanie przedłużając 2× czas trwania animacji. Używamy pomiarów
wykorzystując System.nanotime().

package rozdzial14c;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

public class Listing14c_04d extends Application {
    private double radius;
    private Circle circle;
    private long duration;
    private Linear interp;

    @Override
    public void start(Stage stage) {
        StackPane root = new StackPane();
        circle = new Circle(radius);
        duration = 4000;//ms
        circle.setFill(Color.DARKCYAN);
        interp = new Linear();
        root.getChildren().add(circle);
        AnimationTimer timer = new MyTimer();
        timer.start();
        Scene scene = new Scene(root, 300, 300);
        stage.setTitle("AnimationTimer");
        stage.setScene(scene);
        stage.show();
    }

    private class MyTimer extends AnimationTimer {
        Instant start = Instant.now();
        long start2 = System.nanoTime();
        int counter = 0;
        @Override
        public void handle(long now) {
            long elapsed1 = now - start2;
            long elapsed2 = TimeUnit.MILLISECONDS.convert(elapsed1,
                    TimeUnit.NANOSECONDS);
            counter++;
            if(elapsed2 <= duration) {
                double radiusStart = 10.0;
                double radiusEnd = 80;
                double r = interp.interpolate(radiusStart, radiusEnd,
                        (double) elapsed2 / (double) duration);
                circle.radiusProperty().set(r);
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                radius = 10.0;
                circle.radiusProperty().set(radius);
                stop();
                Instant end = Instant.now();
                long millis = Duration.between(start,  end).toMillis();
                System.out.println("Czas trwania: "+ millis);
                System.out.println("Counter: "+ counter);
            }
        }
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}

Po uruchomieniu otrzymujemy na konsoli>

Czas trwania: 4007
Counter: 116

Jak widzimy czas trwania animacji wzrósł dwukrotnie podobnie jak liczba klatek animacji.

W ten sposób osiągnęliśmy to o co nam chodziło.