Swing自定义JLabel的paintComponent方法添加到JPanel不生效问题
问题根因
- 核心错误是
DLabel的绘制坐标使用了父面板的绝对坐标,而非组件自身的相对坐标:Swing中每个组件的paintComponent方法接收的Graphics对象的坐标原点是当前组件的左上角,你已经通过dlabel.setBounds(152, 150, 60, 15)把DLabel放在了父面板的(152,150)位置,组件自身的宽高只有60*15,此时在DLabel里调用g2.fillRect(152, 150, 60, 15)相当于画到了组件可视区域之外,自然看不到填充效果。 - 额外冗余问题:
GUI类本身已经继承了JFrame,又在内部声明了一个新的JFrame frame对象,属于不必要的重复定义。
修复方案
快速修复DLabel的绘制代码
只要把DLabel的填充坐标改成相对于自身的坐标即可:
public class DLabel extends JLabel { @Override public void paintComponent(Graphics g) { System.out.println("--------IN DLABEL paintComponent--------"); super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.green); // 从组件自身左上角开始填充,刚好填满整个DLabel区域 g2.fillRect(0, 0, getWidth(), getHeight()); } }
运行后就能看到第一个矩形已经被绿色填充。
更推荐的最佳实践
不需要单独定义DLabel组件,直接在MyPanel里维护所有矩形的状态即可,逻辑更简洁,也避免了绝对布局带来的各种坐标问题:
- 改造MyPanel代码,内置矩形状态管理:
public class MyPanel extends JPanel { // 存储8个矩形的坐标和尺寸:x,y,width,height private final int[][] rects = new int[][]{ {152, 150, 60, 15}, {152, 275, 60, 15}, {152, 400, 60, 15}, {421, 205, 60, 15}, {421, 355, 60, 15}, {720, 130, 60, 15}, {720, 280, 60, 15}, {720, 430, 60, 15} }; // 存储每个矩形的状态:0=空心黑色,1=填充绿色,2=填充红色,可根据业务调整 private int[] rectStatus = new int[8]; // 提供修改矩形状态的公开方法,业务侧调用后自动刷新界面 public void setRectStatus(int index, int status) { if(index >=0 && index < rectStatus.length) { this.rectStatus[index] = status; repaint(); } } @Override public void paintComponent(Graphics g){ super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; // 遍历绘制所有矩形 for(int i=0; i<rects.length; i++) { int x = rects[i][0]; int y = rects[i][1]; int w = rects[i][2]; int h = rects[i][3]; int status = rectStatus[i]; if(status == 0) { g2.setColor(Color.BLACK); g2.drawRect(x, y, w, h); } else if(status == 1) { g2.setColor(Color.GREEN); g2.fillRect(x, y, w, h); } else if(status == 2) { g2.setColor(Color.RED); g2.fillRect(x, y, w, h); } } } }
- 简化GUI类代码:
public class GUI extends JFrame { MyPanel mypanel; public GUI() throws Exception { super("Test"); mypanel = new MyPanel(); // 测试:把第0个矩形设为绿色填充 mypanel.setRectStatus(0, 1); getContentPane().add(mypanel); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setSize(1000, 500); setResizable(false); setVisible(true); } }
后续需要修改任意矩形的填充状态,只要调用mypanel.setRectStatus(矩形索引, 状态值)就可以自动刷新界面,不需要管理多个子组件,维护成本低很多。
内容的提问来源于stack exchange,提问作者bendy
相关产品推荐
相关产品推荐

