Java Swing JButton点击后切换两种颜色的问题解决(井字棋场景)
基于颜色的井字棋回合颜色无法切换问题修复
核心问题原因
你的代码里,turns变量被声明在actionPerformed方法内部,每次按钮点击时都会重新初始化turns = 0,之后执行turns++得到1,永远满足turns % 2 != 0的条件,所以每次点击都只会设置蓝色,完全无法实现回合切换。
另外还有几个次要问题需要修正:
- 每个按钮都创建了独立的
ButtonListener实例,但回合计数器应该是全局共享的 - 没有限制按钮重复点击,玩家可以多次点击同一个格子修改颜色
- 冗长的
if-else判断可以大幅简化
修复后的完整代码
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Board extends JPanel { boolean gameRunning = true; private final JButton[][] grid = new JButton[3][3]; private int turns = 0; // 全局回合计数器,移到Board类作为成员变量 JFrame board; JPanel panel; public Board() { initBoard(); } private void makePanel() { panel = new JPanel(); panel.setBackground(Color.lightGray); panel.setLayout(new GridLayout(3, 3)); setBoard(); board.add(panel); } private void initBoard() { int BOARD_WIDTH = 800; int BOARD_HEIGHT = 600; board = new JFrame(); board.setTitle("JTicTacToe"); board.setSize(BOARD_WIDTH, BOARD_HEIGHT); board.setResizable(false); board.setLocationRelativeTo(null); board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); makePanel(); board.setVisible(true); } private void setBoard() { Color defaultColor = new Color(238,238,238); // 遍历生成3x3网格按钮 for (int row = 0; row < grid.length; row++) { for (int col = 0; col < grid[row].length; col++) { grid[row][col] = new JButton(); grid[row][col].setOpaque(true); grid[row][col].setBorderPainted(false); grid[row][col].setBackground(defaultColor); grid[row][col].addActionListener(new ButtonListener()); panel.add(grid[row][col]); } } validate(); } protected class ButtonListener implements ActionListener { Color defaultColor = new Color(238,238,238); protected void check(int moves) { // 检查行 for (int c = 0; c < 3; c++) { if (!defaultColor.equals(grid[c][0].getBackground()) && grid[c][0].getBackground().equals(grid[c][1].getBackground()) && grid[c][0].getBackground().equals(grid[c][2].getBackground())) { gameRunning = false; JOptionPane.showMessageDialog(null, "Game Over!"); } } // 检查列 for (int c = 0; c < 3; c++) { if (!defaultColor.equals(grid[0][c].getBackground()) && grid[0][c].getBackground().equals(grid[1][c].getBackground()) && grid[0][c].getBackground().equals(grid[2][c].getBackground())) { gameRunning = false; JOptionPane.showMessageDialog(null, "Game Over!"); } } // 检查对角线 if (!defaultColor.equals(grid[0][0].getBackground()) && grid[0][0].getBackground().equals(grid[1][1].getBackground()) && grid[0][0].getBackground().equals(grid[2][2].getBackground())) { gameRunning = false; JOptionPane.showMessageDialog(null, "Game Over!"); } if (!defaultColor.equals(grid[0][2].getBackground()) && grid[0][2].getBackground().equals(grid[1][1].getBackground()) && grid[0][2].getBackground().equals(grid[2][0].getBackground())) { gameRunning = false; JOptionPane.showMessageDialog(null, "Game Over!"); } // 检查平局(仅在未分出胜负时触发) if(moves == 9 && gameRunning) { gameRunning = false; JOptionPane.showMessageDialog(null, "Draw!"); } } @Override public void actionPerformed(ActionEvent e) { if (!gameRunning) return; // 游戏结束后不再响应点击 JButton clickedButton = (JButton) e.getSource(); // 仅处理未被点击过的按钮 if (defaultColor.equals(clickedButton.getBackground())) { turns++; // 根据回合数切换颜色 if (turns % 2 == 0) { clickedButton.setBackground(Color.orange); } else { clickedButton.setBackground(Color.blue); } check(turns); } } } public static void main(String[] args) { SwingUtilities.invokeLater(Board::new); } }
关键修改点说明
- 全局回合计数器:把
turns从方法内部移到Board类作为成员变量,确保所有按钮点击共享同一个回合计数 - 简化点击判断:直接通过
e.getSource()获取点击的按钮,替代冗长的9个if-else分支 - 防止重复点击:添加判断,只有按钮背景为默认颜色时才处理点击
- 游戏结束锁定:游戏结束后(
gameRunning为false)不再响应任何按钮点击 - 颜色比较优化:用
equals()替代==比较Color对象,避免引用比较的潜在问题 - 平局判断优化:添加
gameRunning判断,避免在已经分出胜负后还弹出平局提示
内容的提问来源于stack exchange,提问作者Cr3
相关产品推荐
相关产品推荐

