为什么gc.clearRect不会清除画布?

时间:2015-07-21 20:43:45

标签: java canvas javafx

我在MazeUI类中有一些代码,它在JavaFX中创建了几个字段,用于输入要生成的迷宫的高度和宽度以及按钮和按钮的事件。单击Generate Maze时,代码应生成随机迷宫。

现在这很好用。但是在使用gc.clearRect(x,y,z,a)首次绘制迷宫之后清除画布的线似乎不起作用,并且在随后的点击中将迷宫重新绘制在彼此之上:

package dojo.maze.ui;

import dojo.maze.generator.MazeGenerator;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.BoxBlur;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.stage.Stage;

public class MazeUI extends Application {

private MazeGenerator generator;
private Integer height = 15;
private Integer width = 15;

@Override
public void start(Stage primaryStage) throws Exception {
    primaryStage.setTitle("Dojo: Solving a Maze");

    Group root = new Group();

    drawMazeView(root);

    primaryStage.setScene(new Scene(root, Color.WHITE));
    primaryStage.show();
}


private GraphicsContext initialiseGraphicsContext(Canvas canvas) {
    GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.setFill(Color.BLACK);
    gc.fillRect(0,0,600,600);
    gc.setStroke(Color.GREEN);
    gc.setLineCap( StrokeLineCap.ROUND );
    gc.setLineJoin( StrokeLineJoin.ROUND );
    gc.setLineWidth(3);

    BoxBlur blur = new BoxBlur();
    blur.setWidth(1);
    blur.setHeight(1);
    blur.setIterations(1);
    gc.setEffect(blur);
    return gc;
}

private void drawMazeView(Group root) {
    Canvas canvas = new Canvas(800, 800);
    GraphicsContext gc = initialiseGraphicsContext(canvas);

    GridPane.setConstraints(canvas, 0, 6);

    GridPane grid = new GridPane();
    grid.setPadding(new Insets(10, 10, 10, 10));
    grid.setVgap(5);
    grid.setHgap(5);

    Label heightLabel = new Label("Height:");
    final TextField heightTextField = new TextField();
    HBox hbHeight = new HBox();
    hbHeight.getChildren().addAll(heightLabel, heightTextField);
    hbHeight.setSpacing(10);

    GridPane.setConstraints(hbHeight, 0, 0);

    Label widthLabel = new Label("Label:");
    final TextField widthTextField = new TextField();
    HBox hbWidth = new HBox();
    hbWidth.getChildren().addAll(widthLabel, widthTextField);
    hbWidth.setSpacing(10);

    GridPane.setConstraints(hbWidth, 0, 2);

    VBox fieldsBox = new VBox();
    fieldsBox.getChildren().addAll(hbHeight, hbWidth);

    // Create button that allows you to generate a new maze
    Button btn = new Button();
    btn.setText("Generate Random Maze");
    btn.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
            System.out.println("Button clicked!");
            height = Integer.valueOf(heightTextField.getText());
            width = Integer.valueOf(widthTextField.getText());

            // clear old maze
            gc.clearRect(0, 0,
                    canvas.getHeight(),
                    canvas.getWidth());

            generator = new MazeGenerator(height, width);

            drawMaze(gc);
        }
    });

    GridPane.setConstraints(btn, 0, 4);

    grid.getChildren().addAll(fieldsBox, btn, canvas);
    root.getChildren().add(grid);
}

void drawMaze(GraphicsContext gc) {
    int[][] maze = generator.maze();
    int xPos = 20,
        yPos = 20,
        length = 40,
        gap = 10;

    for (int i = 0; i < width; i++) {
        xPos = 20;
        // draw the north edge
        for (int j = 0; j < height; j++) {
            if ((maze[j][i] & 1) == 0) {
                gc.strokeLine(xPos, yPos, xPos + length, yPos); // horizontal
            }
            xPos += length + gap;

            System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+   ");
        }
        System.out.println("+");

        xPos = 20;
        // draw the west edge
        for (int j = 0; j < height; j++) {
            if ((maze[j][i] & 8) == 0) {
                gc.strokeLine(xPos, yPos, xPos, yPos + length); // vertical
            }
            xPos += length + gap;

            System.out.print((maze[j][i] & 8) == 0 ? "|   " : "    ");
        }
        gc.strokeLine(xPos, yPos, xPos, yPos + length); // vertical
        System.out.println("|");
        yPos += length + gap;
    }
    // draw the bottom line

    xPos = 20; // reset x pos to western edge

    for (int j = 0; j < height; j++) {
        gc.strokeLine(xPos, yPos, xPos + length, yPos); // horizontal
        System.out.print("+---");
        xPos += length + gap;
    }
    System.out.println("+");
}

public static void main(String[] args) {
    launch(args);
}
}

