【问题标题】:JavaFX display multiple gifs one by oneJavaFX 一张一张显示多个gif
【发布时间】:2019-08-15 23:22:52
【问题描述】:

我想一个接一个地显示不同的 gif。
我的想法是使用时间轴动态更改包装到图像中的显示 gif。
但我得到一个错误:

从 lambda 表达式引用的局部变量必须是 final 或 有效地最终

有什么解决办法吗?
我的代码:

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

    }


}

【问题讨论】:

  • 请粘贴整个类代码(带导入)。我在编译时遇到了问题。

标签: java javafx javafx-8 gif animated-gif


【解决方案1】:

在 Java 中,在 lambda 或匿名类之外声明但在所述 lambda 或匿名类中使用的局部变量必须是“有效最终的”。这意味着永远不会修改局部变量(即重新分配)。如果局部变量可以在声明中添加 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();
    }

}

您在 lambda 中引用局部变量 i(第一个 KeyFrame)。问题是for 循环修改了i(例如i++),这意味着该变量实际上不是最终的。一种可能的解决方法是在循环中声明另一个变量,为其分配 i 的值,然后在 lambda 中使用那个新的(不变的!)变量。然而,这不是唯一的问题。

您的代码正在为gifs 数组中的每个元素创建一个单独的Timeline — 换句话说,每个循环一个。您还可以在每次迭代结束时对每个 Timeline 调用 play。这将导致同时播放多个Timelines。正如您可能想象的那样,这不会做您想要的。相反,您应该创建一个 single 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 更改为数组中以displayDuration 为间隔的下一个Image

如果你想知道为什么gif 被允许在 lambda 中使用——尽管显然被修改了——这是因为我使用了“增强的 for 循环”。增强型 for 循环的变量的处理方式与常规 for 循环不同,因为它在每次迭代时初始化。请参阅Enhanced 'for' loop and lambda expressions 了解更多信息。

【讨论】:

  • 我读过有关 lambda 错误的信息。你的解释很有帮助!感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多