数独板在Java中使用JPanels

时间:2012-10-14 20:25:06

标签: java arrays swing 2d sudoku

我知道已经有几篇关于数独相关问题的帖子,但我不确定它们中是否有任何我正在寻找的......

我正在尝试使用JPanels和JTextfields在Java中构建一个空的Sudoku板。我还需要在右侧创建一个带有另一个JPanel的菜单。

电路板本身是一个9 x 9的正方形,分为9个3x3正方形。请注意,每个较小的正方形都由比正常的方形边框更重的边框设置。每个方块都是一个文本字段。编写程序,以便文本字段中没有任何内容。用户可以根据需要输入文本字段,如果需要,则会显示数字。在侧面有四个按钮,可以让你解决,获得一个新的谜题,获得提示,或重置谜题。

任何想法都会很棒。我无法理解如何嵌套for循环来创建电路板。这是我的代码......

    import javax.swing.*;
    import javax.swing.border.Border;
    import java.awt.*;

    public class ArrayTest extends JFrame {

        public ArrayTest() {

    JPanel board = new JPanel(new GridLayout(9, 9));
    add(board);

    JPanel[][] squares = new JPanel[9][9];

    Border border = BorderFactory.createLineBorder(Color.BLACK);


    for (int row = 1; row < 9; row++) {

        for (int col = 1; col < 9; col++) {
            squares[row][col] = new JPanel();
            board.add(squares[row][col]);

        }

    }



    JPanel menu = new JPanel();
    menu.add(new JButton("Reset"));
    menu.add(new JButton("Hint"));
    menu.add(new JButton("Solve"));
    menu.add(new JButton("New Puzzle"));



    add(menu);

}
public static void main(String[] args) {
    // TODO Auto-generated method stub

    /** Create a frame and set its properties*/
    JFrame frame = new ArrayTest();
    frame.setTitle("Sudoku");
    frame.setSize(600, 600);
    frame.setLocationRelativeTo(null); //Center the frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

}

}

2 个答案:

答案 0 :(得分:6)

我看到的一些事情:

  • 我认为您现在不需要9x9 JPanel,而是9x9 JTextField s。您可能需要3x3 JPanel s,这样您就可以使每个部分的边框更加大胆。可能更容易明确地列出这些而不是试图在循环中进行。

  • 你的循环计数器(和数组索引)应该从0开始,而不是1.你现在的方式,循环只会执行8次。

  • 您将要跟踪每行,每列和每个3x3子组中的值。行和列很容易在2D数组中使用。您可以考虑使用另一个数组来保存每个3x3区域中的值。这样可以在需要时更轻松地扫描这些值,如果您沿着这条路线行进,则可能有助于将值放在较小的3x3 JPanel中。

答案 1 :(得分:5)

首先,我会使用某种模型来控制“虚拟”板内的值,这会将逻辑与UI分开,并允许更改而不会对另一个产生负面影响。

我会为模型提供适当的事件,以便在模型更改时更新UI,并为每个字段提供根据需要更新模型的方法。

然后我会将问题减少到它最小的概念组件,它将成为子板,并生成UI以最抽象的方式表示它。这允许重复使用并有助于调试,就好像一个板有问题,然后您可以在一个地方为所有人修复它。

public class Sudoku {

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

