我有一个项目,它使用控制器阶段来操作显示阶段并为其着色(它有一个带有 WritableImage 的 ImageView)。我遇到的问题是显示阶段在完成整个图像着色的任务之前就会冻结。看起来问题似乎出在第二个阶段的弹出上,因为每当它被删除并且显示阶段自动填充时,它就会毫无问题地加载 - 除了无法控制显示阶段的问题。
以下是使用此方法的一些结果:
虽然单击播放按钮一次几乎不起作用,但单击多次通常可以加载显示内容。
如果单击按钮几次但显示仍未加载,选择显示阶段将有时加载它。
首先显示显示或控制阶段并将其中一个或另一个用作给定的主要阶段没有区别。
如果将任一阶段放入另一个线程或任务中,则它不会到达 show 语句,每当遇到新阶段减速时就会崩溃。
public void start(Stage display_stage) { // Given "primaryStage"
// Create a basic ImageView to be colored
WritableImage image = new WritableImage(1920, 1080);
PixelWriter writer = image.getPixelWriter();
ImageView view = new ImageView(image);
// Set up display stage
display_stage.setScene(new Scene(new Pane(view), 1920, 1080));
// Set up play button with coloring action
Button play_button = new Button("PLAY");
play_button.setOnAction(e -> {
new Thread( new Task<Void>() {
@Override
protected Void call() {
// Iterate through every pixel and color it arbitrarily
for (int y = 0; y < 1080; y++)
for (int x = 0; x < 1920; x++)
writer.setColor(x, y, Color.rgb(0, 0, 255));
return null;
}
}).start();
});
// Set up control stage
Stage control_stage = new Stage();
control_stage.setScene(new Scene(play_button, 100, 100));
// Show stages
control_stage.show();
display_stage.show();
}
这是减少的代码 - 如果重要的话我正在使用 IntelliJ IDEA。欢迎任何指点 - 提前致谢。
不要从另一个线程在活动场景图中写入(或读取)内容。
具体来说,就您的情况而言,当您不在 JavaFX 线程上时,请勿调用
writer.setColor
。
如果您需要在任务中执行异步操作(我不知道您是否这样做,这可能是过早的优化),则在任务中填充缓冲区并从任务结果中返回它。准备就绪后,使用像素写入器将图像上的像素设置为缓冲区中的值。 这是一种“双缓冲区”,您可以在其中管理离屏缓冲区,而 JavaFX 系统则控制屏幕缓冲区(ImageView 中显示的图像)。 或者,您可以保留两个 WritableImage,一个在场景图上处于活动状态,另一个由异步任务写入,然后在任务完成后翻转它们,方法是将显示的 ImageView 中的图像设置为任务刚刚写入的图像,请参阅与双缓冲相同的 wiki 文章中的“页面翻转”技术。