Java Swing中JPanel调用repaint()未触发paintComponent()问题
问题诊断与解决
核心问题:你的PixelArtCreator面板未被正确布局显示,导致repaint()无法触发paintComponent()。以下是具体问题点和修复方案:
问题1:空布局导致面板不可见
主类中frame.setLayout(null)使用了空布局,但未给添加的PixelArtCreator面板设置边界(Bounds)。空布局下Swing不会自动管理组件的位置和大小,面板默认尺寸为(0,0,0,0),相当于完全隐藏,自然不会触发绘制逻辑。
问题2:paintComponent未调用父类方法
重写paintComponent时必须调用super.paintComponent(g),这是Swing绘制机制的核心要求——父类方法负责完成面板清空、UI委托处理等基础绘制工作,缺失会导致绘制链断裂,即使面板显示也可能出现画面残留、不更新等异常。
问题3:JFrame大小设置不严谨
手动计算frame.setSize(PixelArtCreator.width+14, PixelArtCreator.height+38)依赖系统窗口装饰尺寸,不同系统(Windows/macOS/Linux)的边框、标题栏高度存在差异,容易导致面板显示不全。改用pack()方法让JFrame自动适配组件首选尺寸更稳妥。
修复后的完整代码
PixelArtCreator类修复
package de.luiskun.handling; import de.luiskun.UtilityTool; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; public class PixelArtCreator extends JPanel implements Runnable{ BufferedImage imgBefore; Thread gameThread; public static final int width = 900, height = 500; int fps = 60; public PixelArtCreator() { this.setPreferredSize(new Dimension(width, height)); this.setDoubleBuffered(true); this.setLayout(null); this.setFocusable(true); imgBefore = UtilityTool.SetupImage("res/preparation/00001", 512, 512); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // 必须调用父类基础绘制方法 System.out.println(1); Graphics2D g2 = (Graphics2D) g; if(imgBefore != null) { g2.drawImage(imgBefore, 10, 10, 512, 512, null); } g2.dispose(); // 释放Graphics2D资源 } public void startGameThread() { gameThread = new Thread(this); gameThread.start(); } @Override public void run() { double drawInterval = 1000000000 / fps; double delta = 0; long lastTime = System.nanoTime(); // 改用long类型避免浮点数精度问题 long currentTime; while (gameThread != null) { currentTime = System.nanoTime(); delta += (currentTime - lastTime) / drawInterval; lastTime = currentTime; if (delta >= 1) { System.out.println(2); this.repaint(); delta--; } } } }
Main类修复
package de.luiskun; import de.luiskun.handling.PixelArtCreator; import javax.swing.*; public class Main { public static void main(String[] args) { // Swing组件必须在事件调度线程(EDT)中创建,避免线程安全问题 SwingUtilities.invokeLater(Main::new); } public Main() { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setResizable(false); PixelArtCreator s = new PixelArtCreator(); frame.add(s); frame.pack(); // 自动适配组件首选尺寸 frame.setVisible(true); s.startGameThread(); } }
额外优化说明
- 新增
SwingUtilities.invokeLater(Main::new):Swing要求所有组件的创建和操作必须在**事件调度线程(EDT)**中执行,否则可能出现UI卡顿、线程安全异常,之前的代码直接在main线程创建组件不符合规范。 run()方法中时间变量改为long:避免浮点数精度损耗,计时逻辑更准确。- 新增
g2.dispose():手动释放Graphics2D资源,优化内存占用。
内容的提问来源于stack exchange,提问作者burprinz
相关产品推荐
相关产品推荐

