当前位置:

首页 > 编程开发 > Java Swing自定义复选框CusCheckBox组件(附源码)

Java Swing自定义复选框CusCheckBox组件(附源码)

Swing原生复选框样式受系统限制,难以统一自定义。CusCheckBox组件通过实现Icon接口,将绘制逻辑完全掌控。核心由CheckBoxIcon和CusCheckBox两个类构成,前者负责绘制图标,后者包装标准组件并提供样式设置方法,实现了圆角、颜色、状态等外观的灵活定制。

一、背景

用过Swing的朋友都知道,原生的JCheckBox复选框图标是跟着系统走的。Windows、macOS、Linux,每个平台画出来的样子都不一样。这要是想做个界面风格统一的桌面应用,可就头疼了——圆角、颜色、鼠标悬停效果,这些统统没法自定义。

所以,想要一个完全听你指挥的复选框,就得自己动手画。今天要聊的这个CusCheckBox组件,就是通过实现Icon接口,把绘制逻辑完全掌握在自己手里,圆角、颜色、悬停、禁用状态,想怎么调就怎么调。

Ja va Swing自定义复选框CusCheckBox组件(附源码)

二、核心设计

整个CusCheckBox的实现非常清晰,主要由两个类构成:

  • CheckBoxIcon:这是核心的“画家”。它实现了Icon接口,专门负责绘制复选框的图标部分,包括背景、边框、对勾(或叉号)。
  • CusCheckBox:这是对标准JCheckBox的“包装”。它继承自JCheckBox,但把默认图标换成了我们自己的CheckBoxIcon,并对外提供了一整套设置样式的方法。

这种分工很明确:一个管画,一个管用。

三、CheckBoxIcon 源码

import lombok.Setter;

import ja vax.swing.*;
import ja va.awt.*;

/**
 * 自定义 JCheckBox 图标类
 * 实现 Icon 接口,负责绘制复选框的图标部分
 *
 * 使用示例:
 * CheckBoxIcon icon = new CheckBoxIcon(20, Color.decode("#409EFF"), Color.WHITE);
 */
@Setter
public class CheckBoxIcon implements Icon {
    /** 复选框大小 */
    private int size;
    /** 圆角 */
    private boolean rounded = true;
    /** 圆角半径 */
    private int borderRadius = 8;
    /** 边框宽度 */
    private int borderThickness = 1;
    /** 边框颜色 */
    private Color borderColor = Color.GRAY;
    /** 选中背景颜色 */
    private Color selectedBg;
    /** 对勾颜色 */
    private Color checkColor;
    /** 悬停颜色 */
    private Color hoverColor;
    /** 禁用颜色 */
    private Color disabledColor = Color.decode("#E4E7ED");
    /** 对勾宽度 */
    private float checkThickness = 2.0f;
    /** 是否使用对勾(true=对勾,false=叉号) */
    private boolean useCheckMark = true;
    /** 是否启用 */
    private boolean enabled = true;

    /**
     * 构造函数
     * @param size 图标尺寸
     * @param selectedBg 选中时的背景色
     * @param checkColor 对勾颜色
     */
    public CheckBoxIcon(int size, Color selectedBg, Color checkColor) {
        this.size = Math.max(16, size);
        this.selectedBg = selectedBg;
        this.checkColor = checkColor;
    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        AbstractButton button = (AbstractButton) c;
        ButtonModel model = button.getModel();
        Graphics2D g2 = (Graphics2D) g;
        // 启用抗锯齿
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 获取状态
        boolean isSelected = model.isSelected();
        boolean isPressed = model.isPressed();
        boolean isRollover = model.isRollover();
        // 计算实际绘制区域
        int drawWidth = size - 1;
        int drawHeight = size - 1;
        // 根据状态选择颜色
        Color currentBorder = enabled ? borderColor : disabledColor;
        Color currentBg = Color.WHITE;
        if (isSelected) {
            currentBg = enabled ? selectedBg : disabledColor.brighter();
        }
        if (isRollover && !isPressed && enabled && null != hoverColor) {
            currentBg = hoverColor;
        }
        if (isPressed && enabled) {
            currentBg = selectedBg.darker();
        }
        if (!enabled) {
            currentBg = disabledColor;
        }
        // 绘制背景
        g2.setColor(currentBg);
        if (rounded) {
            g2.fillRoundRect(x, y, drawWidth, drawHeight, borderRadius, borderRadius);
        } else {
            g2.fillRect(x, y, drawWidth, drawHeight);
        }
        // 绘制边框
        g2.setColor(currentBorder);
        g2.setStroke(new BasicStroke(borderThickness));
        if (rounded) {
            g2.drawRoundRect(x, y, drawWidth, drawHeight, borderRadius, borderRadius);
        } else {
            g2.drawRect(x, y, drawWidth, drawHeight);
        }
        // 绘制选中标记
        if (isSelected) {
            drawCheckMark(g2, x, y, drawWidth, drawHeight);
        }
    }

