The class GridGuiOne.java is a Jpanel using a GridLayout
For a 9x9 Sudoku it will be composed by a 3x3 GridLayout into where the 9 regions will be inserted into 3 rows and 3 columns.
Each region will be also a GridLayout 3x3 for the 3 rows and 3 columns of each region.
So one big JPanel which the class extends into which 9 JPanels created within the class.
The constructor receives an instance of the Grid class to build all the panels from the cells contained in the region[] RowColReg array.
The main() method can be used as unit test to test the panel. It builds a JFrame and put the GridGuiOne into it.
import javax.swing.*;
import java.awt.*;
/*
* A Basic JPanel to display the cells
*/
public class GridGuiOne extends JPanel {
private static final long serialVersionUID = 1L;
// Constructor receives an instance of class Grid as parameter
GridGuiOne(Grid grid) {
// get the regions from the Grid
RowColReg[] region = grid.getRegion();
// get the size to get the number of row and column in each region
// and the total of regions per row/column
int size = (int) Math.sqrt((double) region.length);
// this (the main panel) will contain size X size regions
setLayout(new GridLayout(size, size));
// now we will build the other panels (one for each region)
for(int i = 0; i < region.length; i++) {
JPanel p = new JPanel(new GridLayout(size, size));
p.setBorder(BorderFactory.createLineBorder(Color.BLACK));
// get the cells from that region
Cell[] cell = region[i].getCells();
// add the cell to the grid
for(int j = 0; j < cell.length; j++) {
p.add(cell[j]);
}
// then add this panel of a region to the big grid
add(p);
}
}
/*
* To test the Grid
*/
public static void main(String[] atgs) {
// create a JFrame to hold the Grid
JFrame frame = new JFrame("First GUI demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// Build a Grid of size 9
Grid grid = new Grid(9);
// load the grid with predefined problem
Problems.setProblem3(grid);
// ask the Grid to react to keyboard event
grid.registerForKeyboardEvent();
// build a GridGuiOne from that Grid object
GridGuiOne ggo = new GridGuiOne(grid);
// add the Grid to the Frame
frame.add(ggo);
// make it visible
frame.setVisible(true);
frame.pack();
}
}
You can play with the cursor to move from one the to another.
You can enter a value on cells, if the value you enter is valid for that cell.
The Problem class has been upgraded to add a new problem.
The Cell class has been updated to remove the focus listener if no key listener are installed.
Problems.java
/**
* A class that contains, for test purpose, the setters for different
* Sudoku problems
*/
public class Problems {
/*
* private method called by the others to load a problem
*/
private static void load(Grid grid, int[][] val) {
// clear grid because if it already contains something
// the setOriginalProblemValue might reject to set a cell to a value already there
for(int i = 0; i < val.length; i++) {
for(int j = 0; j < val[i].length; j++) {
grid.setCellValue(i, j, 0);
}
}
// load with new problem
for(int i = 0; i < val.length; i++) {
for(int j = 0; j < val[i].length; j++) {
grid.setOriginalProblemValue(i, j, val[i][j]);
}
}
}
// preregistered problem 1
public static void setProblem1(Grid grid) {
int[][] val = {
{0, 0, 0, 0, 0, 7, 0, 0, 0},
{3, 0, 0, 0, 6, 0, 0, 5, 0},
{7, 0, 0, 9, 2, 0, 0, 1, 0},
{0, 8, 0, 0, 3, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 5, 0, 6},
{9, 0, 0, 6, 0, 8, 0, 0, 0},
{0, 0, 0, 0, 1, 3, 6, 0, 0},
{0, 0, 0, 5, 0, 0, 1, 2, 0},
{0, 9, 0, 0, 0, 0, 7, 0, 3}
};
// loat it with my values
load(grid, val);
}
/*
* preregisterd problem 2
* this is kind of worst case for brute force
* no clue on top row where the only solution is 987654321
* so a huge amount of iterations will be required
* this a good problem to test in the brute force with reverse in BruteForceGui.java
* (may be not with the GUI version it would take a while :-))
*/
public static void setProblem2(Grid grid) {
int[][] val = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 3, 0, 8, 5},
{0, 0, 1, 0, 2, 0, 0, 0, 0},
{0, 0, 0, 5, 0, 7, 0, 0, 0},
{0, 0, 4, 0, 0, 0, 1, 0, 0},
{0, 9, 0, 0, 0, 0, 0, 0, 0},
{5, 0, 0, 0, 0, 0, 0, 7, 3},
{0, 0, 2, 0, 1, 0, 0, 0, 0},
{0, 0, 0, 4, 0, 0, 0, 0, 9}
};
// loat it with my values
load(grid, val);
}
/*
* and almost done Sudoku problem to see the BruteForce GUI in action
* the top part if almost done so the reversed method should be slower
* on that one
*/
public static void setProblem3(Grid grid) {
int[][] val = {
{6, 1, 9, 2, 8, 4, 5, 7, 3},
{3, 7, 0, 5, 1, 6, 4, 0, 9},
{4, 5, 2, 0, 7, 0, 8, 0, 0},
{7, 4, 5, 9, 0, 3, 1, 0, 0},
{2, 0, 0, 8, 5, 1, 7, 9, 0},
{8, 9, 1, 0, 2, 0, 3, 6, 0},
{5, 0, 0, 6, 3, 0, 9, 0, 1},
{0, 0, 3, 0, 0, 2, 6, 0, 7},
{1, 0, 4, 0, 9, 0, 0, 0, 0}
};
// loat it with my values
load(grid, val);
}
/*
* To unit test the whole thing
*/
public static void main(String[] args) {
// create a Grid
Grid grid = new Grid(9);
// fill and print it
setProblem1(grid);
grid.printGrid();
// fill and print it
setProblem2(grid);
grid.printGrid();
// fill and print it
setProblem3(grid);
grid.printGrid();
}
}
Cell.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/*
* A Sudoku cell as it might be used in a GUI make it a JLabel
* by extending the JLabel class
*/
public class Cell extends JLabel implements FocusListener, MouseListener, KeyListener {
private static final long serialVersionUID = 1L;
// the font use for displaying the label
private static Font labelFont, boldFont;
// the background for the cell that hasfocus
private static Color lightYellow = new Color(255, 255, 125);
// at first invocation create our fonts
static {
JLabel l = new JLabel(); // build a temp label to get standard font
Font font = l.getFont(); // get the Font
// make a font 2 times the original size (which will be considered bold)
boldFont = font.deriveFont(font.getStyle(), (int) (font.getSize2D() * 2.0));
// a smaller font for the cell not part of the original problem
labelFont = boldFont.deriveFont(boldFont.getStyle() ^ Font.BOLD);
}
// the String representation of the point
private String str;
// the value of the cell
private int value;
// if the value is part of the original problem
private boolean originalProblem;
// the cell position
private Point point;
// an ArrayList to register the SudokuCellKbListener that want to be informed when a
// a the keyboard is press
private ArrayList<SudokuCellKbListener> listenerList;
/*
* Constructor
*/
public Cell(int x, int y) {
super(" ");
point = new Point(x, y);
str = String.format("(%02d,%02d)", x, y);
// have the number centered
setHorizontalAlignment(SwingConstants.CENTER);
// make it opaque to it will have a background
setOpaque(true);
setBackground(Color.WHITE);
// give it a border
setBorder(BorderFactory.createLineBorder(Color.BLACK));
// the font to use
setFont(labelFont);
// the arrayList for the listener of the keyboard
listenerList = new ArrayList<SudokuCellKbListener>();
}
/*
* Returns the cell value
*/
public int getValue() {
return value;
}
/*
* Returns cell position (mostly for debug purpose)
*/
public Point getPosition() {
return point;
}
/*
* Reset a cell
*/
private void reset(int val, boolean original) {
value = val;
// if value == 0 we put originalProblem to false and set the label at " "
if(value == 0) {
originalProblem = false;
setText(" ");
return;
}
originalProblem = original;
setText(" " + Integer.toString(value, Character.MAX_RADIX).toUpperCase() + " ");
// determine the font based on the type
if(originalProblem)
setFont(boldFont);
else
setFont(labelFont);
}
/*
* Set the value for an original problem
*/
public void setOriginalProblemValue(int value) {
reset(value, true);
}
/*
* Set the value for a user guess or solver
*/
public void setValue(int value) {
reset(value, false);
}
// getter for the type of value
public boolean isOriginalProblem() {
return originalProblem;
}
/*
* The method that overloads toString() that return the value
*/
public String toString() {
// for text display so we also pass the 0
return Integer.toString(value, Character.MAX_RADIX).toUpperCase();
}
/*
* To return the unique Id as a String
*/
public String getIdStr() {
return str;
}
/*
* The two method invoked when the cell gain or loose focus
*/
@Override
public void focusGained(FocusEvent e) {
setBackground(lightYellow);
}
@Override
public void focusLost(FocusEvent e) {
setBackground(Color.WHITE);
}
/*
* The mouse listener to gain focus when a cell is cliked
* only pressed is used
*/
@Override
public void mousePressed(MouseEvent e) {
requestFocusInWindow(); // give focus to that cell
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
/*
* to register to have the keyboard event relayed
*/
public void registerCellKbListener(SudokuCellKbListener listener) {
// at the first call, when the arrayList is empty, register this as keyLlistener
// to react to keyBoard key pressed and make the cells focusable
if(listenerList.size() == 0) {
// labels by default are not focusable make it focusable
setFocusable(true);
// and add them a focus listener so we can change the background color
addFocusListener(this);
// amouse listener to be able to select the cell by clicking over it with the mouse
addMouseListener(this);
addKeyListener(this);
// disable the fact that a TAB will bring me to next JLabel
setFocusTraversalKeysEnabled(false);
}
// add this listener to our list
listenerList.add(listener);
}
/*
* The KeyListener methods
*/
@Override
public void keyPressed(KeyEvent ev) {
// pass through our list to prevent all the possible listener
for(SudokuCellKbListener listener : listenerList) {
listener.keyPressed(this, point.x , point.y, ev);
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
This post has been edited by pbl: 21 October 2010 - 04:48 PM





MultiQuote


|