当前位置:首页 > 人生 > 作品墙 > 正文内容

CheckBox 多选框控件调用文档

作品墙2小时前


命名空间:CConUI
继承:System.Windows.Forms.Control
可见性:public class CheckBox
默认尺寸:130 × 20
默认事件:CheckedChanged(设计器双击控件即生成该事件处理器)
定位:自绘多选框——左侧圆角方框 + 勾号/复选方块 + 右侧文字;支持深色模式配色、三态复选(未选 / 选中 / 复选),自动响应鼠标悬停与按下状态。


一、作用

完全自绘的多选框控件,具备以下特性:

  • 二态模式(默认):点击在 [未选] ↔ [选中] 之间切换;

  • 三态模式:ThreeState = true 时按 [未选] → [选中] → [复选] → [未选] 循环;

  • 自绘外观:圆角方框 + 白色勾号 / 内部实心方块 + 右侧文字;

  • 状态配色:边框有 常态 / 悬停 / 按下 三态颜色;选中 / 复选时边框与填充自动使用 CheckedColor;

  • 尺寸自适应:方框边长 = Height - BoxPadding × 2,高度决定方框大小;

  • 透明背景:启用 SupportsTransparentBackColor,背景由父容器透出;

  • 文字:方框右侧偏移 6px 绘制 Text,ForeColor / Font 可控,超长自动省略号。

三种状态视觉对照

状态外框内部边框色
未选圆角方框,镂空无按悬停 / 按下 / 常态取色
选中(Checked=true)圆角方框,实心填充 CheckedColor白色勾号 ✓CheckedColor(忽略悬停/按下)
复选(Indeterminate=true,需 ThreeState=true)圆角方框,镂空内部实心小方块(CheckedColor)按悬停 / 按下 / 常态取色

二、快速上手

using System.Drawing;
using System.Windows.Forms;
using CConUI;

// 1. 创建控件
var cb = new CheckBox();

// 2. 放入容器
cb.Parent = panel1;
cb.Location = new Point(20, 20);
cb.Text = "同意用户协议";

// 3. 订阅状态变化
cb.CheckedChanged += (s, e) =>
{
    var c = (CheckBox)s;
    Console.WriteLine(c.Text + " → Checked=" + c.Checked + ",Indeterminate=" + c.Indeterminate);
};

// 4. 外观自定义(可选)
cb.CheckedColor    = Color.FromArgb(88, 166, 255);
cb.BorderColor     = Color.FromArgb(139, 148, 158);
cb.HoverColor      = Color.FromArgb(173, 186, 199);
cb.PressedColor    = Color.FromArgb(88, 166, 255);
cb.CornerRadius    = 3f;
cb.BorderThickness = 2f;
cb.BoxPadding      = 0;
cb.ForeColor       = Color.White;
cb.Font            = new Font("Microsoft YaHei", 9F);

// 5. 开启三态(可选)
cb.ThreeState = true;

三、构造函数

public CheckBox()

项目说明
参数无
作用初始化自绘多选框
实际行为① 启用 UserPaint | AllPaintingInWmPaint | OptimizedDoubleBuffer | ResizeRedraw | SupportsTransparentBackColor 样式;
② 设置 BackColor = Color.Transparent;
③ 设置 Size = (130, 20);
④ 设置 ForeColor = Color.FromArgb(238, 238, 238);
⑤ 设置 Cursor = Cursors.Hand
默认尺寸130 × 20
默认状态Checked = false、Indeterminate = false、ThreeState = false
默认外观CornerRadius = 3f、BorderThickness = 2f、BoxPadding = 0、InnerBoxPadding = 3f
var cb = new CheckBox
{
    Parent = panel1,
    Text = "选项 A"
};

四、公开属性

4.1 状态属性

public bool Checked

