我试图在屏幕上显示迷宫生成的过程,但在过程完成之前屏幕从未更新。我使用消费者来通知JavaFX端。我试过使用Platform.runLater()
,但无济于事。
下面是正在使用的文件:
"hello-view.fxml">
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane onMouseClicked="#randomize" fx:id="sp" xmlns:fx="http://javafx.com/fxml" fx:controller="com.example.demo2.HelloController">
</StackPane>
这是一个迷宫生成器的删节版本,"BasicMaze.java":
package com.example.demo2;
import java.util.*;
import java.util.function.Consumer;
public class BasicMaze {
public int width;
public int height;
private transient List<Consumer<BasicMaze>> consumers = new ArrayList<>();
public void reset(int w, int h) {
width = w;
height = h;
alertConsumers();
}
public void addConsumer(Consumer<BasicMaze> l) {
if (consumers == null) consumers = new ArrayList<>();
consumers.add(l);
}
public void alertConsumers() {
consumers.forEach(c -> c.accept(this));
}
public void generate() {
int slots = width * height;
do {
if (Math.random() * 10 < 1) {
alertConsumers(); //Platform.runLater tried here
slots--;
}
} while (slots > 1);
System.out.println("DONE!");
}
}
这是控制器"HelloController.java":
package com.example.demo2;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
public class HelloController {
@FXML
StackPane sp;
final Canvas canvas = new Canvas(250,250);
BasicMaze maze = new BasicMaze();
@FXML
public void initialize() {
sp.getChildren().add(canvas);
maze.addConsumer(basicMaze -> this.draw()); //platform.runLater tried here.
}
public void randomize() {
maze.reset(5, 5);
maze.generate();
}
public void draw() {
GraphicsContext gc = canvas.getGraphicsContext2D() ;
gc.setLineWidth(1.0);
gc.setFill(Color.BLACK);
for (int j = 0; j < maze.height; j++) {
for (int i = 0; i < maze.width; i++) {
gc.moveTo(Math.random()*250, Math.random()*250);
gc.lineTo(Math.random()*250, Math.random()*250);
gc.stroke();
}
}
}
}
这里是main函数存根:
package com.example.demo2;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
如果你运行这个并点击屏幕,"完成!"会出现在控制台上,会有一个延迟,然后屏幕上会出现一堆黑线。我正试图让屏幕更新,因为每条线绘制。
好的,这实际上是非常容易的(几乎不麻烦!),我从Sergey Grinev的一些帖子中推断出来。所有需要改变的(几乎)是在自己的线程上运行后台任务。
因此,我们将maze.generate()
封装在一个线程中:
public void randomize() {
maze.reset(500, 500);
new Thread(maze::generate).start();
}
现在初始化中的runLater可以工作了!
@FXML
public void initialize() {
sp.getChildren().add(canvas);
maze.addConsumer(basicMaze -> Platform.runLater(this::draw));
}
底层对象根本不需要改变。