Java Swing自定义JComponent添加到JPanel后不显示问题咨询
问题根因
自定义JComponent不显示是违反Swing基础开发规范导致的,具体问题点:
- 错误重写了
paint方法,没有重写正确的绘制方法paintComponent,且没有调用父类绘制逻辑,破坏了Swing的绘制链 - 没有给自定义的
Player组件设置首选尺寸,Swing布局管理器计算得到的组件尺寸为0*0,不会分配渲染空间 - Swing组件初始化没有放在事件调度线程(EDT)中执行,存在渲染偶发失效的线程安全隐患
- 关闭窗口的常量调用写法不规范,虽然不影响本次运行,但属于易出错的写法
修正代码
Player组件类修正
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import javax.swing.JComponent; public class Player extends JComponent{ public Player() { // 为组件设置首选尺寸,大小覆盖要绘制的矩形范围 setPreferredSize(new Dimension(200, 200)); } @Override protected void paintComponent(Graphics g) { // 必须先调用父类方法完成默认背景等绘制逻辑 super.paintComponent(g); g.setColor(Color.green); // 绘制坐标相对于当前组件的左上角,不是父容器的左上角 g.fillRect(40,40,150,150); } }
Game面板类(无需大改,保持原有逻辑即可)
import java.awt.Color; import java.awt.Dimension; import javax.swing.JPanel; public class Game extends JPanel{ public Game() { this.setBackground(Color.yellow); this.setPreferredSize(new Dimension(500,500)); Player p = new Player(); this.add(p); } }
Launcher启动类修正
import javax.swing.JFrame; import javax.swing.SwingUtilities; public class Launcher { public static void main(String[] args) { // 所有Swing界面操作必须在事件调度线程中执行,避免线程安全导致的渲染异常 SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Key Collector Demo"); frame.add(new Game()); frame.pack(); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } }
开发注意事项
- 自定义Swing组件绘制时,永远优先重写
paintComponent而非paint:paint是Swing的顶层绘制入口,会依次调用paintComponent(绘制组件本身)、paintBorder(绘制边框)、paintChildren(绘制子组件),直接重写paint很容易跳过必要的绘制逻辑,出现渲染异常 - 自定义轻量级组件必须主动返回合适的首选尺寸,否则大部分布局管理器会默认给组件分配0*0的空间,组件不会显示
- 所有Swing组件的创建、修改操作都要放到EDT线程中执行,Swing本身不是线程安全的,跨线程操作UI会出现偶发的不渲染、卡死、脏绘问题
- 绘制方法中的坐标是相对于当前组件自身左上角的,不要直接使用父容器的坐标计算绘制位置
内容的提问来源于stack exchange,提问作者AshDaddy377
相关产品推荐
相关产品推荐