    /**
     * 绘制选中标记(对勾或叉号)
     * @param g2 Graphics2D 对象
     * @param x 起始 X 坐标
     * @param y 起始 Y 坐标
     * @param width 绘制宽度
     * @param height 绘制高度
     */
    private void drawCheckMark(Graphics2D g2, int x, int y, int width, int height) {
        Color currentCheckColor = enabled ? checkColor : Color.DARK_GRAY;
        g2.setColor(currentCheckColor);
        g2.setStroke(new BasicStroke(checkThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        // 20% 内边距
        float padding = width * 0.2f;
        int startX = (int) (x + padding);
        int startY = y + height / 2;
        int midX = x + width / 2;
        int midY = (int) (y + height - padding);
        int endX = (int) (x + width - padding);
        int endY = (int) (y + padding);
        if (useCheckMark) {
            // 对勾
            g2.drawLine(startX, startY, midX, midY);
            g2.drawLine(midX, midY, endX, endY);
        } else {
            // 叉号
            g2.drawLine(startX, startY, endX, endY);
            g2.drawLine(startX, endY, endX, startY);
        }
    }

    @Override
    public int getIconWidth() {
        return size;
    }

    @Override
    public int getIconHeight() {
        return size;
    }

    /**
     * 设置图标尺寸
     * @param size 尺寸
     */
    public void setSize(int size) {
        this.size = Math.max(16, size);
    }
}

四、CusCheckBox 源码

import ja vax.swing.*;
import ja va.awt.*;

/**
 * 自定义复选框
 * 通过自定义 Icon 实现统一的复选框样式
 *
 * 使用示例:
 * CusCheckBox checkBox = new CusCheckBox("同意协议");
 * checkBox.setSelected(true);
 * checkBox.setHoverColor(Color.LIGHT_GRAY);
 */
public class CusCheckBox extends JCheckBox {
    /** 默认尺寸 */
    private static final int DEFAULT_SIZE = 20;
    /** 默认选中背景颜色 */
    private static final Color DEFAULT_BG = Color.decode("#409EFF");
    /** 默认选中对勾颜色 */
    private static final Color DEFAULT_CHECK = Color.WHITE;
    /** 内部图标实例 */
    private final CheckBoxIcon icon;

    /**
     * 默认构造函数
     * @param text 复选框文本
     */
    public CusCheckBox(String text) {
        this(text, DEFAULT_SIZE, DEFAULT_BG, DEFAULT_CHECK, false);
    }

    /**
     * 指定选中状态
     * @param text 复选框文本
     * @param selected 是否选中
     */
    public CusCheckBox(String text, boolean selected) {
        this(text, DEFAULT_SIZE, DEFAULT_BG, DEFAULT_CHECK, selected);
    }

    /**
     * 指定尺寸
     * @param text 复选框文本
     * @param size 图标尺寸
     */
    public CusCheckBox(String text, int size) {
        this(text, size, DEFAULT_BG, DEFAULT_CHECK, false);
    }

    /**
     * 指定尺寸和选中状态
     * @param text 复选框文本
     * @param size 图标尺寸
     * @param selected 是否选中
     */
    public CusCheckBox(String text, int size, boolean selected) {
        this(text, size, DEFAULT_BG, DEFAULT_CHECK, selected);
    }

    /**
     * 指定颜色
     * @param text 复选框文本
     * @param bg 选中时背景色
     * @param check 对勾颜色
     */
    public CusCheckBox(String text, Color bg, Color check) {
        this(text, DEFAULT_SIZE, bg, check, false);
    }

    /**
     * 指定颜色和选中状态
     * @param text 复选框文本
     * @param bg 选中时背景色
     * @param check 对勾颜色
     * @param selected 是否选中
     */
    public CusCheckBox(String text, Color bg, Color check, boolean selected) {
        this(text, DEFAULT_SIZE, bg, check, selected);
    }

    /**
     * 指定尺寸和颜色
     * @param text 复选框文本
     * @param size 图标尺寸
     * @param bg 选中时背景色
     * @param check 对勾颜色
     */
    public CusCheckBox(String text, int size, Color bg, Color check) {
        this(text, size, bg, check, false);
    }

    /**
     * 完整构造函数
     * @param text 复选框文本
     * @param size 图标尺寸
     * @param bg 选中时背景色
     * @param check 对勾颜色
     * @param selected 是否选中
     */
    public CusCheckBox(String text, int size, Color bg, Color check, boolean selected) {
        super(text);
        // 创建自定义图标
        this.icon = new CheckBoxIcon(size, bg, check);
        // 设置图标(选中和未选中共用同一个图标实例,通过状态区分绘制)
        this.setIcon(icon);
        this.setSelectedIcon(icon);
        // 设置选中状态
        this.setSelected(selected);
        // 设置文本颜色和字体
        this.setForeground(Color.BLACK);
        this.setFont(new Font("Microsoft YaHei", Font.PLAIN, 16));
        // 设置透明背景,让父容器背景显示
        this.setOpaque(false);
        // 禁用默认内容区域填充
        this.setContentAreaFilled(false);
        // 禁用边框绘制
        this.setBorderPainted(false);
        // 图标与文字间距
        this.setIconTextGap(10);
    }

    /**
     * 获取自定义图标
     * @return 图标对象
     */
    @Override
    public CheckBoxIcon getIcon() {
        return icon;
    }

    /**
     * 设置图标尺寸
     * @param size 尺寸
     */
    public void setIconSize(int size) {
        icon.setSize(size);
        revalidate();
        repaint();
    }

    /**
     * 设置选中时的背景色
     * @param color 颜色
     */
    public void setSelectedBackground(Color color) {
        icon.setSelectedBg(color);
        repaint();
    }

    /**
     * 设置对勾颜色
     * @param color 颜色
     */
    public void setCheckColor(Color color) {
        icon.setCheckColor(color);
        repaint();
    }

    /**
     * 设置边框颜色
     * @param color 颜色
     */
    public void setBorderColor(Color color) {
        icon.setBorderColor(color);
        repaint();
    }

    /**
     * 设置是否圆角
     * @param rounded 是否圆角
     */
    public void setRounded(boolean rounded) {
        icon.setRounded(rounded);
        repaint();
    }

    /**
     * 设置圆角半径
     * @param radius 半径
     */
    public void setBorderRadius(int radius) {
        icon.setRounded(true);
        icon.setBorderRadius(radius);
        repaint();
    }

    /**
     * 设置边框粗细
     * @param thickness 粗细
     */
    public void setBorderThickness(int thickness) {
        icon.setBorderThickness(thickness);
        repaint();
    }

    /**
     * 设置对勾线条粗细
     * @param thickness 粗细
     */
    public void setCheckThickness(float thickness) {
        icon.setCheckThickness(thickness);
        repaint();
    }

    /**
     * 设置使用对勾还是叉号
     * @param useCheckMark true=对勾,false=叉号
     */
    public void setUseCheckMark(boolean useCheckMark) {
        icon.setUseCheckMark(useCheckMark);
        repaint();
    }

    /**
     * 设置悬停时的背景色
     * @param color 颜色
     */
    public void setHoverColor(Color color) {
        icon.setHoverColor(color);
        repaint();
    }

    /**
     * 重写 setEnabled 以同步图标状态
     * @param enabled 是否启用
     */
    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        if (icon != null) {
            icon.setEnabled(enabled);
            repaint();
        }
    }
}

五、核心功能说明

看完代码,我们来梳理一下这两个类的核心职责。

图标绘制(CheckBoxIcon):

