JavaFX - заставить объект Timeline для нескольких объектов выполнить EventHandler один раз - PullRequest
0 голосов
/ 17 февраля 2020

Я сейчас работаю в JavaFX и столкнулся с проблемой. Я создал простой пример, чтобы продемонстрировать проблему, с которой я сталкиваюсь.

Моя проблема в том, что у меня есть Timeline установка объекта для нескольких анонимных Circle объектов, и я хочу, чтобы действие произошло после окончания временной шкалы его play() метод. Для этого я настроил обработчик событий setOnFinished для выполнения чего-либо после завершения воспроизведения анимации. Однако он выполняет эту логику c несколько раз, поскольку она работает с несколькими объектами.

Здесь я у вас есть простая программа, которая добавляет 3 анонимных объекта в VBox, и есть кнопка, которая вызовет метод flash() для запуска анимации временной шкалы на кругах.

package sample;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        VBox root = new VBox();
        VBox circles = new VBox();

        Button btn = new Button("Touch me to make me flash ;)");
        btn.setOnAction(e -> flash(circles));

        for(int i = 0; i < 3; i++) {
            circles.getChildren().add(new Circle(25, Color.RED));
        }
        circles.setSpacing(10);
        circles.setAlignment(Pos.CENTER);

        root.getChildren().addAll(circles, btn);
        root.setSpacing(10);
        root.setAlignment(Pos.CENTER);

        primaryStage.setScene(new Scene(root, 500, 500));
        primaryStage.show();
    }


    private void flash(VBox root) {
        for(Node circle : root.getChildren()) {
            final Circle c = (Circle) circle;
            Timeline timeline = new Timeline(
                    new KeyFrame(Duration.seconds(0.5), e -> c.setFill(Color.GOLD)),
                    new KeyFrame(Duration.seconds(1.0), e -> c.setFill(Color.RED))
            );

            timeline.setCycleCount(5);
            timeline.play();
            timeline.setOnFinished(e -> System.out.println("Do something here"));
        }
    }
}

Вы можете увидеть в flash() метод, который существует EventHandler, который выполняет эту строку кода:

System.out.println("Do something here")

Я хочу, чтобы он выполнялся только один раз, но он выполняется 3 раза, потому что объект Timeline настроен на 3 круга.

Как сделать так, чтобы EventHandler выполнялся только один раз?

1 Ответ

3 голосов
/ 17 февраля 2020

Рассмотрите возможность использования одного TimeLine объекта для всех Circle объектов:

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

    private ObjectProperty<Paint> colorProperty;

    @Override
    public void start(Stage primaryStage) throws Exception{

        colorProperty = new SimpleObjectProperty<>(Color.WHITE);
        VBox root = new VBox();
        VBox circles = new VBox();

        Button btn = new Button("Touch me to make me flash ;)");
        btn.setOnAction(e -> flash(circles));

        for(int i = 0; i < 3; i++) {
            circles.getChildren().add(new Circle(25, Color.RED));
        }
        circles.setSpacing(10);
        circles.setAlignment(Pos.CENTER);

        root.getChildren().addAll(circles, btn);
        root.setSpacing(10);
        root.setAlignment(Pos.CENTER);

        primaryStage.setScene(new Scene(root, 500, 500));
        primaryStage.show();
    }

    private void flash(VBox root) {

        Timeline timeline = new Timeline(
                new KeyFrame(Duration.seconds(0.5), e -> colorProperty.set(Color.GOLD)),
                new KeyFrame(Duration.seconds(1.0), e -> colorProperty.set(Color.RED))
        );

        timeline.setCycleCount(5);
        timeline.play();
        timeline.setOnFinished(e -> System.out.println("Do something here"));

        for(Node circle : root.getChildren()) {
            final Circle c = (Circle) circle;
            c.fillProperty().bind(colorProperty);
        }
    }

    public static void main(String[] args) {
        launch(null);
    }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...