Java Swing调用repaint()未渲染方块仅显示红色背景问题排查
Swing自定义绘制不生效问题修复
核心故障点
故障和repaint()方法本身无关,代码中存在4个直接导致绘制异常的问题:
- 绘制方法名拼写错误:Swing组件的自定义绘制入口是
protected void paintComponent(Graphics g),你把方法名写成了drawComponent,Swing重绘流程不会识别、调用这个自定义方法,所有矩形绘制逻辑从未执行,自然只能看到默认绘制的红色背景。 - 图形资源提前释放:你在绘制完橙色填充矩形后立刻调用
g2d.dispose()释放图形上下文,后续的矩形边框绘制代码执行时会因为资源已释放抛出运行时异常,哪怕方法名改对了也会导致绘制中断。 - 屏幕尺寸计算错误:
screenHeight计算时错误使用列数maxScreenCol作为乘数,实际应该乘以行数maxScreenRow,会导致面板实际尺寸和预期不符。 - 游戏循环无帧率控制:当前
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
相关产品推荐
相关产品推荐

