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

Java纸牌游戏拖拽功能异常:卡片堆叠错误与原位置未移除

Java Solitaire拖拽问题:卡片覆盖而非堆叠、原卡片未移除的修复方案

核心问题定位

你遇到的问题本质是TransferHandler未正确实现MOVE操作的完整流程,以及目标组件的Drop逻辑未处理卡片堆叠逻辑,同时原组件未在拖拽完成后移除对应卡片。


1. 自定义TransferHandler实现MOVE完整流程

默认TransferHandler不会自动处理原组件的移除,需自定义类重写关键方法,确保拖拽完成后删除原位置卡片:

class CardTransferHandler extends TransferHandler {
    @Override
    protected Transferable createTransferable(JComponent c) {
        // 从卡片组件中获取Card对象(假设组件通过clientProperty绑定卡片数据)
        Card card = (Card) c.getClientProperty("card");
        // 用卡片唯一标识传输(若Card实现Serializable,可直接传输对象)
        return new StringSelection(card.getUniqueId());
    }

    @Override
    public int getSourceActions(JComponent c) {
        return TransferHandler.MOVE; // 明确指定MOVE动作
    }

    @Override
    protected void exportDone(JComponent source, Transferable data, int action) {
        super.exportDone(source, data, action);
        // 仅当MOVE动作完成时,移除原位置卡片
        if (action == TransferHandler.MOVE) {
            JPanel sourceStack = (JPanel) source.getParent();
            sourceStack.remove(source);
            sourceStack.revalidate();
            sourceStack.repaint();
        }
    }
}

给卡片组件绑定该TransferHandler及拖拽触发事件:

CardComponent cardComp = new CardComponent(targetCard);
cardComp.setTransferHandler(new CardTransferHandler());
cardComp.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        JComponent source = (JComponent) e.getSource();
        source.getTransferHandler().exportAsDrag(source, e, TransferHandler.MOVE);
    }
});

2. 目标Tableau Stack的Drop逻辑实现

目标堆叠组件(JPanel)需设置DropTarget,处理拖拽数据并将卡片添加到堆叠顶部:

class TableauStack extends JPanel {
    public TableauStack() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        setDropTarget(new DropTarget() {
            @Override
            public synchronized void drop(DropTargetDropEvent dtde) {
                try {
                    dtde.acceptDrop(TransferHandler.MOVE);
                    // 获取传输的卡片ID,还原为Card对象
                    String cardId = (String) dtde.getTransferable().getTransferData(DataFlavor.stringFlavor);
                    Card draggedCard = CardRepository.getCardById(cardId); // 自定义方法:从全局卡片池获取卡片

                    // 创建新的卡片组件并添加到堆叠顶部
                    CardComponent newCardComp = new CardComponent(draggedCard);
                    newCardComp.setTransferHandler(new CardTransferHandler());
                    // 绑定鼠标拖拽事件(同上述卡片组件逻辑)
                    add(newCardComp);
                    
                    revalidate();
                    repaint();
                    dtde.dropComplete(true);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    dtde.dropComplete(false);
                }
            }
        });
    }
}

3. 关键注意事项

  • DataFlavor匹配:传输与接收的DataFlavor必须一致,若直接传输Card对象,需让Card类实现Serializable,并使用new DataFlavor(Card.class, "Card")
  • 避免直接拖拽组件:拖拽组件易导致覆盖问题,建议传输卡片数据(ID/对象),在目标位置重新创建组件
  • 强制UI更新:每次添加/移除卡片后,必须调用revalidate()和repaint()刷新界面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:21:59