I'm studying Java these days, my first project is to create a "Go board", 9 * 9 rows and columns, and place black and white stones on the intersections.
I created a board with 9 * 9 lines and columns, now I have to create black and white stones using the JButton
component.
Other than the color, size, and position of the button on the first row (setLayout
), I was unable to turn the button into a circle and place the stone on the intersection points.
From multiple searches for related guides, I have noticed that there is some unique structure that I am not familiar with for creating and designing buttons.
And now my question comes in - what is the code structure I need to create in order to produce a button in the shape of a circle, size 65 * 65, in black or white? Do I need to create a new class for this? How and where should I integrate JPanel
?
public class Main {
public static void main(String[] args) {
Board board = new Board(900, 900, "Go board");
}
}
import java.awt.*;
import javax.swing.*;
public class Board extends JPanel {
private int width;
private int height;
private String title;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Board(int width, int height, String title) {
super();
this.width = width;
this.height = height;
this.title = title;
this.initBoard();
}
public Board() {
super();
}
public void initBoard() {
JFrame f = new JFrame(this.getTitle());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// f.getContentPane().setBackground(Color.getHSBColor(25, 75, 47));
f.setSize(this.getWidth(), this.getHeight());
// f.setLocation(550, 25);
f.add(this, BorderLayout.CENTER);
f.setVisible(true);
JButton stone = new JButton(" ");
f.add(stone);
f.setLayout(new FlowLayout());
stone.setBackground(Color.BLACK.darker());
stone.setBorder(BorderFactory.createDashedBorder(getForeground()));
stone.setPreferredSize(new Dimension(65, 65));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < 10; i ) {
g.drawLine(0, 10 (i * ((this.getWidth() - 20) / 9)), this.getWidth(),
10 (i * ((this.getWidth() - 20) / 9)));
g.drawLine(10 (i * ((this.getHeight() - 20) / 9)), 0, 10 (i * ((this.getHeight() - 20) / 9)),
this.getHeight());
}
}
}
Before uploading the post, I read the following posts:
-
Alternatively you can produce the board by custom painting of a
JPanel
. This will make the individual "stones" not clickable and more difficult to modify:import java.awt.*; import javax.swing.*; public class GridByPainting extends JPanel { private static final int ROWS = 9, COLS = 9, SIZE = 65, BORDER = 2; private static final Color BOARD_COLOR = Color.BLACK, STONE = Color.YELLOW, WHITE_STONE = Color.WHITE, BLACK_STONE = Color.BLACK; private final Dimension size; public GridByPainting() { int x = BORDER COLS*(SIZE BORDER); int y = BORDER ROWS*(SIZE BORDER); size = new Dimension(x,y); this.initBoard(); } @Override public Dimension getPreferredSize() { return size; } public void initBoard() { JFrame f = new JFrame("Grid By Painting"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setLayout(new GridBagLayout()); f.add(this); f.pack(); f.setVisible(true); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); int width = getWidth(); int height = getHeight(); int stoneWidth = (width - BORDER) / COLS - BORDER; int stoneHeight = (height -BORDER)/ ROWS - BORDER ; //draw board g.setColor(BOARD_COLOR); g.fillRect(0, 0, width, height); boolean isBlack = true; //draw square stones for (int col = 0; col < COLS; col ) { for (int row = 0; row < ROWS; row ) { int x = BORDER col*(stoneWidth BORDER); int y = BORDER row*(stoneHeight BORDER); g.setColor(STONE); g.fillRect(x, y, stoneWidth, stoneHeight); //draw circle g.setColor(isBlack ? BLACK_STONE : WHITE_STONE); isBlack = !isBlack; g.fillOval(x, y, stoneWidth, stoneHeight); } } } public static void main(String[] args) { SwingUtilities.invokeLater(()->new GridByPainting()); } }
CodePudding user response:
It seems like you skipped over some of the important parts of the Oracle tutorial,
My code has a logical model. My code has a drawing
JPanel
.The first thing I did was create a plain Java getter / setter class to hold a logical representation of a Go Board. I named this the
Board
class.The next thing I did was start my Swing GUI with a call to the
SwingUtilities
invokeLater
method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.I used the
run
method of myRunnable
class to create theJFrame
. TheJFrame
methods must be called in a specific order. This is the order I use for all my Swing applications.I separate the creation of the
JFrame
from the creation of any subsequentJPanels
. I do this to keep my code organized, easy to read, and easy to understand.I extend a
JPanel
to create the drawingJPanel
. I do this so I can override thepaintComponent
method of theJPanel
class. The drawingJPanel
draws (paints) the board state. That's all. Nothing else. Another class will take care of adding pieces to the logical Go board and repainting the drawing JPanel.The
MoveListener
class implements aMouseListener
(extends aMouseAdapter
) to respond to mouse clicks on the Go board. TheMoveListener
class keeps track of whose turn it is. In a more elaborate version of a Go board, you would have another plain Java getter / setter class to keep track of the game state.Here's the complete runnable code. I made all the classes inner classes so I could post this code as one block.
import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class GoBoard implements Runnable { public static void main(String[] args) { SwingUtilities.invokeLater(new GoBoard()); } private Board board; private DrawingPanel drawingPanel; public GoBoard() { this.board = new Board(); } @Override public void run() { JFrame frame = new JFrame("Go Board"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.drawingPanel = new DrawingPanel(board); frame.add(drawingPanel, BorderLayout.CENTER); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public class DrawingPanel extends JPanel { private static final long serialVersionUID = 1L; private final int margin, pieceRadius, lineSpacing; private Board board; public DrawingPanel(Board board) { this.board = board; this.margin = 60; this.pieceRadius = 40; this.lineSpacing = 100; this.setBackground(new Color(0x993300)); int width = 8 * lineSpacing margin margin; this.setPreferredSize(new Dimension(width, width)); this.addMouseListener(new MoveListener(board)); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; paintHorizontalLines(g2d); paintVerticalLines(g2d); paintPieces(g2d); } private void paintHorizontalLines(Graphics2D g2d) { int x = margin; int y1 = margin; int y2 = getHeight() - margin; g2d.setColor(Color.YELLOW); g2d.setStroke(new BasicStroke(3f)); for (int index = 0; index < 9; index ) { g2d.drawLine(x, y1, x, y2); x = lineSpacing; } } private void paintVerticalLines(Graphics2D g2d) { int x1 = margin; int x2 = getWidth() - margin; int y = margin; g2d.setColor(Color.YELLOW); g2d.setStroke(new BasicStroke(3f)); for (int index = 0; index < 9; index ) { g2d.drawLine(x1, y, x2, y); y = lineSpacing; } } private void paintPieces(Graphics2D g2d) { int[][] b = board.getBoard(); for (int row = 0; row < b.length; row ) { for (int column = 0; column < b[row].length; column ) { int x = column * lineSpacing margin; int y = row * lineSpacing margin; if (b[row][column] == 1) { g2d.setColor(Color.BLACK); g2d.fillOval(x - pieceRadius, y - pieceRadius, pieceRadius pieceRadius, pieceRadius pieceRadius); } else if (b[row][column] == 2) { g2d.setColor(Color.WHITE); g2d.fillOval(x - pieceRadius, y - pieceRadius, pieceRadius pieceRadius, pieceRadius pieceRadius); } } } } } public class MoveListener extends MouseAdapter { private boolean isBlackTurn = true; private Board board; public MoveListener(Board board) { this.board = board; } @Override public void mouseReleased(MouseEvent event) { Point point = event.getPoint(); int margin = 60; int pieceRadius = 40; int lineSpacing = 100; int column = (point.x - margin pieceRadius) / lineSpacing; int row = (point.y - margin pieceRadius) / lineSpacing; int piece = (isBlackTurn) ? 1 : 2; board.setPiece(piece, row, column); drawingPanel.repaint(); isBlackTurn = !isBlackTurn; } } public class Board { private int[][] board; public Board() { this.board = new int[9][9]; } /** * <p> * This method inserts a piece on the board. * </p> * * @param piece - 1 for black, 2 for white * @param row - row of piece * @param column - column of piece */ public void setPiece(int piece, int row, int column) { this.board[row][column] = piece; } public int[][] getBoard() { return board; } } }