Sudoku Tip Using JPanels in Java

I know that there have already been several posts about Sudoku-related issues, but I'm not sure that each of them has exactly what I am looking for ...

I am trying to create an empty Sudoku board in Java using JPanels and JTextfields. I also need to create a menu on the right side with another JPanel.

The board itself is a 9 x 9 square divided into 9 3x3 squares. Note that each smaller square is defined by a heavier border than regular inter-square borders. Each square represents a text box. Write the program so that there is nothing in the text box. Users can enter a text box if they want, and if they do, numbers will be displayed. There are four buttons on the side that allow you to decide whether to get a new puzzle, get a hint or a puzzle reset.

Any ideas would be great. I am having trouble understanding how to nest for loops to create a board. Here is my code ...

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

}

+4
source share
2 answers

A few things I see:

  • I do not think you want 9x9 JPanel as it is now, but 9x9 JTextField s. You may need a 3x3 JPanel so you can make the borders of each section more bold. It might be easier to just lay them out explicitly rather than trying to do it in a loop.

  • Your loop counters (and array indices) should start at 0, not 1. Now, as you have it, loops only run 8 times.

  • You will need to keep track of the values ​​in each row, column and in each 3x3 subgroup. Rows and columns are as simple as yours in a 2D array. You can consider another array of arrays that store values ​​in each 3x3 area. This makes it easier to scan these values ​​when you need to, and can be useful for placing values ​​in smaller 3x3 JPanel s if you go along this route.

+6
source

Firstly, I would use some kind of model to manage the values ​​on the "virtual" board, this will separate the logic from the user interface and allow either to change without affecting the other.

I would provide an appropriate model event to allow the user interface to be updated when the model changes, as well as provide facilities for each field to update the model as needed.

Then I would reduce the problem to the smallest conceptual component that will be a subordinate board and create a user interface to present it in the most abstract way. This allows you to reuse it and helps with debugging, as if one board had a problem, you can fix it in one place for everyone.

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

UPDATED

To limit text fields to enter only numeric values, you can watch the JTextField character limit input and accept only numeric values for some ideas

enter image description here

UPDATED (with 2D arrays)

Here, an implementation that uses 2D arrays also subgroups the sub-boards, so each 3x3 grid of fields has its own board ...

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

or, if you want to try to save all the fields in one top-level link, you can do something like ...

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

UPDATED with one class

Ok, so instead of subclassing, just use a few methods to create each separate section of the board from which you can make repeated calls ...

enter image description here

Remember to reduce and reuse.

 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); } } } } } 
+5
source

Source: https://habr.com/ru/post/1439688/


All Articles