  • paintIcon:这是灵魂所在。它根据按钮的实时状态(选中、悬停、按下、禁用)来决定绘制什么颜色和样式,实现了状态驱动的动态外观。
  • drawCheckMark:负责绘制选中标记,支持对勾和叉号两种样式,线条粗细和颜色都可以定制。
  • 配置丰富:圆角还是直角?边框什么颜色多粗?背景、悬停、禁用状态的颜色是什么?这些都可以通过属性灵活设置。

复选框封装(CusCheckBox):

  • 核心操作就是用我们自定义的CheckBoxIcon替换掉原生的图标。
  • 提供了多个构造函数,让你可以按需组合尺寸、颜色和初始选中状态,用起来很方便。
  • 对外暴露了一整套样式设置方法,从圆角、颜色到悬停效果、对勾样式,应有尽有。
  • 通过设置透明背景,可以完美融入任何父容器,不会产生突兀的色块。

六、使用示例

理论说再多,不如看几个实际的例子来得直观。

6.1 基本用法

CusCheckBox checkBox = new CusCheckBox("同意用户协议");
panel.add(checkBox);

6.2 指定选中状态

CusCheckBox checkBox = new CusCheckBox("记住密码", true);
panel.add(checkBox);

6.3 自定义颜色和尺寸

CusCheckBox checkBox = new CusCheckBox("自定义样式", 24, Color.decode("#67C23A"), Color.WHITE);
checkBox.setHoverColor(Color.decode("#E6F7E6"));
panel.add(checkBox);

6.4 圆角半径调整

CusCheckBox checkBox = new CusCheckBox("圆角复选框");
checkBox.setBorderRadius(12);
panel.add(checkBox);

6.5 使用叉号代替对勾

CusCheckBox checkBox = new CusCheckBox("拒绝");
checkBox.setUseCheckMark(false);
checkBox.setSelectedBackground(Color.decode("#F56C6C"));
panel.add(checkBox);

6.6 禁用状态

CusCheckBox checkBox = new CusCheckBox("不可选");
checkBox.setEnabled(false);
panel.add(checkBox);

6.7 监听选中事件

CusCheckBox checkBox = new CusCheckBox("接收通知");
checkBox.addItemListener(e -> {
    boolean selected = e.getStateChange() == ItemEvent.SELECTED;
    System.out.println("选中状态:" + selected);
});

七、注意事项

在实际使用中,有几个细节需要留意:

