Create a Chess board with JPanel

Jamgreen picture Jamgreen · Jan 12, 2014 · Viewed 73.6k times · Source

I have a simple Chess board in a JPanel with GridLayout(8,8) as layout manager.

I am trying to add panels for the fields' column name and row number.

Right now I've created another panel with BorderLayout as layout manager, and in this panel I add the board in BorderLayout.CENTER. Next to the board itself I've added a panels with GridLayout(0,8) in BorderLayout.SOUTH and a panel with GridLayout(8,0) in BorderLayout.WEST. The rows numbers is perfectly placed next to the board because the number of rows in the left JPanel matches the number of rows in the board, but the column names (A, B, C, D, E, F, G, H) in the JPanel under the board is not placed correctly because of the JPanel in BorderLayout.WEST.

What can I do to make a proper Chess board with side panels to show the field numbers/names?

I've tried setting the layout for the south panel to GridLayout(0,9) and have the first field empty, but the width of the left panel is not equal to each field in the board, so it's not a good workaround.

Answer

Andrew Thompson picture Andrew Thompson · Jan 13, 2014

Note

The GUI seen here has been improved and moved to Making a robust, resizable Swing Chess GUI.

I will leave the animated GIF here (because it's cute) and the original, stripped down code (of just 125 code lines, the final code seen on the other thread is 218 LOC).

Chess Game Layout

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;

public class ChessBoardWithColumnsAndRows {

    private final JPanel gui = new JPanel(new BorderLayout(3, 3));
    private JButton[][] chessBoardSquares = new JButton[8][8];
    private JPanel chessBoard;
    private final JLabel message = new JLabel(
            "Chess Champ is ready to play!");
    private static final String COLS = "ABCDEFGH";

    ChessBoardWithColumnsAndRows() {
        initializeGui();
    }

    public final void initializeGui() {
        // set up the main GUI
        gui.setBorder(new EmptyBorder(5, 5, 5, 5));
        JToolBar tools = new JToolBar();
        tools.setFloatable(false);
        gui.add(tools, BorderLayout.PAGE_START);
        tools.add(new JButton("New")); // TODO - add functionality!
        tools.add(new JButton("Save")); // TODO - add functionality!
        tools.add(new JButton("Restore")); // TODO - add functionality!
        tools.addSeparator();
        tools.add(new JButton("Resign")); // TODO - add functionality!
        tools.addSeparator();
        tools.add(message);

        gui.add(new JLabel("?"), BorderLayout.LINE_START);

        chessBoard = new JPanel(new GridLayout(0, 9));
        chessBoard.setBorder(new LineBorder(Color.BLACK));
        gui.add(chessBoard);

        // create the chess board squares
        Insets buttonMargin = new Insets(0,0,0,0);
        for (int ii = 0; ii < chessBoardSquares.length; ii++) {
            for (int jj = 0; jj < chessBoardSquares[ii].length; jj++) {
                JButton b = new JButton();
                b.setMargin(buttonMargin);
                // our chess pieces are 64x64 px in size, so we'll
                // 'fill this in' using a transparent icon..
                ImageIcon icon = new ImageIcon(
                        new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB));
                b.setIcon(icon);
                if ((jj % 2 == 1 && ii % 2 == 1)
                        //) {
                        || (jj % 2 == 0 && ii % 2 == 0)) {
                    b.setBackground(Color.WHITE);
                } else {
                    b.setBackground(Color.BLACK);
                }
                chessBoardSquares[jj][ii] = b;
            }
        }

        //fill the chess board
        chessBoard.add(new JLabel(""));
        // fill the top row
        for (int ii = 0; ii < 8; ii++) {
            chessBoard.add(
                    new JLabel(COLS.substring(ii, ii + 1),
                    SwingConstants.CENTER));
        }
        // fill the black non-pawn piece row
        for (int ii = 0; ii < 8; ii++) {
            for (int jj = 0; jj < 8; jj++) {
                switch (jj) {
                    case 0:
                        chessBoard.add(new JLabel("" + (ii + 1),
                                SwingConstants.CENTER));
                    default:
                        chessBoard.add(chessBoardSquares[jj][ii]);
                }
            }
        }
    }

    public final JComponent getChessBoard() {
        return chessBoard;
    }

    public final JComponent getGui() {
        return gui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                ChessBoardWithColumnsAndRows cb =
                        new ChessBoardWithColumnsAndRows();

                JFrame f = new JFrame("ChessChamp");
                f.add(cb.getGui());
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                // ensures the frame is the minimum size it needs to be
                // in order display the components within it
                f.pack();
                // ensures the minimum size is enforced.
                f.setMinimumSize(f.getSize());
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

Notes

  • The chess board complete with columns on the left and a row above it is provided by a 9x9 GridLayout. The first cell of the grid layout is a label with no text.
  • To simplify the game logic though, we maintain a separate 8x8 array of buttons.
  • To allow keyboard functionality we use buttons for the chess board places. This also provides inbuilt focus indication. Remove the margin of the button to allow them to shrink to the size of the icon. Add an ActionListener to the button and it will respond to both keyboard and mouse events.
  • The small ? in the left hand side of the GUI is meant to imply that area is 'reserved for future use'. We might use it to show lists of captured pieces, a selector for choice of piece when promoting pawns, game statistics, ...
  • The chess piece images were obtained from Example images for code and mark-up Q&As, which was in turn developed out of 'Fill' Unicode characters in labels.

    Using images is simpler, whereas filling Unicode characters is more versatile as well as being 'lighter'. I.E. to support 4 different colors in 3 separate sizes of 3 different chess piece styles would require 36 separate sprite sheets!