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

CircularButtonA 纯色圆形按钮控件调用文档

作品墙1小时前


命名空间:CConUI
继承:System.Windows.Forms.Control
可见性:public class CircularButtonA
默认尺寸:60 × 60(正方形)
默认事件:Click(继承自 Control;[DefaultEvent("Click")],设计器双击控件即生成该事件处理器)
定位:纯色自绘圆形按钮——自适应绘制正圆(即使控件是矩形,也按短边尺寸画正圆),支持三态背景色(常态 / 悬停 / 按下)、可自定义边框、禁用时自动变暗,支持鼠标左键点击与键盘 Space 触发 Click。


一、作用

完全自绘的圆形按钮,特点:

  • 自适应正圆:以 min(宽, 高) 作为直径,居中绘制正圆,控件非正方形时圆仍不变形;

  • 三态背景色:常态 ColorBack / 悬停 ColorEnter / 按下 ColorDown;

  • 边框智能高亮:悬停或按下时边框自动变亮 20%(ControlPaint.Light),常态为 BorderColor;

  • 禁用变暗:Enabled = false 时背景、边框都按 ControlPaint.Dark(..., 0.3f) 变暗 30%,文字变 Color.Gray;

  • 鼠标点击:左键按下 → 松开(松开时仍在控件内)触发 Click;

  • 键盘支持:控件获得焦点后,Space 按下 / 松开触发 Click;

  • 手型光标:默认 Cursors.Hand;

  • 文字居中:Text 在正圆区域内水平 + 垂直居中绘制,超长自动省略号。

状态与视觉对照

状态背景色边框色文字色
常态ColorBackBorderColorForeColor
悬停ColorEnterLight(BorderColor, 0.2)ForeColor
按下(鼠标 / Space)ColorDownLight(BorderColor, 0.2)ForeColor
禁用Dark(ColorBack, 0.3)Dark(BorderColor, 0.3)Color.Gray

二、快速上手

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

// 1. 创建控件
var btn = new CircularButtonA();

// 2. 放入容器
btn.Parent = panel1;
btn.Location = new Point(20, 20);
// 尺寸默认 60×60,可放大;建议保持正方形
btn.Size = new Size(72, 72);
btn.Text = "GO";

// 3. 订阅点击
btn.Click += (s, e) =>
{
    MessageBox.Show("点击了圆形按钮!");
};

// 4. 外观自定义(可选)
btn.ColorBack   = Color.FromArgb(0, 120, 215);
btn.ColorEnter  = Color.FromArgb(0, 150, 255);
btn.ColorDown   = Color.FromArgb(0, 90, 180);
btn.BorderColor = Color.FromArgb(0, 80, 150);
btn.BorderSize  = 2;
btn.ForeColor   = Color.White;
btn.Font        = new Font("Microsoft YaHei", 10F, FontStyle.Bold);

三、构造函数

public CircularButtonA()

项目说明
参数无
作用初始化纯色圆形按钮
实际行为① 启用 UserPaint | AllPaintingInWmPaint | OptimizedDoubleBuffer | ResizeRedraw | Selectable 样式(自绘 + 双缓冲 + 尺寸变化自动重绘 + 可获取焦点);
② 设置 ForeColor = Color.FromArgb(250, 250, 250);
③ 设置 Size = (60, 60)(正方形,保证默认就是正圆);
④ 设置 Cursor = Cursors.Hand
默认尺寸60 × 60(正方形)
默认外观ColorBack = (90,100,115)、ColorEnter = (110,125,140)、ColorDown = (80,90,100)、BorderColor = (139,148,158)、BorderSize = 0
var btn = new CircularButtonA
{
    Parent = panel1,
    Text = "OK"
};

四、公开属性

4.1 形状与边框

public int BorderSize

项目说明
类型int(像素)
默认0
CategoryCCon
DefaultValue0
作用边框粗细。
0 → 不绘制边框;
> 0 → 用 BorderColor 绘制相应粗细的圆形边框
取值范围Math.Max(0, value)——不能为负
绘制处理Pen 居中描边,因此圆形路径内缩 BorderSize / 2,让边框外边缘贴到圆的外接正方形边界
副作用赋值后 Invalidate() 重绘
btn.BorderSize = 0;   // 无边框(默认)
btn.BorderSize = 2;   // 2px 边框

4.2 颜色属性

public Color ColorBack

项目说明
类型Color
默认Color.FromArgb(90, 100, 115)(暗蓝灰)
CategoryCCon
作用按钮常态(未悬停、未按下、未禁用)下的圆形背景色
副作用赋值后 Invalidate() 重绘

public Color ColorEnter