项目说明
类型bool
默认false
CategoryCCon
DefaultValuefalse
作用控件的选中状态
副作用(值有变化时)① 新值为 true 时自动把 Indeterminate 置为 false(互斥);
② 触发 CheckedChanging(Checked 仍为旧值);
③ 写入新值;
④ 触发 CheckedChanged;
⑤ Invalidate() 重绘
幂等赋相同值直接返回,不触发事件、不重绘
cb.Checked = true;    // 触发 CheckedChanging + CheckedChanged
cb.Checked = true;    // 相同值,不触发
cb.Checked = false;   // 触发事件

public bool Indeterminate

项目说明
类型bool
默认false
CategoryCCon
DefaultValuefalse
作用复选(半选)状态,视觉上表现为外框镂空 + 内部实心小方块
约束只在 ThreeState = true 时有效:
若 ThreeState = false 且试图设为 true,静默忽略(保持原值,不抛异常,不触发事件)
副作用(值有变化时)① 新值为 true 时自动把 Checked 置为 false(互斥);
② 触发 CheckedChanging;
③ 写入新值;
④ 触发 CheckedChanged;
⑤ Invalidate() 重绘
幂等赋相同值直接返回
cb.ThreeState = true;
cb.Indeterminate = true;    // OK
cb.ThreeState = false;
cb.Indeterminate = true;    // 无效(静默忽略)

public bool ThreeState

项目说明
类型bool
默认false
CategoryCCon
DefaultValuefalse
作用是否开启三态复选模式:
false → 二态:未选 ↔ 选中;
true → 三态循环:未选 → 选中 → 复选 → 未选
副作用① 赋值后 Invalidate();
② 由 true 改 false 且当前 Indeterminate = true 时,会主动调用 Indeterminate = false(触发相关事件)
幂等赋相同值直接返回
cb.ThreeState = true;    // 开启三态
cb.ThreeState = false;   // 关闭三态,若当前是复选则自动回到未选

4.2 尺寸与形状属性

public int BoxPadding

项目说明
类型int(像素)
默认0
CategoryCCon
DefaultValue0
作用方框与控件上下边缘之间的内边距:
0 → 方框边长 = 控件高度;
> 0 → 方框边长 = Height - BoxPadding × 2
取值范围Math.Max(0, value)——不能为负
副作用赋值后 Invalidate() 重绘
cb.BoxPadding = 0;   // 方框紧贴上下边缘(默认)
cb.BoxPadding = 2;   // 方框边长 = 高度 - 4

public float CornerRadius

项目说明
类型float(像素)
默认3f
CategoryCCon
DefaultValue3f
作用方框的圆角半径。0 为直角,值越大越圆
取值范围Math.Max(0f, value)——不能为负
绘制保护内部限制为 min(radius, min(width, height) / 2),保证圆角不超出方框
cb.CornerRadius = 0f;    // 直角
cb.CornerRadius = 3f;    // 默认
cb.CornerRadius = 8f;    // 大圆角

public float BorderThickness

项目说明
类型float(像素)
默认2f
CategoryCCon
DefaultValue2f
作用方框边框的线宽
取值范围Math.Max(0.5f, value)——最小 0.5f
绘制处理绘制前 boxRect 向内缩 BorderThickness / 2,避免画笔居中描边时超出外接矩形
cb.BorderThickness = 2f;
cb.BorderThickness = 1f;    // 更细
cb.BorderThickness = 4f;    // 更粗

public float InnerBoxPadding

项目说明
类型float(像素)
默认3f(字段初值;DefaultValue 标注为 2f,见注意事项)
CategoryCCon
DefaultValue2f(属性特性标注)
作用复选状态下内部小实心方块距离外框边缘的内边距。数值越小内部方块越大
取值范围Math.Max(0f, value)——不能为负
绘制保护内部方块边长 = boxRect.Width - InnerBoxPadding × 2;≤0 时不绘制内部方块
cb.ThreeState = true;
cb.Indeterminate = true;
cb.InnerBoxPadding = 3f;   // 默认
cb.InnerBoxPadding = 1f;   // 内部方块更大
cb.InnerBoxPadding = 6f;   // 内部方块更小

4.3 颜色属性

public Color BorderColor

项目说明
类型Color
默认Color.FromArgb(139, 148, 158)(中灰)
CategoryCCon
作用未选 / 复选状态下、常态(未悬停、未按下)的边框颜色

