You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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()的效果
  • 预期实现的效果,白色背景仅在边框内部显示:
    预期效果
  • 启用注释的paintComponent()逻辑后,调用setText("String");设置文本时,边角区域出现其他组件重叠绘制的残影:
    setText后的异常效果

问题原因

重写的paintComponent逻辑存在两个核心错误:

  1. 没有调用super.paintComponent(g):JLabel的文本、图标绘制逻辑都封装在父类方法中,不调用会导致文本无法正常绘制,同时重绘流程不完整。
  2. 违反Swing的opaque绘制约定:当给组件设置setOpaque(true)时,相当于告诉Swing“这个组件会自己填充所有边界内的像素”,但原逻辑只填充了边框内部的矩形区域,四个边角属于边框的位置没有做任何绘制。Swing触发局部重绘(比如调用setText更新文本)时,不会自动清空未手动绘制的区域,之前画在这个位置的其他组件像素就会残留,形成重叠残影。

修复方法

只需要做两处修改即可:

  1. 删除MyLabel构造方法里的setOpaque(true);,让标签保持默认非不透明状态。这种情况下Swing重绘标签时,会自动先把标签区域的父容器背景绘制完成,自动清空边角的残留像素,不需要手动处理。
  2. 重写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 15:15:33