项目说明
类型Color
默认Color.FromArgb(110, 125, 140)(中亮蓝灰)
CategoryCCon
作用鼠标悬停时的背景色,通常比 ColorBack 亮作为高亮反馈
副作用赋值后 Invalidate() 重绘

public Color ColorDown

项目说明
类型Color
默认Color.FromArgb(80, 90, 100)(较暗蓝灰)
CategoryCCon
作用按钮按下(鼠标左键按下 / Space 按下)时的背景色,形成“下沉”视觉效果
副作用赋值后 Invalidate() 重绘

public Color BorderColor

项目说明
类型Color
默认Color.FromArgb(139, 148, 158)(浅灰)
CategoryCCon
作用按钮边框颜色;仅在 BorderSize > 0 时可见;
悬停 / 按下时会自动变亮 20%,禁用时自动变暗 30%
副作用赋值后 Invalidate() 重绘
btn.ColorBack   = Color.FromArgb(0, 120, 215);   // 常态:蓝
btn.ColorEnter  = Color.FromArgb(0, 150, 255);   // 悬停:亮蓝
btn.ColorDown   = Color.FromArgb(0, 90, 180);    // 按下:暗蓝
btn.BorderColor = Color.FromArgb(0, 80, 150);    // 边框:深蓝

4.3 重写 / 隐藏的属性

public override string Text

项目说明
类型string
CategoryCCon
作用圆中央显示的文字;空串时不绘制
副作用赋值后 Invalidate() 重绘
绘制使用 TextRenderer.DrawText 在圆的外接正方形内 水平 + 垂直居中;去掉 NoPadding 以修正 GDI+ 文字偏上问题;超长自动省略号(EndEllipsis)

public override Color ForeColor

项目说明
类型Color
默认Color.FromArgb(250, 250, 250)(构造时设置)
CategoryCCon
作用文字颜色;禁用时自动变为 Color.Gray

public override Font Font

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

public override Color BackColor(隐藏)

项目说明
类型Color
Browsablefalse(属性面板中隐藏)
作用对按钮外观无影响——圆形背景由 ColorBack 控制。
此属性仅为兼容 Control 基类而保留,读写不会改变绘制效果

五、公开事件

public event EventHandler Click(继承自 Control)

项目说明
参数EventHandler:sender 为当前 CircularButtonA,e 为 EventArgs.Empty
默认事件是([DefaultEvent("Click")])——设计器双击即生成
触发时机① 鼠标左键:按下时在控件内 → 松开时仍在控件内(ClientRectangle.Contains(e.Location));
② 键盘 Space:OnKeyUp 里按 Space 松开时触发
不触发情况① 鼠标左键按下后移出控件再松开;
② 右键 / 中键;
③ 控件禁用(Enabled = false)——Control 基类不派发鼠标 / 键盘事件
备注内部通过 base.OnClick(EventArgs.Empty) 触发;本类未重写 OnClick,Click 由基类直接派发
btn.Click += (s, e) =>
{
    MessageBox.Show("点击了!");
};

六、公开方法

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

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

方法可见性作用
OnPaint(PaintEventArgs e)protected override整体绘制:正圆背景 → 边框 → 居中文字;禁用时自动变暗
OnMouseEnter(EventArgs e)protected override设置 _isHover = true 并重绘
OnMouseLeave(EventArgs e)protected override清除 _isHover 与 _isPressed 并重绘(防止按住拖出后卡在“按下色”)
OnMouseDown(MouseEventArgs e)protected override左键按下时 _isPressed = true,并调用 Focus() 获取焦点
OnMouseUp(MouseEventArgs e)protected override左键松开时清 _isPressed;若松开点在客户区内则调用 OnClick(EventArgs.Empty)
OnKeyDown(KeyEventArgs e)protected overrideSpace 按下 → _isPressed = true(视觉上按下去)
OnKeyUp(KeyEventArgs e)protected overrideSpace 松开 → _isPressed = false + 触发 OnClick(EventArgs.Empty)

七、公开成员速查表

