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

Java开发国际象棋游戏:棋子拖拽失效及莫名消失问题求助

国际象棋Java开发拖拽问题排查与修复

问题现象

使用JLabel、JFrame和鼠标监听器开发国际象棋游戏时,出现以下异常:

  • 点击棋子后棋子消失
  • 未操作的车(Rook)会莫名消失
  • 无法实现棋子拖拽移动,尝试setLocation方法未解决问题

创建棋子的代码(示例)

// 原代码:使用全局变量pieces,每次创建都会覆盖
pieces = new JLabel(new ImageIcon("blackrook.png"));
panels = (JPanel) board.getComponent(63);
panels.add(pieces);

鼠标监听器核心问题代码

public void mousePressed(MouseEvent e) {
    chessPiece = null;
    String name = getPieceName(e.getX(), e.getY());
    Component c = board.findComponentAt(e.getX(), e.getY());
    if (c instanceof JPanel) {
        return;
    }

    Point parentLocation = c.getParent().getLocation();
    xAdjustment = parentLocation.x - e.getX();
    yAdjustment = parentLocation.y - e.getY();
    chessPiece = (JLabel) c;
    actuallocation = e.getX()/75+(e.getY()/75*8);

    chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
    chessPiece.setSize(chessPiece.getWidth(), chessPiece.getHeight());

    layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
}

public void mouseReleased(MouseEvent e) {
    if(chessPiece == null) return;
    pieces.setVisible(false);
    Component c =  board.findComponentAt(e.getX(), e.getY());

    if (c instanceof JLabel){
        Container parent = c.getParent();
        parent.remove(0);
        parent.add(pieces.getComponent(actuallocation));
    }
    else {
        Container parent = (Container)c;
        parent.add(pieces.getComponent(actuallocation));
    }
    pieces.setVisible(true);
}

public void mouseDragged(MouseEvent e) {
    if (pieces == null) return;
    pieces.setLocation(e.getX(), e.getY());
}

问题根源分析

  1. 全局变量混淆:使用全局变量pieces存储棋子,每次创建新棋子都会覆盖该变量,导致所有操作最终指向最后创建的车(对应棋盘最后一个组件board.getComponent(63)),点击任何棋子都会影响这个全局的车,造成未操作的车消失。
  2. 拖拽对象错误:mouseDragged方法中操作的是全局pieces而非选中的chessPiece,导致拖拽时移动的是车,而非当前点击的棋子。
  3. 组件操作逻辑错误:
    • mousePressed中未将棋子从原父容器移除就添加到分层窗格,导致组件重复存在,引发显示混乱。
    • mouseReleased中调用pieces.getComponent(actuallocation)是错误的,pieces是单个JLabel而非容器,无法获取子组件;同时parent.remove(0)会粗暴移除父容器第一个组件,而非目标位置的棋子。
    • 错误调用pieces.setVisible(false)会隐藏全局的车,导致其莫名消失。

修复方案

1. 修正全局变量使用

取消全局pieces变量,改用局部变量创建棋子,或用集合存储所有棋子以便管理:

// 创建黑车示例:使用局部变量,并存入集合
List<JLabel> allPieces = new ArrayList<>();
JLabel blackRook = new JLabel(new ImageIcon("blackrook.png"));
JPanel targetPanel = (JPanel) board.getComponent(63);
targetPanel.add(blackRook);
allPieces.add(blackRook);

2. 修正鼠标监听器逻辑

添加originalParent变量记录棋子原父容器,确保操作对象始终是当前选中的chessPiece:

private JLabel chessPiece;
private Container originalParent;
private int xAdjustment, yAdjustment;

public void mousePressed(MouseEvent e) {
    chessPiece = null;
    Component c = board.findComponentAt(e.getX(), e.getY());
    if (c instanceof JPanel) {
        return;
    }

    // 计算鼠标与棋子左上角的偏移量,确保拖拽时棋子跟随鼠标位置
    Point mousePos = e.getLocationOnScreen();
    Point parentPos = c.getParent().getLocationOnScreen();
    xAdjustment = mousePos.x - parentPos.x;
    yAdjustment = mousePos.y - parentPos.y;

    chessPiece = (JLabel) c;
    originalParent = chessPiece.getParent();
    // 从原容器移除棋子,避免重复显示
    originalParent.remove(chessPiece);
    originalParent.repaint();

    // 将棋子添加到分层窗格的拖拽层
    chessPiece.setLocation(mousePos.x - xAdjustment, mousePos.y - yAdjustment);
    layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
    layeredPane.repaint();
}

public void mouseDragged(MouseEvent e) {
    if (chessPiece == null) return;
    // 根据偏移量调整棋子位置,实现跟随拖拽
    chessPiece.setLocation(e.getX() - xAdjustment, e.getY() - yAdjustment);
}

public void mouseReleased(MouseEvent e) {
    if (chessPiece == null) return;
    // 从分层窗格移除拖拽中的棋子
    layeredPane.remove(chessPiece);

    Component targetComp = board.findComponentAt(e.getX(), e.getY());
    Container targetParent;

    if (targetComp instanceof JLabel) {
        // 目标位置有棋子,移除它(模拟吃子)
        targetParent = targetComp.getParent();
        targetParent.remove(targetComp);
    } else {
        // 目标位置是空棋盘格
        targetParent = (Container) targetComp;
    }

    // 将棋子添加到目标位置
    targetParent.add(chessPiece);
    targetParent.repaint();
    // 重置选中状态
    chessPiece = null;
}

内容的提问来源于stack exchange,提问作者arthur ho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:45:48