如何在Swing的TitledBorder边框范围内设置JLabel背景?
JLabel设置标题边框后背景溢出、重绘残影问题修复
我对JLabel组件执行setBackground(Color.WHITE)和setBorder(new CustomTitledBorder(Color.BLACK, "Some Text"))操作后,JLabel的白色背景会绘制到边框范围之外,我尝试通过重写paintComponent方法解决,相关测试代码如下:
import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.border.TitledBorder; public class TempFrame extends JFrame { private JPanel contentPane; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { TempFrame frame = new TempFrame(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the frame. */ public TempFrame() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(null); setContentPane(contentPane); var label = new MyLabel(); label.setBounds(10, 10, 334, 65); getContentPane().add(label); JButton btnNewButton = new JButton("Click To Add Text"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { label.setText("String"); } }); btnNewButton.setBounds(127, 86, 89, 23); contentPane.add(btnNewButton); } private class MyLabel extends JLabel { public MyLabel() { // 原代码的setOpaque(true)后续会移除 setOpaque(true); setBorder(new CustomTitledBorder(Color.BLACK, "Title Here")); setBackground(Color.WHITE); } /* 原问题中注释的重写逻辑,存在问题 @Override protected void paintComponent(Graphics g) { var insets = this.getBorder().getBorderInsets(this); g.setColor(Color.WHITE); g.fillRect(insets.left, insets.top, getWidth() - insets.left - insets.right, getHeight() - insets.top - insets.bottom); } */ } private class CustomTitledBorder extends TitledBorder { public CustomTitledBorder(Color color, String title) { super(new LineBorder(color), title); } } }
不同场景下的效果如下:
- 未重写
paintComponent()方法时,白色背景溢出到边框下方:
- 预期实现的效果,白色背景仅在边框内部显示:

- 启用注释的
paintComponent()逻辑后,调用setText("String");设置文本时,边角区域出现其他组件重叠绘制的残影:
问题原因
重写的paintComponent逻辑存在两个核心错误:
- 没有调用
super.paintComponent(g):JLabel的文本、图标绘制逻辑都封装在父类方法中,不调用会导致文本无法正常绘制,同时重绘流程不完整。 - 违反Swing的opaque绘制约定:当给组件设置
setOpaque(true)时,相当于告诉Swing“这个组件会自己填充所有边界内的像素”,但原逻辑只填充了边框内部的矩形区域,四个边角属于边框的位置没有做任何绘制。Swing触发局部重绘(比如调用setText更新文本)时,不会自动清空未手动绘制的区域,之前画在这个位置的其他组件像素就会残留,形成重叠残影。
修复方法
只需要做两处修改即可:
- 删除
MyLabel构造方法里的setOpaque(true);,让标签保持默认非不透明状态。这种情况下Swing重绘标签时,会自动先把标签区域的父容器背景绘制完成,自动清空边角的残留像素,不需要手动处理。 - 重写
paintComponent方法,先填充边框内部的白色背景,再调用父类方法完成文本、图标的绘制,正确代码如下:
@Override protected void paintComponent(Graphics g) { Insets insets = getBorder().getBorderInsets(this); // 仅在边框内部区域填充白色背景 g.setColor(getBackground()); g.fillRect(insets.left, insets.top, getWidth() - insets.left - insets.right, getHeight() - insets.top - insets.bottom); // 调用父类默认逻辑绘制文本、图标等内容 super.paintComponent(g); }
修改后不会再出现背景溢出、重绘残影的问题,文本也能正常显示。
内容的提问来源于stack exchange,提问作者Ell
相关产品推荐
相关产品推荐

