2015-07-21 4 views
0

У меня есть код в классе MazeUI, который создает пару полей в JavaFX для ввода высоты и ширины лабиринта, который будет сгенерирован вместе с кнопкой и событием для кнопки. При нажатии «Создать лабиринт» код должен генерировать случайный лабиринт.Почему gc.clearRect не очищает полотно?

Теперь это нормально работает. Но линия, чтобы очистить полотно после лабиринта, сначала нарисована с использованием 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(); 
} 
} 

Как исправить код так, чтобы он правильно очищает Maze после каждого нажатия кнопки? Я что-то упускаю?

+2

Пожалуйста, не публикуйте столько кода для ответа на этот вопрос. Вместо этого создайте [минимальный пример] (http://stackoverflow.com/help/mcve), то, что кто-то может копировать и вставлять для запуска и репликации, но предоставляет только то количество кода, которое требуется для репликации проблемы. – jewelsea

+0

Без вставки этого кода, как вы знаете, вы можете воспроизвести проблему? Это пользовательский интерфейс, поэтому мне нужно рисовать полный холст. Единственное дополнение - это поля. Но это не так много дополнительного кода. Для создания полного лабиринта необходим код холста. Это минимальный пример для показа рабочей проблемы. –

+0

Я мог бы, вероятно, отказаться от операторов импорта (поскольку они неявные), но даже в этом случае полезно посмотреть, какие библиотеки были использованы в случае, если это проблема –

ответ

1

Удалите эффект BoxBlur, прежде чем очистить полотно, а затем повторно примените его. Очистка холста просто красится прозрачным цветом. Таким образом эффект BoxBlur повлияет и на это.

И что жемчужина сказала. Вы бы нашли это сами, если бы вы только сократили код до минимума ;-)

+0

Спасибо Roland - я думал, что буду придерживаться здесь, если кто-то знал ответ, прежде чем я смог бы выяснить. Я новичок в JavaFX, так что еще не привык к причудам. Я отчитаю, если это решит мою проблему - спасибо. –

+0

Отличное спасибо! Я решил это с помощью removeBoxBlur (gc) перед gc.clearRect и setBoxBlur (gc) после действия кнопки. removeBoxBlur (gc) по существу является gc.setEffect (null); Принял это решение. –