public Color CheckedColor

项目说明
类型Color
默认Color.FromArgb(88, 166, 255)(亮蓝)
CategoryCCon
作用选中时的外框填充色和边框色,以及复选时内部小方块的颜色

public Color HoverColor

项目说明
类型Color
默认Color.FromArgb(173, 186, 199)(浅灰)
CategoryCCon
作用未选 / 复选状态下、鼠标悬停时的边框颜色

public Color PressedColor

项目说明
类型Color
默认Color.FromArgb(88, 166, 255)(亮蓝)
CategoryCCon
作用未选 / 复选状态下、鼠标按下时的边框颜色
cb.BorderColor  = Color.FromArgb(139, 148, 158);
cb.CheckedColor = Color.FromArgb(88, 166, 255);
cb.HoverColor   = Color.FromArgb(173, 186, 199);
cb.PressedColor = Color.FromArgb(88, 166, 255);

4.4 重写的外观属性

public override string Text

项目说明
类型string
CategoryCCon
作用方框右侧显示的文字;空串时不绘制
副作用赋值后 Invalidate()
绘制起始 X = 方框右边缘(含 padding)+ 6px;LineAlignment = Center 垂直居中;超长自动省略号

public override Color ForeColor

项目说明
类型Color
默认Color.FromArgb(238, 238, 238)(浅白)
CategoryCCon
作用文字颜色

public override Font Font

项目说明
类型Font
CategoryCCon
作用文字字体

五、公开事件

public event EventHandler CheckedChanged

项目说明
参数EventHandler:sender 为当前 CheckBox,e 为 EventArgs.Empty
CategoryCCon
默认事件是([DefaultEvent("CheckedChanged")])——设计器双击即生成
触发时机Checked 或 Indeterminate 状态改变后触发
不触发情况① 赋相同值;② Indeterminate 在 ThreeState = false 下被设置(静默忽略)
触发顺序CheckedChanging → 更新状态 → CheckedChanged

public event EventHandler CheckedChanging

项目说明
参数EventHandler
CategoryCCon
触发时机Checked 或 Indeterminate 状态即将改变前——此时两个属性仍是旧值
不触发情况与 CheckedChanged 相同
用途记录切换前的状态;EventArgs 为空,不支持取消
bool _oldChecked = false;
bool _oldIndeterminate = false;

cb.CheckedChanging += (s, e) =>
{
    var c = (CheckBox)s;
    _oldChecked = c.Checked;
    _oldIndeterminate = c.Indeterminate;
    Console.WriteLine("即将改变:旧状态 Checked=" + _oldChecked + ",Indeterminate=" + _oldIndeterminate);
};

cb.CheckedChanged += (s, e) =>
{
    var c = (CheckBox)s;
    Console.WriteLine("已改变:新状态 Checked=" + c.Checked + ",Indeterminate=" + c.Indeterminate);
};

六、公开方法

CheckBox 没有新增 public 方法。所有公开方法继承自 Control(如 Invalidate()、Focus()、BringToFront() 等)。

内部重写方法(protected override,外部不可直接调用)

方法可见性作用
OnPaint(PaintEventArgs e)protected override绘制:外框 → 勾号 / 内部方块 → 文字
OnMouseEnter(EventArgs e)protected override设置 _isHover = true 并重绘
OnMouseLeave(EventArgs e)protected override清除悬停与按下状态并重绘
OnMouseDown(MouseEventArgs e)protected override左键按下时设置 _isPressed = true 并重绘
OnMouseUp(MouseEventArgs e)protected override左键抬起时根据 ThreeState 循环切换状态
GetRoundedRectPath(RectangleF, float)private生成圆角矩形路径的辅助方法

七、公开成员速查表