MazeGenerator代码:

package dojo.maze.generator;

import java.util.Arrays;
import java.util.Collections;

/*
 * recursive backtracking algorithm
 * shamelessly borrowed from the ruby at
 * http://weblog.jamisbuck.org/2010/12/27/maze-generation-recursive-backtracking
*/
public class MazeGenerator {

private final int x;
private final int y;
private final int[][] maze;

public static final int[][] mazeProblemOne = new int[][] {{2,5,2,3,7,3,1,6,7,3,3,5,6,3,5},{4,10,3,5,12,6,3,9,10,3,5,12,8,6,13},{12,6,5,12,12,14,3,1,6,3,9,10,3,9,12},{12,12,12,12,12,12,6,3,9,4,6,7,1,6,9},{14,9,10,9,12,12,12,6,5,12,12,10,5,12,4},{12,2,7,5,12,12,10,9,12,10,13,4,10,9,12},{12,6,9,12,12,12,2,5,10,5,10,11,3,3,13},{12,10,5,12,10,11,3,13,4,10,5,6,3,1,12},{12,6,9,10,5,4,6,9,12,6,9,12,6,3,9},{10,9,6,1,12,10,11,3,9,12,6,13,12,2,5},{6,7,9,6,9,6,3,3,3,9,8,12,12,6,13},{8,12,6,9,6,13,6,3,7,3,3,13,12,12,12},{6,9,10,5,12,12,12,4,10,3,5,8,12,12,8},{14,3,5,12,8,12,10,11,3,5,10,5,12,10,5},{10,1,10,11,3,9,2,3,3,11,1,10,11,3,9}};
public static final int[][] mazeProblemTwo = new int[][] {{2,5,6,5,6,3,1,6,3,3,7,5,2,3,5},{4,10,9,12,14,3,3,9,6,5,12,10,3,3,9},{14,3,3,9,8,6,3,5,12,12,10,3,3,3,5},{12,6,3,3,5,12,4,10,9,10,3,3,3,3,13},{12,12,6,5,12,12,10,3,3,3,5,6,3,3,9},{12,10,9,12,10,9,6,5,6,3,13,10,3,3,5},{10,3,5,12,6,5,12,10,9,4,14,3,3,1,12},{4,6,9,12,12,10,9,6,3,11,13,6,3,3,9},{12,12,2,13,14,3,5,8,6,5,8,10,3,3,5},{12,10,3,9,12,4,12,6,9,12,6,5,6,3,9},{14,7,3,1,10,13,12,12,4,12,12,10,9,6,1},{12,10,3,7,1,12,10,11,9,12,12,2,3,11,5},{12,2,5,12,6,9,2,5,6,9,10,3,3,5,12},{10,5,12,12,12,6,3,13,12,6,7,1,6,9,12},{2,11,9,10,11,9,2,9,10,9,10,3,11,3,9}};
public static final int[][] mazeProblemThree = new int[][] {{2,5,2,3,7,3,3,3,5,6,3,1,6,7,1},{4,10,3,5,12,2,5,6,9,10,3,3,9,14,5},{10,7,5,12,10,5,14,9,6,5,6,3,5,12,12},{6,9,8,10,3,9,12,6,13,12,10,5,12,12,12},{12,6,3,7,1,6,9,12,12,10,3,9,12,8,12},{12,12,4,10,5,10,5,8,14,3,5,2,11,3,13},{12,10,13,4,10,5,10,5,10,5,10,5,6,5,12},{14,1,12,10,5,14,1,12,6,9,4,10,9,12,12},{14,5,10,5,12,10,5,12,12,2,15,3,1,12,12},{8,12,6,9,10,5,12,12,10,3,9,6,3,9,12},{6,9,14,3,3,9,12,10,3,3,3,9,4,6,9},{10,5,12,6,3,3,13,6,3,3,1,6,11,9,4},{6,9,12,10,5,6,11,9,6,3,3,9,6,3,13},{14,5,12,4,12,10,1,6,9,6,5,2,13,4,12},{8,10,11,9,10,3,3,11,3,9,10,3,9,10,9}};
public static final int[][] mazeProblemFour = new int[][] {{2,3,3,5,4,6,7,3,3,5,6,5,6,3,5},{6,3,1,12,12,12,10,3,5,10,9,12,10,5,12},{12,6,3,9,14,9,4,6,9,2,3,11,1,12,12},{14,9,2,3,11,5,12,10,3,5,6,3,3,9,12},{10,5,6,5,2,11,11,5,4,12,12,6,7,1,12},{4,10,9,10,3,5,6,9,12,10,9,8,12,6,13},{14,5,4,6,3,9,12,6,11,5,6,3,9,12,8},{12,10,9,12,4,6,9,10,5,12,14,3,5,10,5},{12,6,5,12,12,12,6,3,9,12,8,6,13,4,12},{14,9,10,9,12,12,10,3,5,10,5,12,10,13,12},{12,2,7,5,10,11,3,3,9,6,9,12,2,9,12},{10,3,9,10,3,3,5,4,6,11,3,9,6,3,13},{6,5,6,7,3,5,12,10,9,6,3,3,9,6,9},{12,10,9,10,5,8,12,6,5,10,5,6,5,10,5},{10,3,3,1,10,3,11,9,10,3,9,8,10,3,9}};
public static final int[][] mazeProblemFive = new int[][] {{2,3,5,6,3,3,7,5,6,3,3,3,7,3,5},{6,5,12,12,6,3,9,8,10,5,4,6,9,4,12},{12,12,12,12,10,3,5,6,5,10,13,10,5,14,9},{12,10,9,10,5,4,10,9,14,1,12,4,12,10,5},{10,5,6,5,10,15,3,1,14,5,14,9,10,5,8},{6,9,12,10,5,8,6,5,8,10,9,6,5,14,5},{10,3,9,4,12,6,9,10,3,3,3,9,12,8,12},{6,3,7,13,12,10,7,5,2,7,7,1,10,3,13},{14,1,12,8,10,5,12,12,6,9,12,6,3,3,9},{8,6,13,6,3,9,12,12,12,2,13,12,6,3,5},{6,9,8,12,4,6,9,12,14,5,8,10,9,4,12},{12,6,3,9,10,9,6,9,8,10,7,5,6,11,9},{12,10,3,3,3,5,14,3,3,5,12,12,10,5,4},{14,1,6,5,6,9,10,3,1,12,12,10,1,10,13},{10,3,9,10,11,3,3,3,3,9,10,3,3,3,9}};

public MazeGenerator(int x, int y) {
    this.x = x;
    this.y = y;
    maze = new int[this.x][this.y];
    generateMaze(0, 0);
}

public void display() {
    for (int i = 0; i < y; i++) {
        // draw the bbc.north edge
        for (int j = 0; j < x; j++) {
            System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+   ");
        }
        System.out.println("+");
        // draw the west edge
        for (int j = 0; j < x; j++) {
            System.out.print((maze[j][i] & 8) == 0 ? "|   " : "    ");
        }
        System.out.println("|");
    }
    // draw the bottom line
    for (int j = 0; j < x; j++) {
        System.out.print("+---");
    }
    System.out.println("+");
}

private void generateMaze(int cx, int cy) {
    DIR[] dirs = DIR.values();
    Collections.shuffle(Arrays.asList(dirs));
    for (DIR dir : dirs) {
        int nx = cx + dir.dx;
        int ny = cy + dir.dy;
        if (between(nx, x) && between(ny, y)
                && (maze[nx][ny] == 0)) {
            maze[cx][cy] |= dir.bit;
            maze[nx][ny] |= dir.opposite.bit;
            generateMaze(nx, ny);
        }
    }
}

private static boolean between(int v, int upper) {
    return (v >= 0) && (v < upper);
}

public int[][] maze() {
    return maze;
}

private enum DIR {
    N(1, 0, -1), S(2, 0, 1), E(4, 1, 0), W(8, -1, 0);
    private final int bit;
    private final int dx;
    private final int dy;
    private DIR opposite;

