You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

井字棋开发求助:点击后修改JToggleButton二维数组图标失败

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:30:21