Thank you for the edit. If this were my application, I'd probably do things very differently including,
- Use a grid of JLabels not JButtons. I see no need to use JButtons, and a problem in that the button would not be as visually appealing as other possible solutions.
- Either give the JLabel cells or the containing JPanel a MouseListener,
- Have the JPanel cells have no Icon and thus be empty if no checker is on them,
- Or have them hold an ImageIcon of an appropriately colored checker if they are not empty.
- You could even animate the GUI by using the glass pane to hold a JPanel with an appropriate checker ImageIcon that the user can drag.
Note that if you absolutely have to use JButtons, then don't add JLabels to them. Instead simply set the JButton's Icon to null or to an appropriate Checker ImageIcon.
Edit
For example, a bad code example as a proof of concept. Try compiling and running this.
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
@SuppressWarnings("serial")
public class Checkers extends JPanel {
public static final int SIDE_LENGTH = 60;
public static final int ROW_COUNT = 8;
private static final String ROW = "row";
private static final String COLUMN = "column";
private static final Color LIGHT_COLOR = new Color(210, 180, 140);
private static final Color DARK_COLOR = new Color(107, 68, 35);
private Map<Checker, Icon> checkerIconMap = new EnumMap<Checker, Icon>(
Checker.class);
private JLabel[][] labelGrid = new JLabel[ROW_COUNT][ROW_COUNT];
private Checker[][] checkerGrid = new Checker[ROW_COUNT][ROW_COUNT];
public Checkers() {
for (Checker checker : Checker.values()) {
checkerIconMap.put(checker, createCheckerIcon(checker));
}
setLayout(new GridLayout(ROW_COUNT, ROW_COUNT));
for (int row = 0; row < labelGrid.length; row++) {
for (int col = 0; col < labelGrid[row].length; col++) {
checkerGrid[row][col] = Checker.EMPTY;
JLabel gridCell = new JLabel(checkerIconMap.get(Checker.EMPTY));
gridCell.setOpaque(true);
gridCell.putClientProperty(ROW, row);
gridCell.putClientProperty(COLUMN, col);
Color c = row % 2 == col % 2 ? LIGHT_COLOR : DARK_COLOR;
gridCell.setBackground(c);
add(gridCell);
labelGrid[row][col] = gridCell;
}
}
for (int i = 0; i < labelGrid.length / 2 - 1; i++) {
for (int j = 0; j < labelGrid.length / 2; j++) {
int row = i;
int col = j * 2;
col += row % 2 == 0 ? 1 : 0;
labelGrid[row][col].setIcon(checkerIconMap.get(Checker.BLACK));
checkerGrid[row][col] = Checker.BLACK;
row = ROW_COUNT - row - 1;
col = ROW_COUNT - col - 1;
labelGrid[row][col].setIcon(checkerIconMap.get(Checker.RED));
checkerGrid[row][col] = Checker.RED;
}
}
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
private Icon createCheckerIcon(Checker checker) {
BufferedImage img = new BufferedImage(SIDE_LENGTH, SIDE_LENGTH,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(checker.getColor());
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int x = 3;
int y = x;
int width = SIDE_LENGTH - 2 * x;
int height = width;
g2.fillOval(x, y, width, height);
g2.dispose();
return new ImageIcon(img);
}
private class MyMouseAdapter extends MouseAdapter {
private int selectedRow = -1;
private int selectedCol = -1;
private Checker selectedChecker = null;
private JPanel glassPane = null;
private Point p = null;
private JLabel movingLabel = new JLabel(checkerIconMap.get(Checker.EMPTY));
public MyMouseAdapter() {
movingLabel.setSize(movingLabel.getPreferredSize());
movingLabel.setVisible(false);
}
@Override
public void mousePressed(MouseEvent e) {
p = e.getPoint();
for (int row = 0; row < labelGrid.length; row++) {
for (int col = 0; col < labelGrid[row].length; col++) {
JLabel gridCell = labelGrid[row][col];
if (gridCell == getComponentAt(p)) {
if (checkerGrid[row][col] != Checker.EMPTY) {
selectedRow = row;
selectedCol = col;
selectedChecker = checkerGrid[row][col];
checkerGrid[row][col] = Checker.EMPTY;
labelGrid[row][col].setIcon(checkerIconMap.get(Checker.EMPTY));
JRootPane rootPane = SwingUtilities.getRootPane(Checkers.this);
glassPane = (JPanel) rootPane.getGlassPane();
glassPane.setVisible(true);
glassPane.setLayout(null);
movingLabel.setIcon(checkerIconMap.get(selectedChecker));
movingLabel.setVisible(true);
glassPane.add(movingLabel);
int x = p.x - SIDE_LENGTH / 2;
int y = p.y - SIDE_LENGTH / 2;
movingLabel.setLocation(x, y);
}
}
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (selectedChecker == null) {
return;
}
p = e.getPoint();
if (!Checkers.this.contains(p)) {
// if mouse releases and is totally off of the grid
returnCheckerToOriginalCell();
clearGlassPane();
return;
}
for (int row = 0; row < labelGrid.length; row++) {
for (int col = 0; col < labelGrid[row].length; col++) {
JLabel gridCell = labelGrid[row][col];
if (gridCell == getComponentAt(p)) {
if (isMoveLegal(row, col)) {
checkerGrid[row][col] = selectedChecker;
labelGrid[row][col].setIcon(checkerIconMap.get(selectedChecker));
// todo: check for jumped pieces...
} else {
// illegal move
returnCheckerToOriginalCell();
}
}
}
}
clearGlassPane();
}
// this code would go in the model class
private boolean isMoveLegal(int row, int col) {
if (checkerGrid[row][col] != Checker.EMPTY) {
// trying to put a checker on another checker
returnCheckerToOriginalCell();
} else if (row == selectedRow && col == selectedCol) {
// trying to put checker back in same position
returnCheckerToOriginalCell();
} else if (row % 2 == col % 2) {
// invalid square
returnCheckerToOriginalCell();
} else {
// TODO: more logic needs to go here to test for a legal move
// and to remove jumped pieces
return true;
}
return false;
}
@Override
public void mouseDragged(MouseEvent e) {
if (selectedChecker == null || p == null) {
return;
}
p = e.getPoint();
int x = p.x - SIDE_LENGTH / 2;
int y = p.y - SIDE_LENGTH / 2;
movingLabel.setLocation(x, y);
}
private void clearGlassPane() {
glassPane.setVisible(false);
movingLabel.setVisible(false);
selectedChecker = null;
p = null;
selectedCol = -1;
selectedRow = -1;
}
private void returnCheckerToOriginalCell() {
checkerGrid[selectedRow][selectedCol] = selectedChecker;
labelGrid[selectedRow][selectedCol].setIcon(checkerIconMap.get(selectedChecker));
}
}
private static void createAndShowGui() {
Checkers mainPanel = new Checkers();
JFrame frame = new JFrame("JLabelGrid");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class CheckerModel {
}
enum Checker {
EMPTY(new Color(0, 0, 0, 0)), RED(Color.red), BLACK(Color.black);
private Color color;
private Checker(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
Better Model-View example being worked on...