成员来源类型说明
CheckBox()本类构造函数默认尺寸 130×20,透明背景,手型光标
Checked本类属性(bool)选中状态;设为 true 时自动清空 Indeterminate
Indeterminate本类属性(bool)复选状态(仅 ThreeState=true 时有效);设为 true 时自动清空 Checked
ThreeState本类属性(bool)是否三态;关闭时若处于复选会重置为未选
BoxPadding本类属性(int)方框距控件上下边缘的内边距(默认 0)
CornerRadius本类属性(float)方框圆角半径(默认 3f)
BorderThickness本类属性(float)方框边框粗细(默认 2f,≥0.5f)
InnerBoxPadding本类属性(float)复选内部小方块的内边距(默认 3f,≥0)
BorderColor本类属性(Color)常态边框颜色
CheckedColor本类属性(Color)选中填充 / 边框 / 复选方块颜色
HoverColor本类属性(Color)悬停边框颜色
PressedColor本类属性(Color)按下边框颜色
Text(重写)Control属性(string)方框右侧文字
ForeColor(重写)Control属性(Color)文字颜色
Font(重写)Control属性(Font)文字字体
BackColorControl属性(Color)默认 Transparent;本类绘制不使用它,背景由父容器透出
Size / ClientSizeControl属性(Size)控件尺寸;高度决定方框大小
CursorControl属性默认 Hand(手型)
CheckedChanged本类事件(默认事件)状态改变后触发
CheckedChanging本类事件状态改变前触发(属性仍是旧值)
Invalidate()Control方法触发重绘
OnPaint(e)本类(override)方法(protected)绘制逻辑,外部不可直接调用
OnMouseEnter / OnMouseLeave / OnMouseDown / OnMouseUp本类(override)方法(protected)鼠标交互,外部不可直接调用

八、绘制原理(深入理解)

8.1 计算方框尺寸

float boxSize = this.Height - (this._boxPadding * 2f);
if (boxSize <= 4f) boxSize = 4f;

float boxX = this._boxPadding;
float boxY = (this.Height - boxSize) / 2f;

float halfThickness = this._borderThickness / 2f;
RectangleF boxRect = new RectangleF(
    boxX + halfThickness, boxY + halfThickness,
    boxSize - this._borderThickness, boxSize - this._borderThickness);
要点说明
boxSize = Height - BoxPadding × 2上下各留 BoxPadding,所以减去 × 2。
BoxPadding=0 时方框边长 = 控件高度,紧贴上下边缘
≤ 4f 兜底控件过小或 padding 过大时强制 4,避免 0 或负值
boxY = (Height - boxSize) / 2垂直居中
boxRect 内缩 halfThicknessPen 居中描边时外边缘会超出路径 BorderThickness / 2。内缩半个线宽后,方框外边缘正好贴到 boxSize 区域,不会被裁剪

8.2 决定边框颜色(优先级)

Color currentBorder;
if (this._isPressed)
    currentBorder = this._pressedColor;
else if (this._isHover)
    currentBorder = this._hoverColor;
else
    currentBorder = this._borderColor;

优先级:按下 > 悬停 > 常态。

8.3 绘制外框

using (var path = GetRoundedRectPath(boxRect, this._cornerRadius))
{
    if (this._checked)
    {
        using (var brush = new SolidBrush(this._checkedColor))
            g.FillPath(brush, path);      // 选中时填充
    }

    Color drawBorderColor = this._checked ? this._checkedColor : currentBorder;
    using (var pen = new Pen(drawBorderColor, this._borderThickness))
        g.DrawPath(pen, path);
}
状态填充边框色
Checked = trueCheckedColor 填充CheckedColor(忽略悬停 / 按下)
Indeterminate = true不填充(镂空)按悬停 / 按下 / 常态
未选不填充(镂空)按悬停 / 按下 / 常态

8.4 绘制勾号(选中时)

float cx1 = boxRect.X + boxRect.Width * 0.25f;
float cy1 = boxRect.Y + boxRect.Height * 0.50f;
float cx2 = boxRect.X + boxRect.Width * 0.45f;
float cy2 = boxRect.Y + boxRect.Height * 0.70f;
float cx3 = boxRect.X + boxRect.Width * 0.75f;
float cy3 = boxRect.Y + boxRect.Height * 0.30f;

