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

如何在JFrame中添加JPanel且不清除已绘制的图形?

解决Java Swing国际象棋初始棋子不可见及拖动时棋盘消失问题

问题根源

  1. 初始棋子不可见

    • 直接在JFrame的paint方法中绘制棋盘,且未调用super.paint(g),导致添加的PieceImage子组件无法被渲染。
    • PieceImage作为JPanel,默认未设置合适尺寸,且未开启透明模式,即使被绘制也会因遮挡或尺寸问题无法显示。
  2. 拖动时棋盘消失

    • 拖动棋子触发重绘时,JFrame的paint方法未正确处理组件层次,直接覆盖棋盘绘制;同时直接在JFrame上绘制棋盘不符合Swing组件设计规范,导致重绘顺序混乱。

修改后的完整代码

1. 棋盘面板(BoardPanel.java)

专门负责棋盘绘制的底层组件,替代直接在JFrame中绘制:

import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;

public class BoardPanel extends JPanel {
    
    public BoardPanel() {
        setSize(1000, 1000);
        setLayout(null); // 使用绝对布局,方便棋子定位
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int[] swap  = {1,2};
        String[] rowNum = {"8","7","6","5","4","3","2","1"};
        String[] ColumnLetter = {"A","B","C","D","E","F","G","H"};
        int rowCount = 0;
        int columnCount = 0;
        for(int i=100;i<900;i+=100)
        {
            for(int j=100;j<900;j+=100)
            {
                if(i==100)
                {
                    g.setColor(Color.black);
                    g.drawString(rowNum[rowCount++],i-20,j+60);
                }
                if(j==100)
                {
                    g.setColor(Color.black);
                    g.drawString(ColumnLetter[columnCount++],i+50,j+820);
                }
                if(swap[0] == 1)
                    g.setColor(Color.white);
                else
                    g.setColor(Color.black);
                swapColor(swap);
                g.fillRect(i,j,100,100);
                if(j==800)
                    swapColor(swap);
            }
        }
    }
    
    private void swapColor(int[] swap)
    {
        int temp = swap[0];
        swap[0] = swap[1];
        swap[1] = temp;
    }
}

2. 主窗口(BoardGUI.java)

将棋盘面板作为内容容器,棋子添加到棋盘面板中:

import javax.swing.JFrame;

public class BoardGUI extends JFrame {
    
    public BoardGUI()
    {
        this.setSize(1000,1000);
        this.setTitle("Chess");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // 初始化棋盘面板并设置为内容面板
        BoardPanel boardPanel = new BoardPanel();
        this.setContentPane(boardPanel);
        
        // 添加棋子到棋盘面板
        PieceImage king = new PieceImage("./king.png",500,800);
        boardPanel.add(king);
        
        this.setVisible(true);
    }
}

3. 棋子组件(PieceImage.java)

修复显示与拖动逻辑,确保初始可见且拖动不遮挡棋盘:

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.Graphics;
import java.awt.Point;

public class PieceImage extends JPanel {
    private ImageIcon image;
    private Point offset; // 鼠标点击位置相对于棋子左上角的偏移量
    
    public PieceImage(String imagePath, int xPos, int yPos)
    {
        if(imagePath == null)
            return;
        this.image = new ImageIcon(imagePath);
        // 设置组件大小与图片一致
        setSize(image.getIconWidth(), image.getIconHeight());
        // 设置初始位置
        setLocation(xPos, yPos);
        // 开启透明模式,避免遮挡棋盘
        setOpaque(false);
        
        // 合并鼠标点击与拖动监听器
        MouseAdapter mouseHandler = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                // 记录鼠标相对于棋子的偏移,避免拖动时棋子跳变
                offset = e.getPoint();
            }
            
            @Override
            public void mouseDragged(MouseEvent e) {
                // 获取鼠标在父容器(棋盘)中的位置,计算棋子新位置
                Point parentMousePos = getParent().getMousePosition();
                if (parentMousePos != null) {
                    int newX = (int) parentMousePos.getX() - offset.x;
                    int newY = (int) parentMousePos.getY() - offset.y;
                    setLocation(newX, newY);
                }
            }
        };
        
        addMouseListener(mouseHandler);
        addMouseMotionListener(mouseHandler);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null) {
            // 从组件左上角绘制图片,匹配组件位置
            image.paintIcon(this, g, 0, 0);
        }
    }
}

关键修改说明

  • 棋盘绘制分离:将棋盘绘制逻辑移到独立的BoardPanel中,符合Swing组件层次设计,确保棋盘作为底层容器稳定显示。
  • 棋子组件优化:设置透明模式、匹配图片尺寸、修复拖动坐标计算,保证棋子初始可见且拖动时不遮挡棋盘。
  • 重绘逻辑修复:调用super.paintComponent(g)确保组件背景与子组件正确渲染,避免重绘时内容丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 14:03:23