尝试根据选择的 RadioButton 更改网格大小 - Java Swing GUI - SOS 棋盘游戏
Attempting to change grid size based on which RadioButton is selected - Java Swing GUI - SOS board game
这个项目围绕一个名为 SOS 的 TicTacToe 变体游戏展开。要求之一是游戏网格需要有两个大小选项。较小的网格是 5x5,较大的是 8x8。
我的目标是根据选择的单选按钮更改网格大小。在我下面的代码中,我有一个注释掉的方法来根据选择的单选按钮更改 GRID_SIZE 变量。但它在目前的位置不起作用,我正在努力想出解决方案。另一个与网格大小更改相关的问题是,我不相信我现在创建网格的方式会允许它在按下单选按钮时实时更改。
我需要跟踪在网格的每个单元格中播放的内容(无论玩家放置的是 S 还是 O)所以我的想法是也许有更好的方法来为两者创建网格GUI 和作为所玩动作的存储方法。
这个项目是我的第一个 java 项目,也是这个深度的第一个 GUI 项目。这也是我最后一个 类 毕业的主要项目,所以我认真对待这个问题并且真的可以得到帮助。我知道我的代码可能不是很好,我是来改进的,所以欢迎任何帮助。
package practice;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings({ "serial", "unused"})
public class SOS_GUI extends JFrame {
public int GRID_SIZE = 8;
public Grid grid;
public SOS_GUI() {
GameBoard();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setTitle("SOS Practice");
this.setLocationRelativeTo(null);
setVisible(true);
}
public void GameBoard(){
// CONTENT PANE FOR HOLDING ALL GUI COMPONENTS
Container ContentPane = getContentPane();
// PANEL FOR GAME GRID
JPanel gameBoardCanvas = new JPanel();
gameBoardCanvas.setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
for (int x = 0; x < GRID_SIZE; x++) {
for (int y = 0; y < GRID_SIZE; y++) {
final Grid cell = new Grid(x, y);
gameBoardCanvas.add(cell);
}
}
// FOUR PANELS SURROUNDING GAME GRID
JPanel TopPanel = new JPanel();
JPanel BottomPanel = new JPanel();
JPanel LeftPanel = new JPanel();
JPanel RightPanel = new JPanel();
JLabel SpacerLabel = new JLabel(" || ");
// GAME MODE OOPTIONS - SIMPLE OR GENERAL
JLabel GameModeLabel = new JLabel("Game Mode :");
JRadioButton SimpleGameButton = new JRadioButton("Simple", true);
JRadioButton GeneralGameButton = new JRadioButton("General");
ButtonGroup GameModeButtons = new ButtonGroup();
GameModeButtons.add(SimpleGameButton);
GameModeButtons.add(GeneralGameButton);
// BOARD SIZE BUTTONS - SMALL(5X5) OR LARGE(8X8)
JLabel SizeOptionLabel = new JLabel("Board Size :");
JRadioButton SmallGridButton = new JRadioButton("Small", true);
JRadioButton LargeGridButton = new JRadioButton("Large");
ButtonGroup GridSizeButtons = new ButtonGroup();
GridSizeButtons.add(SmallGridButton);
GridSizeButtons.add(LargeGridButton);
// PLAY LETTER SETTINGS
JRadioButton PlayS_Button = new JRadioButton("S", true);
JRadioButton PlayO_Button = new JRadioButton("O");
ButtonGroup PlayLetterButtons = new ButtonGroup();
PlayLetterButtons.add(PlayS_Button);
PlayLetterButtons.add(PlayO_Button);
// BLUE PLAYER SETTINGS
JLabel BluePlayerLabel = new JLabel("Blue Player");
JRadioButton BlueHumanButton = new JRadioButton("Human", true);
JRadioButton BlueComputerButton = new JRadioButton("Computer");
ButtonGroup BluePlayerButtons = new ButtonGroup();
BluePlayerButtons.add(BlueHumanButton);
BluePlayerButtons.add(BlueComputerButton);
// RED PLAYER SETTINGS
JLabel RedPlayerLabel = new JLabel("Red Player");
JRadioButton RedHumanButton = new JRadioButton("Human");
JRadioButton RedComputerButton = new JRadioButton("Computer", true);
ButtonGroup RedPlayerButtons = new ButtonGroup();
RedPlayerButtons.add(RedHumanButton);
RedPlayerButtons.add(RedComputerButton);
// ADDING COMPONENTS TO TOP PANEL
TopPanel.add(GameModeLabel);
TopPanel.add(SimpleGameButton);
TopPanel.add(GeneralGameButton);
TopPanel.add(SpacerLabel);
TopPanel.add(SizeOptionLabel);
TopPanel.add(SmallGridButton);
TopPanel.add(LargeGridButton);
// ADDING COMPONENTS TO BOTTOM PANEL
BottomPanel.add(PlayS_Button);
BottomPanel.add(PlayO_Button);
// ADDING COMPONENTS TO LEFT PANEL
LeftPanel.add(BluePlayerLabel);
LeftPanel.add(BlueHumanButton);
LeftPanel.add(BlueComputerButton);
// ADDING COMPONENTS TO RIGHT PANEL
RightPanel.add(RedPlayerLabel);
RightPanel.add(RedHumanButton);
RightPanel.add(RedComputerButton);
// ADDING PANELS TO CONTENT PANE
ContentPane.setLayout(new BorderLayout());
ContentPane.add(TopPanel, BorderLayout.NORTH);
ContentPane.add(BottomPanel, BorderLayout.SOUTH);
ContentPane.add(LeftPanel, BorderLayout.WEST);
ContentPane.add(RightPanel, BorderLayout.EAST);
ContentPane.add(gameBoardCanvas, BorderLayout.CENTER);
TopPanel.setPreferredSize(new Dimension(50, 50));
BottomPanel.setPreferredSize(new Dimension(50, 50));
LeftPanel.setPreferredSize(new Dimension(100, 100));
RightPanel.setPreferredSize(new Dimension(100, 100));
ContentPane.setPreferredSize(new Dimension(550, 500));
}
// CLASS SETTING UP HOW THE GRID WILL BE CREATED
class Grid extends JPanel {
public static final int CELL_SIZE = 1;
private int xPos;
private int yPos;
public JLabel gridLabel;
public Grid (int x, int y) {
xPos = x;
yPos = y;
gridLabel = new JLabel("");
gridLabel.setFont(new Font("Serif", Font.BOLD, 40));
add(gridLabel);
setOpaque(true);
setLayout(new FlowLayout());
setBorder(BorderFactory.createBevelBorder(CELL_SIZE));
setBackground(new Color(200, 200, 200));
setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
}
}
/* POSSIBLE FUNCTION TO SET GRID_SIZE BASED OFF RADIO BUTTON INPUT? DOESNT WORK HERE
public getGridSize() {
if (GameBoard().SmallGridButton.isSelected() == true) {
GRID_SIZE = 5;
}
else if (GameBoard().LargeGridButton.isSelected() == true) {
GRID_SIZE = 8;
}
return GRID_SIZE;
}
*/
public static void main(String[] args) {
new SOS_GUI();
}
}
screenshot of the smaller 5x5 grid
screenshot of larger 8x8 grid
再次,我建议,如果您想使用组件作为网格单元,要么使用 CardLayout 交换视图 (JPanel),要么在按下 JRadioButton 时交换网格单元。
我建议:
- 将 ActionListener 添加到 JRadioButton 以在按下时收到通知。
- 如果您要交换组件,则创建一个 JPanel 来保存网格单元格,例如称为 gridHolder,并在按下按钮时删除所有组件。
- 然后向此 JPanel 添加一个新的 GridLayout 布局管理器,并根据按下的 JRadioButton 设置约束。
- 然后re-adding网格单元格组件到这个holder JPanel
- 然后通过在 top-level window 上调用
pack()
来中继 GUI 中的所有组件并调整其大小,这里是 JFrame。
- 在下面的示例中,我使用 JLabel 来保存网格单元格,因为向这些单元格添加文本很简单。
- 我使用
.putClientProperty(...)
方法存储每个网格单元格的行和列,同样可以使用 .getClientProperty(...)
方法检索值。
- 我在构造函数中调用
createGrid(...)
以使用默认的小尺寸创建网格。
- 只要按下 JRadioButton,我就会调用相同的方法。
例如:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.BevelBorder;
@SuppressWarnings("serial")
public class SosGrid2 extends JPanel {
private static final int SMALL_SIZE = 5;
private static final int LARGE_SIZE = 8;
private static final String[] SIZES = { "Small", "Large" };
private static final Dimension CELL_SIZE = new Dimension(60, 60);
private static final Color GRID_BG = new Color(200, 200, 200);
private static final String ROW = "row";
private static final String COL = "col";
private JPanel gridHolder = new JPanel();
private ButtonGroup gridSizeGroup = new ButtonGroup();
public SosGrid2() {
JPanel radioButtonPanel = new JPanel();
for (String size : SIZES) {
JRadioButton radioButton = new JRadioButton(size);
radioButton.setSelected(size.equals(SIZES[0]));
radioButton.setActionCommand(size);
gridSizeGroup.add(radioButton);
radioButtonPanel.add(radioButton);
radioButton.addActionListener(e -> radioListener());
}
createGrid(SMALL_SIZE);
setLayout(new BorderLayout());
add(gridHolder);
add(radioButtonPanel, BorderLayout.PAGE_END);
}
private void createGrid(int gridSize) {
gridHolder.removeAll();
gridHolder.setLayout(new GridLayout(gridSize, gridSize));
for (int row = 0; row < gridSize; row++) {
for (int col = 0; col < gridSize; col++) {
JLabel gridCell = createGridCell(row, col);
gridHolder.add(gridCell);
}
}
}
// factory method to create grid cell JLabels.
private JLabel createGridCell(int row, int col) {
JLabel label = new JLabel("", SwingConstants.CENTER);
label.setFont(label.getFont().deriveFont(Font.BOLD, 32f));
label.setOpaque(true);
label.setBackground(GRID_BG);
label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
label.setPreferredSize(CELL_SIZE);
label.putClientProperty(ROW, row);
label.putClientProperty(COL, col);
label.addMouseListener(new MyMouseListener());
return label;
}
private class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
JLabel gridCell = (JLabel) e.getSource();
int row = (int) gridCell.getClientProperty(ROW);
int col = (int) gridCell.getClientProperty(COL);
String message = String.format("Row: %d, Col: %d", row, col);
String title = "Cell Pressed";
int type = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(SosGrid2.this, message, title, type);
String text = gridCell.getText();
if (text.isEmpty()) {
gridCell.setText("X");
} else {
gridCell.setText("");
}
}
}
private void radioListener() {
ButtonModel btnModel = gridSizeGroup.getSelection();
if (btnModel != null) {
int gridSize = btnModel.getActionCommand().equals(SIZES[0]) ? SMALL_SIZE : LARGE_SIZE;
createGrid(gridSize);
Window jframe = SwingUtilities.getWindowAncestor(this);
jframe.pack();
jframe.setLocationRelativeTo(null);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SosGrid2 mainPanel = new SosGrid2();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
这个项目围绕一个名为 SOS 的 TicTacToe 变体游戏展开。要求之一是游戏网格需要有两个大小选项。较小的网格是 5x5,较大的是 8x8。
我的目标是根据选择的单选按钮更改网格大小。在我下面的代码中,我有一个注释掉的方法来根据选择的单选按钮更改 GRID_SIZE 变量。但它在目前的位置不起作用,我正在努力想出解决方案。另一个与网格大小更改相关的问题是,我不相信我现在创建网格的方式会允许它在按下单选按钮时实时更改。
我需要跟踪在网格的每个单元格中播放的内容(无论玩家放置的是 S 还是 O)所以我的想法是也许有更好的方法来为两者创建网格GUI 和作为所玩动作的存储方法。
这个项目是我的第一个 java 项目,也是这个深度的第一个 GUI 项目。这也是我最后一个 类 毕业的主要项目,所以我认真对待这个问题并且真的可以得到帮助。我知道我的代码可能不是很好,我是来改进的,所以欢迎任何帮助。
package practice;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings({ "serial", "unused"})
public class SOS_GUI extends JFrame {
public int GRID_SIZE = 8;
public Grid grid;
public SOS_GUI() {
GameBoard();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setTitle("SOS Practice");
this.setLocationRelativeTo(null);
setVisible(true);
}
public void GameBoard(){
// CONTENT PANE FOR HOLDING ALL GUI COMPONENTS
Container ContentPane = getContentPane();
// PANEL FOR GAME GRID
JPanel gameBoardCanvas = new JPanel();
gameBoardCanvas.setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
for (int x = 0; x < GRID_SIZE; x++) {
for (int y = 0; y < GRID_SIZE; y++) {
final Grid cell = new Grid(x, y);
gameBoardCanvas.add(cell);
}
}
// FOUR PANELS SURROUNDING GAME GRID
JPanel TopPanel = new JPanel();
JPanel BottomPanel = new JPanel();
JPanel LeftPanel = new JPanel();
JPanel RightPanel = new JPanel();
JLabel SpacerLabel = new JLabel(" || ");
// GAME MODE OOPTIONS - SIMPLE OR GENERAL
JLabel GameModeLabel = new JLabel("Game Mode :");
JRadioButton SimpleGameButton = new JRadioButton("Simple", true);
JRadioButton GeneralGameButton = new JRadioButton("General");
ButtonGroup GameModeButtons = new ButtonGroup();
GameModeButtons.add(SimpleGameButton);
GameModeButtons.add(GeneralGameButton);
// BOARD SIZE BUTTONS - SMALL(5X5) OR LARGE(8X8)
JLabel SizeOptionLabel = new JLabel("Board Size :");
JRadioButton SmallGridButton = new JRadioButton("Small", true);
JRadioButton LargeGridButton = new JRadioButton("Large");
ButtonGroup GridSizeButtons = new ButtonGroup();
GridSizeButtons.add(SmallGridButton);
GridSizeButtons.add(LargeGridButton);
// PLAY LETTER SETTINGS
JRadioButton PlayS_Button = new JRadioButton("S", true);
JRadioButton PlayO_Button = new JRadioButton("O");
ButtonGroup PlayLetterButtons = new ButtonGroup();
PlayLetterButtons.add(PlayS_Button);
PlayLetterButtons.add(PlayO_Button);
// BLUE PLAYER SETTINGS
JLabel BluePlayerLabel = new JLabel("Blue Player");
JRadioButton BlueHumanButton = new JRadioButton("Human", true);
JRadioButton BlueComputerButton = new JRadioButton("Computer");
ButtonGroup BluePlayerButtons = new ButtonGroup();
BluePlayerButtons.add(BlueHumanButton);
BluePlayerButtons.add(BlueComputerButton);
// RED PLAYER SETTINGS
JLabel RedPlayerLabel = new JLabel("Red Player");
JRadioButton RedHumanButton = new JRadioButton("Human");
JRadioButton RedComputerButton = new JRadioButton("Computer", true);
ButtonGroup RedPlayerButtons = new ButtonGroup();
RedPlayerButtons.add(RedHumanButton);
RedPlayerButtons.add(RedComputerButton);
// ADDING COMPONENTS TO TOP PANEL
TopPanel.add(GameModeLabel);
TopPanel.add(SimpleGameButton);
TopPanel.add(GeneralGameButton);
TopPanel.add(SpacerLabel);
TopPanel.add(SizeOptionLabel);
TopPanel.add(SmallGridButton);
TopPanel.add(LargeGridButton);
// ADDING COMPONENTS TO BOTTOM PANEL
BottomPanel.add(PlayS_Button);
BottomPanel.add(PlayO_Button);
// ADDING COMPONENTS TO LEFT PANEL
LeftPanel.add(BluePlayerLabel);
LeftPanel.add(BlueHumanButton);
LeftPanel.add(BlueComputerButton);
// ADDING COMPONENTS TO RIGHT PANEL
RightPanel.add(RedPlayerLabel);
RightPanel.add(RedHumanButton);
RightPanel.add(RedComputerButton);
// ADDING PANELS TO CONTENT PANE
ContentPane.setLayout(new BorderLayout());
ContentPane.add(TopPanel, BorderLayout.NORTH);
ContentPane.add(BottomPanel, BorderLayout.SOUTH);
ContentPane.add(LeftPanel, BorderLayout.WEST);
ContentPane.add(RightPanel, BorderLayout.EAST);
ContentPane.add(gameBoardCanvas, BorderLayout.CENTER);
TopPanel.setPreferredSize(new Dimension(50, 50));
BottomPanel.setPreferredSize(new Dimension(50, 50));
LeftPanel.setPreferredSize(new Dimension(100, 100));
RightPanel.setPreferredSize(new Dimension(100, 100));
ContentPane.setPreferredSize(new Dimension(550, 500));
}
// CLASS SETTING UP HOW THE GRID WILL BE CREATED
class Grid extends JPanel {
public static final int CELL_SIZE = 1;
private int xPos;
private int yPos;
public JLabel gridLabel;
public Grid (int x, int y) {
xPos = x;
yPos = y;
gridLabel = new JLabel("");
gridLabel.setFont(new Font("Serif", Font.BOLD, 40));
add(gridLabel);
setOpaque(true);
setLayout(new FlowLayout());
setBorder(BorderFactory.createBevelBorder(CELL_SIZE));
setBackground(new Color(200, 200, 200));
setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
}
}
/* POSSIBLE FUNCTION TO SET GRID_SIZE BASED OFF RADIO BUTTON INPUT? DOESNT WORK HERE
public getGridSize() {
if (GameBoard().SmallGridButton.isSelected() == true) {
GRID_SIZE = 5;
}
else if (GameBoard().LargeGridButton.isSelected() == true) {
GRID_SIZE = 8;
}
return GRID_SIZE;
}
*/
public static void main(String[] args) {
new SOS_GUI();
}
}
screenshot of the smaller 5x5 grid screenshot of larger 8x8 grid
再次,我建议,如果您想使用组件作为网格单元,要么使用 CardLayout 交换视图 (JPanel),要么在按下 JRadioButton 时交换网格单元。
我建议:
- 将 ActionListener 添加到 JRadioButton 以在按下时收到通知。
- 如果您要交换组件,则创建一个 JPanel 来保存网格单元格,例如称为 gridHolder,并在按下按钮时删除所有组件。
- 然后向此 JPanel 添加一个新的 GridLayout 布局管理器,并根据按下的 JRadioButton 设置约束。
- 然后re-adding网格单元格组件到这个holder JPanel
- 然后通过在 top-level window 上调用
pack()
来中继 GUI 中的所有组件并调整其大小,这里是 JFrame。 - 在下面的示例中,我使用 JLabel 来保存网格单元格,因为向这些单元格添加文本很简单。
- 我使用
.putClientProperty(...)
方法存储每个网格单元格的行和列,同样可以使用.getClientProperty(...)
方法检索值。 - 我在构造函数中调用
createGrid(...)
以使用默认的小尺寸创建网格。 - 只要按下 JRadioButton,我就会调用相同的方法。
例如:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.BevelBorder;
@SuppressWarnings("serial")
public class SosGrid2 extends JPanel {
private static final int SMALL_SIZE = 5;
private static final int LARGE_SIZE = 8;
private static final String[] SIZES = { "Small", "Large" };
private static final Dimension CELL_SIZE = new Dimension(60, 60);
private static final Color GRID_BG = new Color(200, 200, 200);
private static final String ROW = "row";
private static final String COL = "col";
private JPanel gridHolder = new JPanel();
private ButtonGroup gridSizeGroup = new ButtonGroup();
public SosGrid2() {
JPanel radioButtonPanel = new JPanel();
for (String size : SIZES) {
JRadioButton radioButton = new JRadioButton(size);
radioButton.setSelected(size.equals(SIZES[0]));
radioButton.setActionCommand(size);
gridSizeGroup.add(radioButton);
radioButtonPanel.add(radioButton);
radioButton.addActionListener(e -> radioListener());
}
createGrid(SMALL_SIZE);
setLayout(new BorderLayout());
add(gridHolder);
add(radioButtonPanel, BorderLayout.PAGE_END);
}
private void createGrid(int gridSize) {
gridHolder.removeAll();
gridHolder.setLayout(new GridLayout(gridSize, gridSize));
for (int row = 0; row < gridSize; row++) {
for (int col = 0; col < gridSize; col++) {
JLabel gridCell = createGridCell(row, col);
gridHolder.add(gridCell);
}
}
}
// factory method to create grid cell JLabels.
private JLabel createGridCell(int row, int col) {
JLabel label = new JLabel("", SwingConstants.CENTER);
label.setFont(label.getFont().deriveFont(Font.BOLD, 32f));
label.setOpaque(true);
label.setBackground(GRID_BG);
label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
label.setPreferredSize(CELL_SIZE);
label.putClientProperty(ROW, row);
label.putClientProperty(COL, col);
label.addMouseListener(new MyMouseListener());
return label;
}
private class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
JLabel gridCell = (JLabel) e.getSource();
int row = (int) gridCell.getClientProperty(ROW);
int col = (int) gridCell.getClientProperty(COL);
String message = String.format("Row: %d, Col: %d", row, col);
String title = "Cell Pressed";
int type = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(SosGrid2.this, message, title, type);
String text = gridCell.getText();
if (text.isEmpty()) {
gridCell.setText("X");
} else {
gridCell.setText("");
}
}
}
private void radioListener() {
ButtonModel btnModel = gridSizeGroup.getSelection();
if (btnModel != null) {
int gridSize = btnModel.getActionCommand().equals(SIZES[0]) ? SMALL_SIZE : LARGE_SIZE;
createGrid(gridSize);
Window jframe = SwingUtilities.getWindowAncestor(this);
jframe.pack();
jframe.setLocationRelativeTo(null);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SosGrid2 mainPanel = new SosGrid2();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}