JavaFX отображать несколько картинок по одному - PullRequest
0 голосов
/ 25 марта 2019

Я хочу отображать разные картинки один за другим.
Моя идея состояла в том, чтобы динамически изменить отображение GIF, который обернут в изображение, используя временную шкалу.
Но я получил ошибку:

локальные переменные, на которые ссылается лямбда-выражение, должны быть окончательными или эффективно окончательный

Есть ли решения?
Мой код:

public class Task10 extends Application {
    @Override
    public void start(Stage primaryStage) {
        HBox hbox5 = new HBox();

        VBox VBoxAll = new VBox();


        Image gifs[] = new Image[3];
        gifs[0] = new Image(this.getClass().getResource("/img/L1.gif").toExternalForm());
        gifs[1] = new Image(this.getClass().getResource("/img/L2.gif").toExternalForm());
        gifs[2] = new Image(this.getClass().getResource("/img/L1.gif").toExternalForm());

        ImageView currentGif = new ImageView();


        Button localLoadButton = new Button("Start!");
        localLoadButton.setOnAction(e -> {
            show(currentGif, gifs);
        });

        hbox5.getChildren().addAll(currentGif, localLoadButton);

        VBoxAll.getChildren().addAll(hbox5);
        VBoxAll.setSpacing(15);

        Pane pane = new Pane();
        pane.getChildren().add(VBoxAll);

        Scene scene = new Scene(pane, 500, 350);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void show(ImageView currentGif, Image[] gifs) {
        for (int i = 0; i<gifs.length; i++) {
            Timeline timeline = new Timeline(
                new KeyFrame(Duration.ZERO, e -> { currentGif.setImage(gifs[i]); }),
                new KeyFrame(Duration.seconds(2), e -> { currentGif.setImage(null); })
            );
            timeline.play();
        }

    }


}

1 Ответ

1 голос
/ 26 марта 2019

В Java локальные переменные, которые объявлены вне лямбда или анонимного класса, но используются внутри упомянутого лямбда или анонимного класса, должны быть "эффективно финальными".Это означает, что локальная переменная никогда не изменяется (т. Е. Переназначается).Если локальная переменная может иметь ключевое слово final, добавленное к объявлению, не вызывая ошибки компиляции, переменная будет фактически конечной.

В вашем коде есть следующее:

public void show(ImageView currentGif, Image[] gifs) {
    for (int i = 0; i<gifs.length; i++) {
        Timeline timeline = new Timeline(
            new KeyFrame(Duration.ZERO, e -> { currentGif.setImage(gifs[i]); }),
            new KeyFrame(Duration.seconds(2), e -> { currentGif.setImage(null); })
        );
        timeline.play();
    }

}

Вы ссылаетесь на локальную переменную i внутри лямбды (сначала KeyFrame).Проблема в том, что цикл for изменяет i (например, i++), что означает, что переменная не является окончательной.Возможное исправление - объявить другую переменную внутри цикла, присвоить ей значение i, а затем использовать эту новую (неизменную!) Переменную внутри лямбды.Однако это не единственная проблема.

Ваш код создает отдельный Timeline для каждого элемента в массиве gifs, другими словами, по одному на цикл.Вы также вызываете play для каждого Timeline в конце каждой итерации.Это приведет к одновременному воспроизведению нескольких Timeline с.Как вы можете себе представить, это не будет делать то, что вы хотите.Вместо этого вы должны создать сингл Timeline, и каждое изменение Image должно быть его собственным KeyFrame.Примерно так:

public void show(ImageView view, Image[] gifs, Duration displayDuration) {
    Timeline timeline = new Timeline();

    Duration totalDelay = Duration.ZERO;
    for (Image gif : gifs) {
        KeyFrame frame = new KeyFrame(totalDelay, e -> view.setImage(gif));
        timeline.getFrames().add(frame);
        totalDelay = totalDelay.add(displayDuration);
    }
    timeline.getFrames().add(new KeyFrame(totalDelay, e -> view.setImage(null));

   timeline.play();
}

Это изменит Image на следующий Image в массиве с интервалами displayDuration.

Если вам интересно, почему gif разрешено использовать внутри лямбда - несмотря на то, что он, видимо, был модифицирован - это потому, что я использовал «расширенный цикл».Переменная расширенного цикла for обрабатывается иначе, чем обычный цикл for, поскольку она инициализируется каждую итерацию.См. Расширенные выражения для цикла и лямбда-выражения для получения дополнительной информации.

...