  • 图标共用:选中和未选中的状态,用的是同一个CheckBoxIcon实例。它内部通过ButtonModel.isSelected()来判断当前该画什么,这是一种高效的设计。
  • 透明背景:代码中通过setOpaque(false)和setContentAreaFilled(false)确保了组件背景透明,这样它就能自然地“贴”在父容器上,不会遮挡背景。
  • 字体兼容性:示例中字体设置为“Microsoft YaHei”,这在Windows上没问题。如果你的应用要跨平台,记得替换成更通用的字体,比如“DejaVu Sans”。
  • 默认主题:默认的主题色#409EFF是参考了Element UI的风格,你可以根据自己项目的设计规范进行调整。
  • 尺寸下限:图标尺寸被限制为最小16px,这是为了保证良好的可交互性,避免用户点不到。

八、小结

总的来说,CusCheckBox通过自定义Icon接口,成功绕开了Swing原生样式的限制,实现了高度可控的复选框组件。它的核心思路非常清晰:

  • 实现Icon接口,在paintIcon方法里自己画。
  • 根据按钮的各种状态(选中、悬停、禁用、按下)来动态改变绘制内容。
  • 通过丰富的构造函数和setter方法,把配置的灵活性的交给使用者。

这种“自绘图标”的思路其实是一种通用解法,完全可以举一反三,应用到其他需要自定义样式的Swing组件上,比如单选框(RadioButton)、开关(ToggleButton)等等。掌握了它,就等于掌握了Swing界面定制化的一把钥匙。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发
相关文章 更多
Java Swing家庭收支管理
Java Swing家庭收支管理

基于JavaSwing和MySQL构建的家庭收支管理工具,功能简洁清晰,支持收入与支出记录及类别管理。通过Eclipse导入项目,配置JDBC连接参数,导入SQL文件建立数据库,运行后即可登录使用。适合Java初学者练习桌面应用开发与数据库交互。

JavaSwing实现自定义TablePanel组件(附完整代码)
JavaSwing实现自定义TablePanel组件(附完整代码)

一、背景 前面两篇分别介绍了 CusTable 和表格的渲染器/编辑器机制,但实际项目中,表格通常不是孤立存在的,还需要配合: 查询条件面板(搜索框、下拉框、日期选择器等) 工具栏(新增、删除、导出等操作按钮) 分页组件 每次写一个表格页面都要重复搭建这些组件,代码冗余且容易出错。 TablePan

如何确保 Swing 中 JPanel 的自绘图形完整可见
如何确保 Swing 中 JPanel 的自绘图形完整可见

在Swing中,JPanel自绘图形被裁剪的根本原因是布局管理器依据getPreferredSize()分配空间,而默认尺寸过小,通常为零。解决方法是重写getPreferredSize()返回所需尺寸,并同步调整getMinimumSize(),确保自定义绘制内容完整可见。此外,还需注意在paintComponent中正确绘制。

JavaSwing实现自定义可搜索下拉框(附完整代码)
JavaSwing实现自定义可搜索下拉框(附完整代码)

一种基于JavaSwing的可搜索下拉框CusComboBox,通过继承JComboBox并启用可编辑模式,实现输入关键字动态过滤选项、键盘导航(上下键、回车、ESC)及无匹配回调,同时加入200ms防抖延迟和中文输入状态处理,优化搜索性能与用户体验。

如何在Notepad++中配置Java Swing界面的运行环境
如何在Notepad++中配置Java Swing界面的运行环境

如何在Notepad++中配置Ja va Swing界面的运行环境 先说一个核心事实:Notepad++本身只是个出色的文本编辑器,它并不提供Ja va的编译与运行环境。想在里面跑起Swing程序,本质上还是得依赖系统里已经装好的JDK,然后通过外部工具(比如nppexec插件)去调用ja vac和

提升Java GUI技能:掌握高级技术,打造卓越的界面
提升Java GUI技能:掌握高级技术,打造卓越的界面

1.深入定制组件外观1.1自定义组件外观使用Swing的“外观”功能,可以轻松地更改组件的外观,而无需重新编码。提供了多种预定义的外观,如Nimbus、Metal、Motif等等,只需几行代码即可应用外观。如果需要更高级的定制,可以通过创建自定义外观来实现。1.2调整组件大小和布局通过调整组件的大小和布局,可以创建更具吸引力和易用性的GUI。可以使用BorderLayout、GridLayout、FlowLayout等布局管理器来安排组件,也可以使用自定义布局来实现更复杂的布局。1.3创建自定义组件如果现

swing布局嵌套的例子
swing布局嵌套的例子

嵌套的Swing布局示例Swing是一个非常流行的Java界面开发工具包,它提供了一系列的布局管理器,用于在图形用户界面中设计和构建组件的布局。本文将介绍一个使用Swing布局管理器进行嵌套布局的示例。在Swing中,可以使用多种布局管理器来实现不同的布局效果,例如BorderLayout、FlowLayout、GridLayout等。

怎么使用java+io+swing实现学生信息管理系统
怎么使用java+io+swing实现学生信息管理系统

说明:1.开发环境基于eclipse外加windowbuilder插件。2.采用io流持续储存文件到本地磁盘。3.Arrylist对文件信息进行操作。一、界面展示本地储存学生信息的txt文件,可在此对学生信息增删改查但需要注意格式。二、项目构架三、相关代码及介绍1.IO部分学生实体类packagestuManager;publicclassStuInfo{privateintstuId;//学号privateStringstuName;//姓名privateintstuAge;//年龄privateStr

java swing怎么实现简单计算器界面
java swing怎么实现简单计算器界面

运用到的知识:1.常用顶层容器JFrame类的使用2.常用中间容器JPanel类的使用3.单行文本框的实现类JTextField类的使用4.按钮的实现类JButton类的使用5.边框布局管理器的使用6.网格布局管理器的使用基本思路:1.创建1个窗口f12.创建1个文本框t13.创建内层面板p3,保存文本框t14.创建16个按钮5.创建内层面板p2,设置为网格布局,用于保存16个按钮6.创建外层面板p1,设置为边框布局,北部保存p3,中部保存p2下面是是具体的代码实现,可以直接运行importjavax.s

怎么用Java+swing实现抖音上的表白程序
怎么用Java+swing实现抖音上的表白程序

1.准备工作a.需要下载一个带着swing插件的eclipseb.需要配置好JDKc.创建一个JFrame的项目(如下图所示的步骤)d.把资源文件放入与src所在的那个目录步骤如下:1.先复制资源文件2.粘贴文件3.把jar文件放入ReferencedLibraries文件夹下这第3步的具体操作如何所示那么如何判断添加是否成功呢?解答:看ReferencedLibraries下面是否出现了刚刚buildpath的两个文件,若出现了,则代表添加成功(成功的视图如下所示:)e.design界面和source界

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程
PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
Postman macOS版
Postman macOS版
Mac

Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。

Docker Desktop macOS版
Docker Desktop macOS版
Mac

Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。

Android Studio macOS版
Android Studio macOS版
Mac

Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

WINDOWS 更多
Postman Windows版
Postman Windows版
Windows

Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等

Docker Desktop Windows版
Docker Desktop Windows版
Windows

Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。

Android Studio Windows版
Android Studio Windows版
Windows

Android Studio 是 Google 面向 Android 应用开发提供的官方集成开发环境,以 IntelliJ IDEA 为基础,集成智能代码编辑、Gradle 构建、设备模拟、界面预览、调试测试及性能分析工具,