Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
769 views
in Technique[技术] by (71.8m points)

css - Sudoku GUI Grid Lines

Stack Overflow first timer here!

First off, I'm creating a Sudoku Solver using JavaFX. I've got everything working, however, the only issue I'm having is creating the bolded 3x3 big blocks with 3x3 cells inside each big block. I've tried creating 2 'for' loops for the big blocks followed by 2 more 'for' loops for each small TextField cell. However, accessing those cells seem impossible since then I'd be technically creating a 4-D array and I somehow have to access that mess.

Hence, I backed off on the aesthetics and worked with 9x9 TextField cells without the appropriate Sudoku lines. It works with the solver, but now I want to add in those lines, since I might as well make it look like a legit Sudoku grid. Thought about using CSS, but nth-child does not work with JavaFX CSS. Thank you, yall!

    public class SudokuGUI extends Application {

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

public static LimitedNumberTextField[][] tf2D = 
        new LimitedNumberTextField[9][9];
public static int[][] tf2DVal = new int[9][9];
public static int[][] output = SudokuSolver.output;
public static int[][] zeroBoard = SudokuSolver.zeroSudoku;

@Override
public void start(Stage mainStage) throws Exception {

    //Solve Button
    Button solveButton = new Button("Solve");
    solveButton.setMaxWidth(Double.MAX_VALUE);
    solveButton.setStyle("-fx-background-color: "
            + "linear-gradient(#f2f2f2, #d6d6d6), "
            + "linear-gradient(#fcfcfc 0%, #d9d9d9 20%, #d6d6d6 100%),"
            + "linear-gradient(#dddddd 0%, #f6f6f6 50%);"
            + "-fx-background-radius: 8,7,6;"
            + "-fx-background-insets: 0,1,2;" 
            + "-fx-text-fill: black;"
            + "-fx-effect: dropshadow( three-pass-box , "
            + "rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 );");

    //Reset Button
    Button resetButton = new Button("Reset");
    resetButton.setMaxWidth(Double.MAX_VALUE);
    resetButton.setStyle("-fx-background-color: "
            + "linear-gradient(#f2f2f2, #d6d6d6), "
            + "linear-gradient(#fcfcfc 0%, #d9d9d9 20%, #d6d6d6 100%),"
            + "linear-gradient(#dddddd 0%, #f6f6f6 50%);"
            + "-fx-background-radius: 8,7,6;"
            + "-fx-background-insets: 0,1,2;" 
            + "-fx-text-fill: black;"
            + "-fx-effect: dropshadow( three-pass-box , "
            + "rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 );");

    //Grid
    GridPane grid = new GridPane();
    grid.setPadding(new Insets(40, 40, 40, 40));

    //Setting the grid to the scene.
    Scene scene = new Scene(grid);

    // Will hold the 2 buttons in a vBox.
    VBox vb = new VBox();
    vb.setPadding(new Insets(10, 0, 0, 30));
    vb.setSpacing(10);
    vb.getChildren().addAll(solveButton, resetButton);

    GridPane.setRowIndex(vb, 0);
    GridPane.setColumnIndex(vb, 4);

    // Adds in the vBox consisting of the 2 buttons onto the GridPane.
    grid.getChildren().add(vb);

    grid.setStyle("-fx-background-color: linear-gradient(to bottom, "
            + "#cedbe9 0%,#aac5de 17%,#6199c7 50%,#3a84c3 51%,"
            + "#419ad6 59%,#4bb8f0 71%,#3a8bc2 84%,#26558b 100%);");

    // Creation of Sudoku grid consisting of 81 total cells.
    GridPane box = new GridPane();
        box.setStyle("-fx-background-color: black, "
                + "-fx-control-inner-background; "
                + "-fx-background-insets: 0, 2; " 
                + "-fx-padding: 4;"
                + "-fx-grid-lines-visible: true;");
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                LimitedNumberTextField limitNumberTextField = 
                        new LimitedNumberTextField(1);
                limitNumberTextField.setStyle(
                        "-fx-pref-width: 3em; " 
                        + "-fx-pref-height: 3em;");
                GridPane.setConstraints(limitNumberTextField, row, col);
                box.getChildren().add(limitNumberTextField);

                if (limitNumberTextField.getText().equals("")) {
                    limitNumberTextField.setText("0");
                }
                tf2D[row][col]= limitNumberTextField;

                tf2DVal[row][col] = Integer
                        .parseInt(limitNumberTextField.getText());

                if (limitNumberTextField.getText().equals("0")) {
                    limitNumberTextField.setText("");
                    tf2D[row][col] = limitNumberTextField;
                }
            }
        }

    grid.getChildren().add(box);

    //Action Listeners for the buttons.
    try {
        solveButton.setOnAction(e -> {
            getBoard();
            setBoard(tf2DVal);

            if (isZeroBoard(tf2DVal)) {
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle(" No values!! ");
                alert.setHeaderText(null);
                alert.setContentText(
                        " Please input some values and try again.");
                alert.showAndWait();
                return;
            }
            try {
                SudokuSolver.solveIt(tf2DVal);
            } catch (Exception e1) {
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle(" Invalid Sudoku board! ");
                alert.setHeaderText(null);
                alert.setContentText(" Your input is invalid! 
"
                        + " Please check your board and try again.");
                alert.showAndWait();
            }
            setFinalBoard();
        });

        resetButton.setOnAction(e -> {
            getBoard();
            resetBoard();
        });

        //Shows hand when hovered over. 
        solveButton.setOnMouseEntered(e -> {
            solveButton.setCursor(Cursor.HAND);
        });

        resetButton.setOnMouseEntered(e -> {
            resetButton.setCursor(Cursor.HAND);
        });

    } catch (Exception e) { // In case there is no solution. Not likely. 
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setTitle(" No Solution Found! ");
        alert.setHeaderText(null);
        alert.setContentText(
                "Please check your board and try again. ");
        alert.showAndWait();
    }
    mainStage.setTitle("Sudoku Solver");
    mainStage.getIcons().add(new Image("file:logo_icon.png"));
    mainStage.setScene(scene);
    mainStage.show();
}