float tickThickness = Math.Max(1.5f, boxSize * 0.12f);
using (var pen = new Pen(Color.White, tickThickness))
{
    pen.StartCap = LineCap.Round;
    pen.EndCap = LineCap.Round;
    pen.LineJoin = LineJoin.Round;
    g.DrawLines(pen, new PointF[] {
        new PointF(cx1, cy1),
        new PointF(cx2, cy2),
        new PointF(cx3, cy3)
    });
}
要点说明
三个点比例坐标(25%, 50%) → (45%, 70%) → (75%, 30%),形成标准 ✓ 形
tickThickness至少 1.5px,随方框大小按 12% 缩放,小方框也能看清
端点 / 连接样式Round:勾号两端和拐角圆润,视觉更顺滑
颜色固定白色;如需自定义可修改源码

8.5 绘制复选内部方块(Indeterminate=true 时)

float innerSize = boxRect.Width - (this._innerBoxPadding * 2f);
if (innerSize > 0)
{
    float innerX = boxRect.X + this._innerBoxPadding;
    float innerY = boxRect.Y + this._innerBoxPadding;
    RectangleF innerRect = new RectangleF(innerX, innerY, innerSize, innerSize);

    using (var brush = new SolidBrush(this._checkedColor))
        g.FillRectangle(brush, innerRect);
}
要点说明
innerSize = boxRect.Width - InnerBoxPadding × 2左右各留 InnerBoxPadding,所以减去 × 2
innerSize ≤ 0 保护内边距过大时不绘制内部方块(只剩外框,视觉上像未选)
颜色固定 CheckedColor
形状实心矩形(直角),与外框圆角形成视觉对比

8.6 绘制文字

float textX = boxX + boxSize + 6f;
RectangleF textRect = new RectangleF(textX, 0, this.Width - textX, this.Height);

using (var brush = new SolidBrush(this.ForeColor))
using (var sf = new StringFormat
{
    Alignment = StringAlignment.Near,
    LineAlignment = StringAlignment.Center,
    Trimming = StringTrimming.EllipsisCharacter
})
{
    g.DrawString(this.Text, this.Font, brush, textRect, sf);
}
要点说明
textX = boxX + boxSize + 6方框右边缘 + 6px 间距,避免文字贴边
LineAlignment = Center文字垂直居中于控件高度
Trimming = EllipsisCharacter文字过长时自动省略号
宽度计算Width - textX,即方框右侧到控件右边缘的剩余宽度

8.7 圆角路径生成

private GraphicsPath GetRoundedRectPath(RectangleF rect, float radius)
{
    var path = new GraphicsPath();
    float r = Math.Min(radius, Math.Min(rect.Width, rect.Height) / 2f);
    float d = r * 2f;

    if (r <= 0)
    {
        path.AddRectangle(rect);
        return path;
    }

    path.AddArc(rect.X, rect.Y, d, d, 180, 90);                     // 左上角
    path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);             // 右上角
    path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);      // 右下角
    path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);             // 左下角
    path.CloseFigure();
    return path;
}
要点说明
r = min(radius, min(width, height) / 2)圆角半径不能超过边长度的一半,否则 AddArc 会异常
四段圆弧左上 180→270、右上 270→360、右下 0→90、左下 90→180,组成圆角矩形
r ≤ 0直角时直接 AddRectangle

九、交互一览

操作效果
鼠标进入控件_isHover = true,边框变 HoverColor(选中时仍用 CheckedColor)
鼠标离开控件_isHover = false、_isPressed = false,边框恢复
左键按下_isPressed = true,边框变 PressedColor(选中时仍用 CheckedColor)
左键抬起(在控件内)按 ThreeState 循环切换状态
左键抬起(移出控件外)不切换,仅清除 _isPressed
右键 / 中键不响应
键盘未重写键盘处理:Space / Enter 不切换;如需键盘支持请自行扩展

状态循环(ThreeState = true 时)

当前状态点击后
未选(Checked=false, Indeterminate=false)选中(Checked=true)
选中(Checked=true)复选(Indeterminate=true)
复选(Indeterminate=true)未选(两属性均为 false)