    public Sudoku() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new SudokuBoard());
                frame.add(new MenuPane(), BorderLayout.AFTER_LINE_ENDS);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    public class MenuPane extends JPanel {

        public MenuPane() {
            setBorder(new EmptyBorder(4, 4, 4, 4));
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            add(new JButton("Solve"), gbc);
            gbc.gridy++;
            add(new JButton("New"), gbc);
            gbc.gridy++;
            add(new JButton("Hint"), gbc);
            gbc.gridy++;
            add(new JButton("Reset"), gbc);
        }
    }

    public class SudokuBoard extends JPanel {

        public static final int ROWS = 3;
        public static final int COLUMNS = 3;

        private SubBoard[] subBoards;

        public SudokuBoard() {
            setBorder(new EmptyBorder(4, 4, 4, 4));
            subBoards = new SubBoard[ROWS * COLUMNS];
            setLayout(new GridLayout(ROWS, COLUMNS, 2, 2));
            for (int row = 0; row < ROWS; row++) {
                for (int col = 0; col < COLUMNS; col++) {
                    int index = (row * ROWS) + col;
                    SubBoard board = new SubBoard();
                    board.setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 3), new EmptyBorder(4, 4, 4, 4)));
                    subBoards[index] = board;
                    add(board);
                }
            }
        }
    }

    public class SubBoard extends JPanel {

        public static final int ROWS = 9;
        public static final int COLUMNS = 9;

        private JTextField[] fields;

        public SubBoard() {
            setLayout(new GridLayout(ROWS, COLUMNS, 2, 2));
            fields = new JTextField[ROWS * COLUMNS];
            for (int row = 0; row < ROWS; row++) {
                for (int col = 0; col < COLUMNS; col++) {
                    int index = (row * COLUMNS) + col;
                    JTextField field = new JTextField(4);
                    fields[index] = field;
//                    field.setText(Integer.toString(index));
                    add(field);
                }
            }
        }
    }
}

<强>已更新

要将文本字段限制为仅允许输入数字值,您可以查看JTextField limiting character amount input and accepting numeric only了解某些想法

enter image description here

更新(使用2D数组)

这是一个使用2D数组的实现,它还对子板进行子组合,以便3x3字段的每个网格都有自己的板...

enter image description here

public class Sudoku {

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

    public Sudoku() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new SudokuBoard());
                frame.add(new MenuPane(), BorderLayout.AFTER_LINE_ENDS);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    public class MenuPane extends JPanel {

        public MenuPane() {
            setBorder(new EmptyBorder(4, 4, 4, 4));
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            add(new JButton("Solve"), gbc);
            gbc.gridy++;
            add(new JButton("New"), gbc);
            gbc.gridy++;
            add(new JButton("Hint"), gbc);
            gbc.gridy++;
            add(new JButton("Reset"), gbc);

        }

    }

    public class SudokuBoard extends JPanel {

        public static final int ROWS = 3;
        public static final int COLUMNS = 3;

        private SubBoard[][] subBoards;

        public SudokuBoard() {
            setBorder(new EmptyBorder(4, 4, 4, 4));
            subBoards = new SubBoard[ROWS][COLUMNS];
            setLayout(new GridLayout(ROWS, COLUMNS, 2, 2));
            for (int row = 0; row < ROWS; row++) {
                for (int col = 0; col < COLUMNS; col++) {
                    int index = (row * ROWS) + col;
                    SubBoard board = new SubBoard();
                    board.setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 3), new EmptyBorder(4, 4, 4, 4)));
                    subBoards[row][col] = board;
                    add(board);
                }
            }
        }

    }

    public class SubBoard extends JPanel {

        public SubBoard() {
            setLayout(new GridLayout(3, 3, 2, 2));

            for (int index = 0; index < 3*3; index++) {
                add(new ChildBoard(3, 3));
            }

        }
    }

    public class ChildBoard extends JPanel {

        private JTextField[][] fields;

        public ChildBoard(int rows, int cols) {
            setBorder(new LineBorder(Color.LIGHT_GRAY));
            setLayout(new GridLayout(rows, cols, 2, 2));
            fields = new JTextField[rows][cols];
            for (int row = 0; row < rows; row++) {
                for (int col = 0; col < cols; col++) {
                    JTextField field = new JTextField(4);
                    fields[row][col] = field;
                    add(field);
                }
            }
        }

    }
}

或者,如果您想尝试将所有字段保留在单个顶级参考中,您可以执行以下操作...

public class SubBoard extends JPanel {

    private JTextField[][] fields;