//Reading the values of the Sudoku. 
public static void getBoard() {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            LimitedNumberTextField ltf = tf2D[i][j];
            if (ltf.getText().equals("")) {
                ltf.setText("0");
            }

            tf2DVal[i][j] = 0;
            tf2DVal[i][j] = Integer.parseInt(ltf.getText());

            if (ltf.getText().equals("0")) {
                ltf.setText("");
                tf2D[i][j] = ltf;
            }

        }
    }
}

//Setting the values to the board. 
public static void setBoard(int[][] board) {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            tf2DVal[i][j] = board[i][j];

            if (tf2D[i][j].getText().equals("")) {
                tf2D[i][j].setText("0");
            }

            tf2D[i][j].setText(Integer.toString(tf2DVal[i][j]));

            if (tf2D[i][j].getText().equals("0")) {
                tf2D[i][j].setText("");
            }
        }
    }
}

//Method to set the final value after it is solved. 
public static void setFinalBoard() {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            tf2DVal[i][j] = output[i][j];
            if (tf2D[i][j].getText().equals("")) {
                tf2D[i][j].setText("0");
            }
            tf2D[i][j].setText(Integer.toString(tf2DVal[i][j]));
            if (tf2D[i][j].getText().equals("0")) {
                tf2D[i][j].setText("");
            }
        }
    }
}

//Resets the board.
public static void resetBoard() {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            tf2D[i][j].setText("");
        }
    }
}

//This method compares the board to a board with all zeros. 
public static boolean isZeroBoard(int[][] input) {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (!(input[i][j] == zeroBoard[i][j])) {
                return false;
            }
        }
    }
    return true;
}

}

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The basic idea I would use is to put the text fields inside another container (e.g. a StackPane) and then add some style to the stack pane. You should use an external style sheet to define the styles.

As the style depends on the location of the cell inside the "block", you need to somehow manipulate the style class depending on that location. Essentially you need a border on the bottom for rows 2 and 5, and a border on the right for columns 2 and 5. I think the cleanest way to do that part is to set or unset CSS PseudoClasses to indicate if the cell is in the right column, or bottom row of the respective blocks.

To generate the actual borders, use a "nested background" approach. The basic idea is to paint two rectangular backgrounds. The first is for the border, and fills the entire space. The second is for portion inside the border, and is painted over the top of the first, but with a 1 pixel inset along the edges where you want the border visible.

The CSS looks like:

sudoku.css:

.root {
    -fx-padding: 5px ;
}

.cell {

    /* Defines a black border around the standard color -fx-base */
    -fx-background-color:  black, -fx-base ;

    /* By default draw the base color over the whole region, so no border visible */
    -fx-background-insets: 0, 0 ;

    -fx-padding: 5px ;
}

.cell:right {
    -fx-background-insets: 0, 0 1 0 0 ;
}

.cell:bottom {
    -fx-background-insets: 0, 0 0 1 0 ;
}

.cell:right:bottom {
    -fx-background-insets: 0, 0 1 1 0 ;
}

.cell .text-field {
    -fx-pref-width: 3em ;
    -fx-pref-height: 3em ;
}

And here's a sample that uses it:

import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class SudokuBoard extends Application {

    @Override
    public void start(Stage primaryStage) {

        GridPane board = new GridPane();

        PseudoClass right = PseudoClass.getPseudoClass("right");
        PseudoClass bottom = PseudoClass.getPseudoClass("bottom");

        for (int col = 0; col < 9; col++) {
            for (int row = 0; row < 9; row++) {
                StackPane cell = new StackPane();
                cell.getStyleClass().add("cell");
                cell.pseudoClassStateChanged(right, col == 2 || col == 5);
                cell.pseudoClassStateChanged(bottom, row == 2 || row == 5);

                cell.getChildren().add(createTextField());

                board.add(cell, col, row);
            }
        }


        Scene scene = new Scene(board);
        scene.getStylesheets().add("sudoku.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TextField createTextField() {
        TextField textField = new TextField();

        // restrict input to integers:
        textField.setTextFormatter(new TextFormatter<Integer>(c -> {
            if (c.getControlNewText().matches("\d?")) {
                return c ;
            } else {
                return null ;
            }
        }));
        return textField ;
    }

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

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...