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

Java Swing调用repaint()未渲染方块仅显示红色背景问题排查

Swing自定义绘制不生效问题修复

核心故障点

故障和repaint()方法本身无关,代码中存在4个直接导致绘制异常的问题:

  1. 绘制方法名拼写错误:Swing组件的自定义绘制入口是protected void paintComponent(Graphics g),你把方法名写成了drawComponent,Swing重绘流程不会识别、调用这个自定义方法,所有矩形绘制逻辑从未执行,自然只能看到默认绘制的红色背景。
  2. 图形资源提前释放:你在绘制完橙色填充矩形后立刻调用g2d.dispose()释放图形上下文,后续的矩形边框绘制代码执行时会因为资源已释放抛出运行时异常,哪怕方法名改对了也会导致绘制中断。
  3. 屏幕尺寸计算错误:screenHeight计算时错误使用列数maxScreenCol作为乘数,实际应该乘以行数maxScreenRow,会导致面板实际尺寸和预期不符。
  4. 游戏循环无帧率控制:当前while循环是无间隔死循环,会占满单个CPU核心资源,可能导致Swing绘制事件调度被阻塞。

另外MainWindow类里重复调用了两次setVisible(true),还使用魔法值3作为关闭操作参数,属于不规范写法,会引发窗口初次加载闪烁问题。

修复方案

  • 将自定义绘制方法重命名为paintComponent,添加@Override注解,强制编译器校验方法签名正确性,避免写错方法名不被调用的问题。注意该方法访问修饰符是protected,不要写成public。
  • 删除绘制逻辑中提前调用的g2d.dispose(),Swing会自行管理传入的Graphics对象生命周期,不需要手动释放。
  • 修正screenHeight计算逻辑,将乘数改为maxScreenRow。
  • 给游戏循环添加60FPS帧率控制,避免CPU空转阻塞事件线程。
  • 调整MainWindow初始化顺序,删除重复的setVisible调用,使用Swing提供的常量替代魔法值。

修复后核心代码

// MainWindow类修正
public class MainWindow {
    public static void main(String[] args) {
        GamePanel gamepanel  = new GamePanel();
        JFrame window = new JFrame();
        // 使用常量替代魔法值
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(true);
        window.setTitle("2D Adventure Game" + Info.version);
        window.add(gamepanel);
        // 先完成pack再设置可见,删除重复的setVisible调用
        window.pack();
        window.setLocationRelativeTo(null);
        window.setVisible(true);
        // 窗口可见后再启动游戏线程
        gamepanel.startGameThread();
    }
}

// GamePanel类修正部分
public class GamePanel extends JPanel implements Runnable{
    private static final long serialVersionUID = 1L;
    public static final int originalPlayerSize = 16;
    public static final int scale = 3;
    public static final int tileSize = originalPlayerSize * scale;
    public static final int maxScreenCol = 40;
    public static final int maxScreenRow = 22;
    // 修正屏幕高度计算
    public static final int screenWidth = tileSize * maxScreenCol;
    public static final int screenHeight = tileSize * maxScreenRow;
    
    Thread gameThread;
    
    public GamePanel() {
        this.setPreferredSize(new Dimension(screenWidth, screenHeight));
        this.setBackground(Color.red);
        this.setDoubleBuffered(true);
    }
    
    public void startGameThread() {
        gameThread = new Thread(this);
        gameThread.start();
    }

    @Override
    public void run() { 
        // 60FPS帧率控制
        final long frameTime = 1000000000 / 60;
        long lastTime = System.nanoTime();
        while(gameThread != null) {
            long now = System.nanoTime();
            if (now - lastTime >= frameTime) {
                update();
                repaint();
                lastTime = now;
            }
            Thread.yield();
        }
    }

    public static void update() {
        // 后续游戏逻辑写在这里
    }

    // 修正方法名、注解,删除提前dispose的错误代码
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setColor(Color.ORANGE);
        g2d.fillRect(100, 100, tileSize, tileSize);
        g2d.setColor(Color.BLACK);
        g2d.drawRect(50, 50, 100, 100);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:09:23