    public SubBoard() {
        setLayout(new GridLayout(3, 3, 2, 2));

        fields = new JTextField[9][9];
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                fields[row][col] = new JTextField(4);
            }
        }

        for (int row = 0; row < 3; row++) {
            for (int col = 0; col < 3; col++) {

                int startRow = row * 3;
                int startCol = col * 3;

                add(new ChildBoard(3, 3, fields, startRow, startCol));

            }
        }

    }
}

public class ChildBoard extends JPanel {

    public ChildBoard(int rows, int cols, JTextField[][] fields, int startRow, int startCol) {
        setBorder(new LineBorder(Color.LIGHT_GRAY));
        setLayout(new GridLayout(rows, cols, 2, 2));
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                JTextField field = fields[startRow + row][startCol + col];
                fields[row][col] = field;
                add(field);
            }
        }
    }

}

使用单一类更新

好吧,那么不要再进行子类化,只需使用几种方法来创建电路板的每个部分,您可以从中重复调用...

enter image description here

记住,减少和重复使用。

public class Sudoku {

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

    public Sudoku() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new SudokuBoard());
                frame.add(new MenuPane(), BorderLayout.AFTER_LINE_ENDS);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    public class MenuPane extends JPanel {

        public MenuPane() {
            setBorder(new EmptyBorder(4, 4, 4, 4));
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            add(new JButton("Solve"), gbc);
            gbc.gridy++;
            add(new JButton("New"), gbc);
            gbc.gridy++;
            add(new JButton("Hint"), gbc);
            gbc.gridy++;
            add(new JButton("Reset"), gbc);

        }
    }

    public class SudokuBoard extends JPanel {

        public static final int GRID_ROWS = 3;
        public static final int GRID_COLUMNS = 3;
        public static final int BOARD_ROWS = 9;
        public static final int BOARD_COLUMNS = 9;
        private JTextField fields[][];

        public SudokuBoard() {
            setBorder(new EmptyBorder(4, 4, 4, 4));
            fields = new JTextField[GRID_ROWS * BOARD_ROWS][GRID_COLUMNS * BOARD_COLUMNS];

            setLayout(new GridLayout(GRID_ROWS, GRID_COLUMNS, 2, 2));
            for (int row = 0; row < GRID_ROWS; row++) {
                for (int col = 0; col < GRID_COLUMNS; col++) {
                    int startRow = row * GRID_ROWS;
                    int startCol = col * GRID_COLUMNS;
                    add(createBoard(fields, startRow, startCol));
                }
            }
        }

        protected JPanel createBoard(JTextField fiels[][], int startRow, int startCol) {
            JPanel panel = new JPanel(new GridLayout(3, 3, 2, 2));
            panel.setBorder(new CompoundBorder(new LineBorder(Color.DARK_GRAY, 2), new EmptyBorder(2, 2, 2, 2)));

            for (int row = 0; row < 3; row++) {
                for (int col = 0; col < 3; col++) {
                    int rowIndex = (startRow + row) * 3;
                    int colIndex = (startCol + col) * 3;
                    panel.add(createSubBoard(fields, rowIndex, colIndex));
                }
            }
            return panel;
        }

        protected JPanel createSubBoard(JTextField[][] fields, int startRow, int startCol) {
            JPanel panel = new JPanel(new GridLayout(3, 3, 2, 2));
            panel.setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 2), new EmptyBorder(2, 2, 2, 2)));

            populateFields(fields, startRow, startCol);
            for (int row = 0; row < 3; row++) {
                for (int col = 0; col < 3; col++) {
                    panel.add(fields[row + startRow][col + startCol]);
                }
            }
            return panel;
        }

        protected void populateFields(JTextField[][] fields, int startRow, int startCol) {
            for (int row = startRow; row < startRow + 3; row++) {
                for (int col = startCol; col < startCol + 3; col++) {
                    fields[row][col] = new JTextField(4);
                }
            }
        }
    }
}