成员来源类型说明
CircularButtonA()本类构造函数默认尺寸 60×60,默认无边框
BorderSize本类属性(int)边框粗细(默认 0,≥0)
ColorBack本类属性(Color)常态背景色
ColorEnter本类属性(Color)悬停背景色
ColorDown本类属性(Color)按下背景色
BorderColor本类属性(Color)边框颜色(BorderSize > 0 时可见);悬停自动变亮、禁用自动变暗
Text(重写)Control属性(string)圆中央文字
ForeColor(重写)Control属性(Color)文字颜色(禁用时变 Gray)
Font(重写)Control属性(Font)文字字体
BackColor(隐藏)Control属性(Color)Browsable(false);对按钮外观无影响
EnabledControl属性(bool)是否启用;禁用时背景 / 边框 / 文字自动变暗,鼠标键盘事件不派发
CursorControl属性默认 Hand;可自行改为 Default
TabStopControl属性(bool)默认 false;要支持 Tab 聚焦 + Space 触发需设为 true
Size / ClientSizeControl属性(Size)控件尺寸;建议保持正方形,非正方形时圆取短边尺寸
ClickControl事件(默认事件)鼠标左键或 Space 松开时触发
Invalidate()Control方法触发重绘
Focus()Control方法让按钮获取焦点(鼠标按下时已自动调用)
OnPaint(e)本类(override)方法(protected)绘制逻辑,外部不可直接调用
OnMouseEnter / OnMouseLeave / OnMouseDown / OnMouseUp本类(override)方法(protected)鼠标交互,外部不可直接调用
OnKeyDown / OnKeyUp本类(override)方法(protected)键盘交互,外部不可直接调用

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

8.1 确定背景色(优先级)

Color currentBackColor;
if (!this.Enabled)
    currentBackColor = ControlPaint.Dark(this._colorBack, 0.3f);
else if (this._isPressed)
    currentBackColor = this._colorDown;
else if (this._isHover)
    currentBackColor = this._colorEnter;
else
    currentBackColor = this._colorBack;
优先级状态背景色
1(最高)禁用ControlPaint.Dark(ColorBack, 0.3f)——变暗 30%
2按下ColorDown
3悬停ColorEnter
4常态ColorBack

8.2 计算自适应正圆

float side = Math.Min(ClientSize.Width, ClientSize.Height);
if (side <= 4f) return;

float ox = (ClientSize.Width - side) / 2f;
float oy = (ClientSize.Height - side) / 2f;
RectangleF outerRect = new RectangleF(ox, oy, side, side);

float bs = this._borderSize;
float halfBorder = bs / 2f;
RectangleF innerRect = RectangleF.Inflate(outerRect, -halfBorder, -halfBorder);
要点说明
side = min(宽, 高)取短边作为圆的直径——无论控件是什么形状都画正圆,多余空间留白
ox / oy水平 / 垂直居中偏移:(Client - side) / 2 是多出的半宽 / 半高
side ≤ 4控件过小时直接不绘制,避免异常半径
innerRect 内缩 halfBorderPen 居中描边,外边缘会超出路径 BorderSize / 2。内缩半个线宽后,边框外边缘正好贴到 outerRect

8.3 绘制背景与边框

using (var brush = new SolidBrush(currentBackColor))
    g.FillEllipse(brush, innerRect);

if (bs > 0)
{
    Color currentBorderColor;
    if (!this.Enabled)
        currentBorderColor = ControlPaint.Dark(this._borderColor, 0.3f);
    else if (this._isHover || this._isPressed)
        currentBorderColor = ControlPaint.Light(this._borderColor, 0.2f);
    else
        currentBorderColor = this._borderColor;

    using (var pen = new Pen(currentBorderColor, bs))
        g.DrawEllipse(pen, innerRect);
}
要点说明
背景与边框都使用 innerRect两者共享同一几何路径,视觉对齐
禁用时边框变暗Dark(BorderColor, 0.3f) 与背景变暗的力度一致
悬停 / 按下时边框变亮Light(BorderColor, 0.2f),让交互反馈更明显
bs = 0 时跳过边框绘制;背景仍填充在 innerRect 上(因 halfBorder = 0,即 outerRect)

8.4 绘制文字(用 TextRenderer 修正居中问题)

if (!string.IsNullOrEmpty(this.Text))
{
    Color textColor = this.Enabled ? this.ForeColor : Color.Gray;

    TextRenderer.DrawText(
        g,
        this.Text,
        this.Font,
        Rectangle.Round(outerRect),
        textColor,
        TextFormatFlags.HorizontalCenter |
        TextFormatFlags.VerticalCenter |
        TextFormatFlags.EndEllipsis |
        TextFormatFlags.NoPadding
    );
}
要点说明
TextRenderer 而非 Graphics.DrawString基于 GDI 绘制,字体渲染更清晰;
关键修复:DrawString 在圆中垂直居中时常常偏上(因 GDI+ 字体度量方式),改用 TextRenderer + NoPadding 可完美居中
NoPadding去掉文本周围内边距,保证视觉绝对居中
EndEllipsis文字超长自动省略号
绘制区域为 outerRect即正圆的外接正方形;文字在正方形内居中 → 视觉上在圆中央
禁用时文字变灰用 Color.Gray 替代 ForeColor

8.5 圆角在非正方形控件下的表现

控件尺寸绘制效果
正方形(宽=高)圆铺满整个客户区(扣除边框)
宽 > 高圆直径 = 高,水平居中,左右留白
宽 < 高圆直径 = 宽,垂直居中,上下留白