    // use the static initializer to resolve forward references
    static {
        N.opposite = S;
        S.opposite = N;
        E.opposite = W;
        W.opposite = E;
    }

    private DIR(int bit, int dx, int dy) {
        this.bit = bit;
        this.dx = dx;
        this.dy = dy;
    }
};

public static void main(String[] args) {
    int x = args.length >= 1 ? (Integer.parseInt(args[0])) : 8;
    int y = args.length == 2 ? (Integer.parseInt(args[1])) : 8;
    MazeGenerator maze = new MazeGenerator(x, y);
    maze.display();
}
}

如何修复代码,以便在每次点击按钮后正确清除迷宫?我错过了什么吗?

2 个答案:

答案 0 :(得分:1)

在清除画布之前删除BoxBlur效果,然后重新应用它。清除画布只需涂上透明色。所以BoxBlur效果也会影响到它。

jewelsea说的是什么。如果您只将代码减少到最低限度,您就可以自己找到它; - )

答案 1 :(得分:0)

对于正在寻找答案的人们,它可能无法正常工作的另一个原因是,如果您将GraphicsContext.globalBlendMode设置为BlendMode.SCREEN之类的话。

由于clearRect()用透明像素绘制画布,所以透明像素在该BlendMode中将无效。

在致电gc.globalBlendMode = BlendMode.SRC_OVER之前设置clearRect()