数独GUI网格线 [英] Sudoku GUI Grid Lines

查看:151
本文介绍了数独GUI网格线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Stack Overflow第一个计时器在这里!

Stack Overflow first timer here!

首先,我正在使用JavaFX创建一个Sudoku Solver。我已经完成了所有工作,但是,我唯一的问题是在每个大块内部创建带有3x3单元的粗体3x3大块。我已经尝试为大块创建2'for'循环,然后为每个小TextField单元创建2个'for'循环。然而,访问这些单元格似乎是不可能的,因为从那时起,我将在技术上创建一个4-D数组,我不知何故必须访问这个混乱。

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.

因此,我放弃了美学,并使用9x9 TextField单元格而没有相应的数独行。它适用于求解器,但现在我想添加这些行,因为我不妨使它看起来像一个合法的数独网格。考虑使用CSS,但是nth-child不能与JavaFX CSS一起使用。谢谢,yall!

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! \n"
                        + " 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;
}

}

推荐答案

我将使用的基本思想是将文本字段放在另一个容器中(例如 StackPane ),然后将一些样式添加到堆栈窗格。您应该使用外部样式表来定义样式。

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.

由于样式取决于块内单元格的位置,因此您需要以某种方式根据该位置操作样式类。基本上你需要在第2和第5行的底部有一个边框,在第2和第5列的右边需要一个边框。我认为最简洁的方法是设置或取消设置CSS PseudoClass es 表示如果单元格位于相应块的右列或底行中。

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.

要生成实际边框,请使用嵌套背景方法。基本的想法是绘制两个矩形背景。第一个是边界,填充整个空间。第二个是边框内部的部分,并且绘制在第一个部分的顶部,但沿边缘有1个像素插入,您希望边框可见。

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.

CSS看起来像:

sudoku.css:

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 ;
}

以下是使用它的示例:

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);
    }
}

这篇关于数独GUI网格线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