建议:为获得最佳视觉,尽量把 Size 设为正方形;否则周围留白看起来可能不美观。


九、交互一览

操作效果
鼠标进入控件_isHover = true,背景变 ColorEnter,边框变亮 20%
鼠标离开控件_isHover = false、_isPressed = false,背景 / 边框恢复常态
左键按下_isPressed = true,Focus() 获取焦点,背景变 ColorDown
左键松开(在控件内)_isPressed = false,触发 Click,背景回到悬停或常态
左键松开(移出控件)_isPressed = false,不触发 Click
Space 按下(有焦点)_isPressed = true,背景变 ColorDown
Space 松开(有焦点)_isPressed = false,触发 Click,背景恢复
Enter / 其它键不响应(本类只处理 Space)
右键 / 中键不响应,不触发 Click,也不改变视觉状态
禁用(Enabled=false)背景 / 边框 / 文字自动变暗;鼠标键盘事件不派发;不响应悬停 / 按下

十、完整使用示例

示例 1:基础圆形按钮

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

var btn = new CircularButtonA
{
    Parent = this,
    Location = new Point(20, 20),
    Size = new Size(60, 60),
    Text = "GO"
};

btn.Click += (s, e) =>
{
    MessageBox.Show("点击了圆形按钮!");
};

示例 2:大号 + 边框圆形按钮

var btn = new CircularButtonA
{
    Parent = this,
    Location = new Point(20, 20),
    Size = new Size(90, 90),
    Text = "开始",
    BorderSize = 3,
    ColorBack   = Color.FromArgb(0, 120, 215),
    ColorEnter  = Color.FromArgb(0, 150, 255),
    ColorDown   = Color.FromArgb(0, 90, 180),
    BorderColor = Color.FromArgb(0, 80, 150),
    ForeColor   = Color.White,
    Font        = new Font("Microsoft YaHei", 12F, FontStyle.Bold)
};

示例 3:圆形图标按钮(无边框)

var btn = new CircularButtonA
{
    Parent = this,
    Location = new Point(20, 20),
    Size = new Size(48, 48),
    Text = "+",
    BorderSize = 0,
    ColorBack   = Color.FromArgb(0, 180, 120),
    ColorEnter  = Color.FromArgb(0, 210, 150),
    ColorDown   = Color.FromArgb(0, 150, 100),
    ForeColor   = Color.White,
    Font        = new Font("Segoe UI", 18F, FontStyle.Bold)
};

示例 4:禁用状态

var btn = new CircularButtonA
{
    Parent = this,
    Text = "禁用",
    ColorBack = Color.Orange,
    BorderSize = 2,
    Enabled = false    // 禁用:背景/边框/文字自动变暗
};

// 条件满足时启用
btn.Enabled = true;

示例 5:键盘操作(Tab 聚焦 + Space 点击)

var btn = new CircularButtonA
{
    Parent = this,
    Size = new Size(64, 64),
    Text = "OK",
    TabStop = true      // 允许 Tab 键聚焦
};

btn.Click += (s, e) => MessageBox.Show("Space 触发");

说明:本类已通过 ControlStyles.Selectable 允许获取焦点。用户按 Tab 切到按钮后,按 Space 会先显示“按下”视觉,松开 Space 触发 Click。

示例 6:主题切换(圆形按钮组)

void ApplyPrimaryTheme(CircularButtonA btn)
{
    btn.ColorBack   = Color.FromArgb(0, 120, 215);
    btn.ColorEnter  = Color.FromArgb(0, 150, 255);
    btn.ColorDown   = Color.FromArgb(0, 90, 180);
    btn.BorderColor = Color.FromArgb(0, 80, 150);
    btn.ForeColor   = Color.White;
}

void ApplyDangerTheme(CircularButtonA btn)
{
    btn.ColorBack   = Color.FromArgb(200, 50, 50);
    btn.ColorEnter  = Color.FromArgb(230, 70, 70);
    btn.ColorDown   = Color.FromArgb(160, 30, 30);
    btn.BorderColor = Color.FromArgb(140, 20, 20);
    btn.ForeColor   = Color.White;
}

ApplyPrimaryTheme(btnPlay);
ApplyDangerTheme(btnStop);

示例 7:非正方形控件(自动画正圆)

// 控件是长方形,但依然画正圆,周围留白
var btn = new CircularButtonA
{
    Parent = this,
    Size = new Size(120, 60),    // 实际圆直径 = min(120, 60) = 60
    Text = "OK",
    ColorBack = Color.DodgerBlue,
    BorderSize = 2
};






转载请注明出处。

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

相关文章

已经实现的一些算法

编码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定位:虚线蚂蚁线...