Java?Swing自定義復(fù)選框CusCheckBox組件(附源碼)
一、背景
Swing 原生 JCheckBox 的復(fù)選框圖標(biāo)是系統(tǒng)默認(rèn)樣式,不同操作系統(tǒng)下風(fēng)格不一致,且無(wú)法自定義圓角、顏色、懸停效果等。 要實(shí)現(xiàn)統(tǒng)一的復(fù)選框樣式,需要自己繪制圖標(biāo)。CusCheckBox 通過(guò)實(shí)現(xiàn) Icon 接口自定義復(fù)選框的繪制邏輯,支持圓角、自定義顏色、懸停效果、禁用狀態(tài)等。
二、核心設(shè)計(jì)
CusCheckBox 由兩個(gè)類組成:
- CheckBoxIcon:實(shí)現(xiàn) Icon 接口,負(fù)責(zé)繪制復(fù)選框圖標(biāo)(背景、邊框、對(duì)勾/叉號(hào))
- CusCheckBox:繼承 JCheckBox,使用 CheckBoxIcon 作為圖標(biāo),提供豐富的樣式設(shè)置方法
三、CheckBoxIcon 源碼
import lombok.Setter;
import javax.swing.*;
import java.awt.*;
/**
* 自定義 JCheckBox 圖標(biāo)類
* 實(shí)現(xiàn) Icon 接口,負(fù)責(zé)繪制復(fù)選框的圖標(biāo)部分
*
* 使用示例:
* CheckBoxIcon icon = new CheckBoxIcon(20, Color.decode("#409EFF"), Color.WHITE);
*/
@Setter
public class CheckBoxIcon implements Icon {
/** 復(fù)選框大小 */
private int size;
/** 圓角 */
private boolean rounded = true;
/** 圓角半徑 */
private int borderRadius = 8;
/** 邊框?qū)挾?*/
private int borderThickness = 1;
/** 邊框顏色 */
private Color borderColor = Color.GRAY;
/** 選中背景顏色 */
private Color selectedBg;
/** 對(duì)勾顏色 */
private Color checkColor;
/** 懸停顏色 */
private Color hoverColor;
/** 禁用顏色 */
private Color disabledColor = Color.decode("#E4E7ED");
/** 對(duì)勾寬度 */
private float checkThickness = 2.0f;
/** 是否使用對(duì)勾(true=對(duì)勾,false=叉號(hào)) */
private boolean useCheckMark = true;
/** 是否啟用 */
private boolean enabled = true;
/**
* 構(gòu)造函數(shù)
* @param size 圖標(biāo)尺寸
* @param selectedBg 選中時(shí)的背景色
* @param checkColor 對(duì)勾顏色
*/
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);
// 獲取狀態(tài)
boolean isSelected = model.isSelected();
boolean isPressed = model.isPressed();
boolean isRollover = model.isRollover();
// 計(jì)算實(shí)際繪制區(qū)域
int drawWidth = size - 1;
int drawHeight = size - 1;
// 根據(jù)狀態(tài)選擇顏色
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);
}
// 繪制選中標(biāo)記
if (isSelected) {
drawCheckMark(g2, x, y, drawWidth, drawHeight);
}
}
/**
* 繪制選中標(biāo)記(對(duì)勾或叉號(hào))
* @param g2 Graphics2D 對(duì)象
* @param x 起始 X 坐標(biāo)
* @param y 起始 Y 坐標(biāo)
* @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% 內(nèi)邊距
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) {
// 對(duì)勾
g2.drawLine(startX, startY, midX, midY);
g2.drawLine(midX, midY, endX, endY);
} else {
// 叉號(hào)
g2.drawLine(startX, startY, endX, endY);
g2.drawLine(startX, endY, endX, startY);
}
}
@Override
public int getIconWidth() {
return size;
}
@Override
public int getIconHeight() {
return size;
}
/**
* 設(shè)置圖標(biāo)尺寸
* @param size 尺寸
*/
public void setSize(int size) {
this.size = Math.max(16, size);
}
}
四、CusCheckBox 源碼
import javax.swing.*;
import java.awt.*;
/**
* 自定義復(fù)選框
* 通過(guò)自定義 Icon 實(shí)現(xiàn)統(tǒng)一的復(fù)選框樣式
*
* 使用示例:
* CusCheckBox checkBox = new CusCheckBox("同意協(xié)議");
* checkBox.setSelected(true);
* checkBox.setHoverColor(Color.LIGHT_GRAY);
*/
public class CusCheckBox extends JCheckBox {
/** 默認(rèn)尺寸 */
private static final int DEFAULT_SIZE = 20;
/** 默認(rèn)選中背景顏色 */
private static final Color DEFAULT_BG = Color.decode("#409EFF");
/** 默認(rèn)選中對(duì)勾顏色 */
private static final Color DEFAULT_CHECK = Color.WHITE;
/** 內(nèi)部圖標(biāo)實(shí)例 */
private final CheckBoxIcon icon;
/**
* 默認(rèn)構(gòu)造函數(shù)
* @param text 復(fù)選框文本
*/
public CusCheckBox(String text) {
this(text, DEFAULT_SIZE, DEFAULT_BG, DEFAULT_CHECK, false);
}
/**
* 指定選中狀態(tài)
* @param text 復(fù)選框文本
* @param selected 是否選中
*/
public CusCheckBox(String text, boolean selected) {
this(text, DEFAULT_SIZE, DEFAULT_BG, DEFAULT_CHECK, selected);
}
/**
* 指定尺寸
* @param text 復(fù)選框文本
* @param size 圖標(biāo)尺寸
*/
public CusCheckBox(String text, int size) {
this(text, size, DEFAULT_BG, DEFAULT_CHECK, false);
}
/**
* 指定尺寸和選中狀態(tài)
* @param text 復(fù)選框文本
* @param size 圖標(biāo)尺寸
* @param selected 是否選中
*/
public CusCheckBox(String text, int size, boolean selected) {
this(text, size, DEFAULT_BG, DEFAULT_CHECK, selected);
}
/**
* 指定顏色
* @param text 復(fù)選框文本
* @param bg 選中時(shí)背景色
* @param check 對(duì)勾顏色
*/
public CusCheckBox(String text, Color bg, Color check) {
this(text, DEFAULT_SIZE, bg, check, false);
}
/**
* 指定顏色和選中狀態(tài)
* @param text 復(fù)選框文本
* @param bg 選中時(shí)背景色
* @param check 對(duì)勾顏色
* @param selected 是否選中
*/
public CusCheckBox(String text, Color bg, Color check, boolean selected) {
this(text, DEFAULT_SIZE, bg, check, selected);
}
/**
* 指定尺寸和顏色
* @param text 復(fù)選框文本
* @param size 圖標(biāo)尺寸
* @param bg 選中時(shí)背景色
* @param check 對(duì)勾顏色
*/
public CusCheckBox(String text, int size, Color bg, Color check) {
this(text, size, bg, check, false);
}
/**
* 完整構(gòu)造函數(shù)
* @param text 復(fù)選框文本
* @param size 圖標(biāo)尺寸
* @param bg 選中時(shí)背景色
* @param check 對(duì)勾顏色
* @param selected 是否選中
*/
public CusCheckBox(String text, int size, Color bg, Color check, boolean selected) {
super(text);
// 創(chuàng)建自定義圖標(biāo)
this.icon = new CheckBoxIcon(size, bg, check);
// 設(shè)置圖標(biāo)(選中和未選中共用同一個(gè)圖標(biāo)實(shí)例,通過(guò)狀態(tài)區(qū)分繪制)
this.setIcon(icon);
this.setSelectedIcon(icon);
// 設(shè)置選中狀態(tài)
this.setSelected(selected);
// 設(shè)置文本顏色和字體
this.setForeground(Color.BLACK);
this.setFont(new Font("Microsoft YaHei", Font.PLAIN, 16));
// 設(shè)置透明背景,讓父容器背景顯示
this.setOpaque(false);
// 禁用默認(rèn)內(nèi)容區(qū)域填充
this.setContentAreaFilled(false);
// 禁用邊框繪制
this.setBorderPainted(false);
// 圖標(biāo)與文字間距
this.setIconTextGap(10);
}
/**
* 獲取自定義圖標(biāo)
* @return 圖標(biāo)對(duì)象
*/
@Override
public CheckBoxIcon getIcon() {
return icon;
}
/**
* 設(shè)置圖標(biāo)尺寸
* @param size 尺寸
*/
public void setIconSize(int size) {
icon.setSize(size);
revalidate();
repaint();
}
/**
* 設(shè)置選中時(shí)的背景色
* @param color 顏色
*/
public void setSelectedBackground(Color color) {
icon.setSelectedBg(color);
repaint();
}
/**
* 設(shè)置對(duì)勾顏色
* @param color 顏色
*/
public void setCheckColor(Color color) {
icon.setCheckColor(color);
repaint();
}
/**
* 設(shè)置邊框顏色
* @param color 顏色
*/
public void setBorderColor(Color color) {
icon.setBorderColor(color);
repaint();
}
/**
* 設(shè)置是否圓角
* @param rounded 是否圓角
*/
public void setRounded(boolean rounded) {
icon.setRounded(rounded);
repaint();
}
/**
* 設(shè)置圓角半徑
* @param radius 半徑
*/
public void setBorderRadius(int radius) {
icon.setRounded(true);
icon.setBorderRadius(radius);
repaint();
}
/**
* 設(shè)置邊框粗細(xì)
* @param thickness 粗細(xì)
*/
public void setBorderThickness(int thickness) {
icon.setBorderThickness(thickness);
repaint();
}
/**
* 設(shè)置對(duì)勾線條粗細(xì)
* @param thickness 粗細(xì)
*/
public void setCheckThickness(float thickness) {
icon.setCheckThickness(thickness);
repaint();
}
/**
* 設(shè)置使用對(duì)勾還是叉號(hào)
* @param useCheckMark true=對(duì)勾,false=叉號(hào)
*/
public void setUseCheckMark(boolean useCheckMark) {
icon.setUseCheckMark(useCheckMark);
repaint();
}
/**
* 設(shè)置懸停時(shí)的背景色
* @param color 顏色
*/
public void setHoverColor(Color color) {
icon.setHoverColor(color);
repaint();
}
/**
* 重寫 setEnabled 以同步圖標(biāo)狀態(tài)
* @param enabled 是否啟用
*/
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (icon != null) {
icon.setEnabled(enabled);
repaint();
}
}
}
五、核心功能說(shuō)明
圖標(biāo)繪制(CheckBoxIcon):
- paintIcon:核心繪制方法,根據(jù)按鈕狀態(tài)(選中/懸停/按下/禁用)繪制不同樣式
- drawCheckMark:繪制對(duì)勾或叉號(hào),支持線條粗細(xì)和顏色定制
- 支持圓角/直角、邊框顏色/粗細(xì)、背景色、懸停色、禁用色等配置
復(fù)選框封裝(CusCheckBox):
- 使用 CheckBoxIcon 替換原生圖標(biāo)
- 提供多個(gè)構(gòu)造函數(shù)簡(jiǎn)化使用(尺寸/顏色/選中狀態(tài)組合)
- 提供樣式設(shè)置方法(圓角、顏色、懸停、對(duì)勾樣式等)
- 透明背景,便于融入父容器
六、使用示例
6.1 基本用法
CusCheckBox checkBox = new CusCheckBox("同意用戶協(xié)議");
panel.add(checkBox);
6.2 指定選中狀態(tài)
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 圓角半徑調(diào)整
CusCheckBox checkBox = new CusCheckBox("圓角復(fù)選框");
checkBox.setBorderRadius(12);
panel.add(checkBox);
6.5 使用叉號(hào)代替對(duì)勾
CusCheckBox checkBox = new CusCheckBox("拒絕");
checkBox.setUseCheckMark(false);
checkBox.setSelectedBackground(Color.decode("#F56C6C"));
panel.add(checkBox);
6.6 禁用狀態(tài)
CusCheckBox checkBox = new CusCheckBox("不可選");
checkBox.setEnabled(false);
panel.add(checkBox);
6.7 監(jiān)聽(tīng)選中事件
CusCheckBox checkBox = new CusCheckBox("接收通知");
checkBox.addItemListener(e -> {
boolean selected = e.getStateChange() == ItemEvent.SELECTED;
System.out.println("選中狀態(tài):" + selected);
});
七、注意事項(xiàng)
- con 共用:選中和未選中共用同一個(gè) CheckBoxIcon 實(shí)例,通過(guò) ButtonModel.isSelected() 區(qū)分繪制狀態(tài)
- 透明背景:setOpaque(false) 和 setContentAreaFilled(false) 確保背景不覆蓋父容器
- 字體設(shè)置:代碼中使用 Microsoft YaHei,非 Windows 系統(tǒng)需替換為 DejaVu Sans 或 Serif
- 顏色默認(rèn)值:默認(rèn)主題色為 #409EFF(Element UI 風(fēng)格),可根據(jù)項(xiàng)目調(diào)整
- 圖標(biāo)尺寸:最小值限制為 16px,避免過(guò)小無(wú)法交互
八、小結(jié)
CusCheckBox 通過(guò)自定義 Icon 實(shí)現(xiàn)了樣式統(tǒng)一的復(fù)選框組件。核心思路是:
- 實(shí)現(xiàn) Icon 接口,重寫 paintIcon 方法自繪圖標(biāo)
- 根據(jù)按鈕狀態(tài)(選中/懸停/禁用/按下)繪制不同樣式
- 通過(guò)多個(gè)構(gòu)造函數(shù)和 setter 方法提供靈活配置
這種實(shí)現(xiàn)方式可以推廣到其他自定義組件(如單選框、開(kāi)關(guān)等)。
以上就是Java Swing自定義復(fù)選框CusCheckBox組件(附源碼)的詳細(xì)內(nèi)容,更多關(guān)于Java Swing自定義復(fù)選框的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中HttpServletRequestWrapper的使用與原理詳解
這篇文章主要介紹了Java中HttpServletRequestWrapper的使用與原理詳解,HttpServletRequestWrapper 實(shí)現(xiàn)了 HttpServletRequest 接口,可以讓開(kāi)發(fā)人員很方便的改造發(fā)送給 Servlet 的請(qǐng)求,需要的朋友可以參考下2024-01-01
Spring中@RequestMapping、@RestController和Postman
本文介紹了Spring框架中常用的@RequestMapping和@RestController注解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10
Spring Boot中使用Actuator的/info端點(diǎn)輸出Git版本信息
這篇文章主要介紹了Spring Boot中使用Actuator的/info端點(diǎn)輸出Git版本信息,需要的朋友可以參考下2017-06-06
Java實(shí)現(xiàn)簡(jiǎn)單日歷小程序 Java圖形界面小日歷開(kāi)發(fā)
這篇文章主要介紹了Java實(shí)現(xiàn)簡(jiǎn)單日歷小程序,如何用Java swing開(kāi)發(fā)一款簡(jiǎn)單的小日歷,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02
spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理理解
這篇文章主要為大家詳細(xì)介紹了spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
Maven Profile中的資源過(guò)濾與屬性管理詳解
在持續(xù)交付體系下,軟件需要面向開(kāi)發(fā)、測(cè)試、預(yù)發(fā)布、生產(chǎn)等多個(gè)環(huán)境進(jìn)行差異化配置,Maven作為Java生態(tài)的核心構(gòu)建工具,其Profile機(jī)制配合資源過(guò)濾功能,為多環(huán)境構(gòu)建提供了優(yōu)雅的解決方案,本文深入解析如何通過(guò)<resources>與<filters>的聯(lián)動(dòng)實(shí)現(xiàn)環(huán)境隔離2025-05-05
idea項(xiàng)目實(shí)現(xiàn)移除和添加git
本文指導(dǎo)讀者如何從官網(wǎng)下載并安裝Git,以及在IDEA中配置Git的詳細(xì)步驟,首先,用戶需訪問(wèn)Git官方網(wǎng)站下載適合自己操作系統(tǒng)的Git版本并完成安裝,接著,在IDEA中通過(guò)設(shè)置找到git.exe文件以配置Gi2024-10-10
Struts2學(xué)習(xí)教程之入門小白的開(kāi)始基礎(chǔ)
struts2其實(shí)就是為我們封裝了servlet,簡(jiǎn)化了jsp跳轉(zhuǎn)的復(fù)雜操作,并且提供了易于編寫的標(biāo)簽,可以快速開(kāi)發(fā)view層的代碼。下面這篇文章主要給各位想要學(xué)習(xí)Struts2的小白們?cè)敿?xì)介紹了關(guān)于Struts2入門的一些開(kāi)始基礎(chǔ),需要的朋友可以參考下2018-04-04
Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說(shuō)明
這篇文章主要介紹了Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

