July 20, 2018
Hot Topics:

Building a Java ME CDC Application Using the SavaJe Phone

  • October 24, 2006
  • By Carl Quinn
  • Send Email »
  • More Articles »

Create the UI JPanel

The game's main UI is implemented using a straightforward Swing JPanel subclass.

public class SudokuPanel extends JPanel {

On construction, you set up the focus properties and add a keyboard listener to handle navigation and digit entry. The arrow keys update the selection row or column, and the digit keys modify the user's answer for the currently selected cell. After any of these changes, you call repaint() to get your changes painted.

public SudokuPanel() {
   addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
         switch (e.getKeyCode()) {
         case KeyEvent.VK_LEFT:  if (selc > 0) selc--; break;
         case KeyEvent.VK_9:
            if (!puzzle.given[selr][selc]) {
               puzzle.answer[selr][selc] = e.getKeyCode()
                  - KeyEvent.VK_1 + 1;

Before the above listener is ever invoked, you need to make sure that you have a valid Puzzle instance created. You call over to the Puzzles factory class to create a puzzle instance for you, identified by an index.

puzzle = Puzzles.newPuzzle(puzIndex);

When the user has finished a puzzle (or gets stuck and gives up), they can use the Game/New menu item that invokes this method to create a new Puzzle.

void newPuzzle() {
   puzzle = Puzzles.newPuzzle(++puzIndex);

Implementing getPreferredSize is important when running on the desktop so that the outer frame ends up with a reasonable size and not squished down to nothing.

public Dimension getPreferredSize() {
   new Dimension(9*PCW+2*MW+3, 9*PCW+2*MH+3);

The paintComponent method is the heart of the panel and performs all of the rendering. The first step in painting is to grab the graphics context in its Graphics2D form. Once you have that, you can use regular Java 2D calls to paint your panel.

public void paintComponent(final Graphics g) {
   final Graphics2D graphics = (Graphics2D) g;
   final int panelw = getWidth();
   final int panelh = getHeight();

After a few dimension calculations, you paint the white background and the yellow selection cursor:

// background rectangle
graphics.fillRect(0, 0, panelw, panelh);

// selection rectangle
int sx = origx + selc*cellw;
int sy = origy + selr*cellh;

Then the black grid lines:

// grid lines
for (int v = 0; v < 10; v++) {
   if (v%3 == 0) {


for (int h = 0; h < 10; h++) {
   if (h%3 == 0) {


Finally, you render the actual digits. You distinguish the givens from the guesses by painting the former in black and the latter in blue. You also add a quick scan for obvious invalid moves and paint those in red.

// cell labels
graphics.setFont(new Font("Arial", Font.BOLD,
FontMetrics fm = graphics.getFontMetrics();
int lh = fm.getHeight() - fm.getLeading() - fm.getDescent();

// paint the cells
for (int r = 0; r < 9; r++) {
   for (int c = 0; c < 9; c++) {
      int val = puzzle.answer[r][c];
      if (val > 0) {
         String label = Integer.toString(val);
         int lw = fm.stringWidth(label);
         int lx = origx + c*cellw + cellw/2 - lw/2;
         int ly = origy + r*cellh + cellh/2 + lh/2;
         Color tcolor = puzzle.given[r][c]
            ? Color.BLACK
            : (r == selr && c ==
               selc && !isMoveValid(puzzle.answer, r, c))
            ? Color.RED : Color.BLUE;
         graphics.drawString(label, lx, ly);

Page 3 of 4

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

By submitting your information, you agree that developer.com may send you developer offers via email, phone and text message, as well as email offers about other products and services that developer believes may be of interest to you. developer will process your information in accordance with the Quinstreet Privacy Policy.


Thanks for your registration, follow us on our social networks to keep up-to-date