java - JavaFX 一张一张显示多个gif
问题描述
我想一个接一个地显示不同的 gif。
我的想法是使用时间轴动态更改包装到图像中的显示 gif。
但我得到一个错误:
从 lambda 表达式引用的局部变量必须是 final 或有效 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 中,在 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();
}
}
您正在引用i
lambda 内的局部变量( first KeyFrame
)。问题是for
循环修改了i
(例如i++
),这意味着变量不是有效的最终变量。一个可能的解决方法是在循环中声明另一个变量,为其分配 的值i
,然后在 lambda 中使用那个新的(不变的!)变量。然而,这不是唯一的问题。
Timeline
您的代码正在为数组中的每个元素创建一个单独的元素gifs
——换句话说,每个循环一个元素。您还可以在每次迭代结束时调用play
每个。Timeline
这将导致Timeline
同时播放多个 s。正如您可能想象的那样,这不会做您想要的。相反,您应该创建一个单一 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
允许在 lambda 中使用——尽管显然被修改了——这是因为我使用了“增强的 for 循环”。增强 for 循环的变量的处理方式与常规for
循环不同,因为它在每次迭代时都被初始化。有关更多信息,请参阅增强的“for”循环和 lambda 表达式。
推荐阅读
- webpack - Webpack (Encore):使用 image-webpack-loader 将图像转换为 webp
- python-2.7 - QTreeView selectionChanged 触发方法
- wordpress - 自定义帖子类型不显示 wordpress
- java - eclipselink 加载 n+1 个关联,即使它们被标记为 FetchType.LAZY
- java - 从java转换为scala
- intellij-idea - Intellij Pull Requests Tool Windows 出现错误
- google-app-engine - Google Datastore NDB 验证可选 IntegerProperty
- ios - Navigator.mediaDevices.getUserMedia 在 iOS 12 Safari 上不起作用
- delphi - 无形应用程序中的 TFDGUIxWaitCursor
- makefile - makefile 解析目标以定义依赖项