十、完整使用示例

示例 1:基础二态多选框

using System.Drawing;
using System.Windows.Forms;
using CConUI;

var cb = new CheckBox
{
    Parent = panel1,
    Location = new Point(20, 20),
    Text = "同意用户协议",
    Checked = true
};

cb.CheckedChanged += (s, e) =>
{
    var c = (CheckBox)s;
    btnSubmit.Enabled = c.Checked;
};

示例 2:三态多选框(表格全选场景)

var cbAll = new CheckBox
{
    Parent = this,
    Location = new Point(20, 20),
    Text = "全选",
    ThreeState = true
};

// 表格行选中数变化时,更新 cbAll 的三态
void UpdateAllCheckBox(int checkedCount, int total)
{
    if (checkedCount == 0)
    {
        cbAll.Checked = false;
        cbAll.Indeterminate = false;   // 未选
    }
    else if (checkedCount == total)
    {
        cbAll.Checked = true;          // 选中(会自动清 Indeterminate)
    }
    else
    {
        cbAll.Indeterminate = true;    // 复选(会自动清 Checked)
    }
}

示例 3:深色主题外观

var cb = new CheckBox
{
    Parent = this,
    Location = new Point(20, 20),
    Text = "深色主题选项",
    ForeColor       = Color.White,
    BorderColor     = Color.FromArgb(90, 90, 95),
    HoverColor      = Color.FromArgb(140, 140, 150),
    PressedColor    = Color.FromArgb(0, 200, 255),
    CheckedColor    = Color.FromArgb(0, 200, 255),
    BorderThickness = 2f,
    CornerRadius    = 4f,
    BoxPadding      = 2
};

示例 4:大号复选框

var cb = new CheckBox
{
    Parent = this,
    Size = new Size(200, 28),
    Text = "大号复选框",
    BorderThickness = 2.5f,
    CornerRadius = 5f,
    BoxPadding = 2
    // 方框边长 = 28 - 2×2 = 24
};

示例 5:直角极简风格

var cb = new CheckBox
{
    Parent = this,
    Text = "极简风格",
    CornerRadius = 0f,
    BorderThickness = 1.5f,
    BoxPadding = 2,
    CheckedColor = Color.Black,
    BorderColor = Color.Gray,
    ForeColor = Color.Black
};

示例 6:用 CheckedChanging 记录状态,CheckedChanged 做业务

bool _wasChecked = false;

cb.CheckedChanging += (s, e) =>
{
    var c = (CheckBox)s;
    _wasChecked = c.Checked;
};

cb.CheckedChanged += (s, e) =>
{
    var c = (CheckBox)s;

    if (c.Checked && !_wasChecked)
    {
        Console.WriteLine("用户主动勾选");
    }
    else if (!c.Checked && _wasChecked)
    {
        Console.WriteLine("用户取消勾选");
    }
};

示例 7:三态循环手动测试

var cb = new CheckBox
{
    Parent = this,
    Location = new Point(20, 20),
    Text = "点击我循环 3 态",
    ThreeState = true
};

cb.CheckedChanged += (s, e) =>
{
    var c = (CheckBox)s;
    string state;
    if (c.Checked) state = "选中";
    else if (c.Indeterminate) state = "复选";
    else state = "未选";

    Console.WriteLine("当前状态:" + state);
};



转载请注明出处。

本文链接:http://www.pythonopen.com/?id=26

相关文章

已经实现的一些算法

编码CConA1是一种可复原的编码算法,用于将文本或字节转换为纯字母。可用于文件名混淆,避免因包含违...

横向滚动条HScrollBar 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control版本:基于所提供...

纵向滚动条VScrollBar 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control版本:基于所提供...

菜单MenuItem 与 ContextMenu 控件调用文档

命名空间:CConUI依赖:System.Windows.Forms、System.Drawing、...

图片框PictureBox 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control定位:自绘图片框...

蚂蚁线AntLine 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control定位:虚线蚂蚁线...