井字棋开发求助:点击后修改JToggleButton二维数组图标失败
一、先排查图标加载失败问题
你当前直接使用相对路径创建ImageIcon,这种方式在项目编译或打包后极易失效,且无法直观判断资源是否加载成功。改用类加载器加载资源,同时增加加载校验:
// 替换原静态图标定义 static Icon oIcon; static Icon xIcon; static { try { // 资源路径要对应项目结构,确保编译后资源在classpath下 oIcon = new ImageIcon(Board.class.getResource("/TicTacToeBoard/assets/16894.png")); xIcon = new ImageIcon(Board.class.getResource("/TicTacToeBoard/assets/1828778.png")); // 校验图标是否加载成功 if (oIcon.getImageLoadStatus() != MediaTracker.COMPLETE) { System.err.println("O图标加载失败,请检查路径"); } if (xIcon.getImageLoadStatus() != MediaTracker.COMPLETE) { System.err.println("X图标加载失败,请检查路径"); } } catch (Exception e) { System.err.println("图标资源加载异常:" + e.getMessage()); e.printStackTrace(); } }
注意资源放置:把assets文件夹放在src/main/resources/TicTacToeBoard/(Maven/Gradle项目),或普通项目的src/TicTacToeBoard/assets/下,确保编译后资源能被正确访问。
二、修正选中状态的图标逻辑
井字棋每个格子只能点击一次,且需要交替显示X/O,当前逻辑仅处理选中时设O图标,存在缺陷。调整监听逻辑:
protected class ButtonListener implements ActionListener{ // 记录当前回合该显示O还是X private boolean isTurnO = true; @Override public void actionPerformed(ActionEvent e){ JToggleButton button = (JToggleButton) e.getSource(); // 已点击过的格子直接返回 if (button.getIcon() != null) { return; } // 根据回合设置对应图标 if (isTurnO) { button.setIcon(Board.oIcon); } else { button.setIcon(Board.xIcon); } // 禁用按钮防止重复点击 button.setEnabled(false); // 切换回合 isTurnO = !isTurnO; System.out.println("点击了列 " + button.getClientProperty("column") + ", 行 " + button.getClientProperty("row")); } }
三、确保按钮尺寸足够显示图标
默认JToggleButton尺寸可能过小导致图标无法显示,创建按钮时设置合适尺寸:
grid[row][col] = new JToggleButton(); // 设置按钮首选尺寸,保证图标能完整显示 grid[row][col].setPreferredSize(new Dimension(200, 150)); grid[row][col].setBackground(Color.BLACK); // 其他属性设置...
四、检查按钮选中/占用状态的正确方式
如果后续需要判断胜负,可通过以下方式检查按钮状态:
// 方式1:判断是否有图标(直观判断是否被占用) if (grid[row][col].getIcon() != null) { // 该格子已被点击 } // 方式2:判断选中状态(若保留toggle功能) if (grid[row][col].isSelected()) { // 按钮处于选中状态 }
完整修正后的核心代码片段
public class Board extends JPanel{ private JToggleButton[][] grid = new JToggleButton[3][3]; private final int BOARD_WIDTH = 800; private final int BOARD_HEIGHT = 600; static Icon oIcon; static Icon xIcon; static { try { oIcon = new ImageIcon(Board.class.getResource("/TicTacToeBoard/assets/16894.png")); xIcon = new ImageIcon(Board.class.getResource("/TicTacToeBoard/assets/1828778.png")); if (oIcon.getImageLoadStatus() != MediaTracker.COMPLETE) { System.err.println("O图标加载失败,请检查路径"); } if (xIcon.getImageLoadStatus() != MediaTracker.COMPLETE) { System.err.println("X图标加载失败,请检查路径"); } } catch (Exception e) { System.err.println("图标资源加载异常:" + e.getMessage()); e.printStackTrace(); } } JFrame board; JPanel panel; public Board(){ initBoard(); } private void makePanel(){ panel.setBackground(Color.lightGray); panel.setLayout(new GridLayout(3,3, 5,5)); // 按钮间添加间距,布局更美观 setBoard(); board.add(panel); } private void initBoard(){ board = new JFrame(); panel = new JPanel(); 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(){ for(int row = 0; row < grid.length; row++){ for(int col = 0; col < grid[row].length; col++){ grid[row][col] = new JToggleButton(); grid[row][col].setBackground(Color.BLACK); grid[row][col].setForeground(Color.white); grid[row][col].setPreferredSize(new Dimension(200,150)); grid[row][col].putClientProperty("row", row); grid[row][col].putClientProperty("column",col); grid[row][col].addActionListener(new ButtonListener()); panel.add(grid[row][col]); } } } protected class ButtonListener implements ActionListener{ private boolean isTurnO = true; @Override public void actionPerformed(ActionEvent e){ JToggleButton button = (JToggleButton) e.getSource(); if (button.getIcon() != null) { return; } if (isTurnO) { button.setIcon(oIcon); } else { button.setIcon(xIcon); } button.setEnabled(false); isTurnO = !isTurnO; System.out.println("点击了列 " + button.getClientProperty("column") + ", 行 " + button.getClientProperty("row")); } } }
内容的提问来源于stack exchange,提问作者Cr3
相关产品推荐
相关产品推荐

