ProgressBarB 圆形进度条调用文档
命名空间:CConUI
继承:ProgressBarBase(自定义基类) → Control
可见性:public class ProgressBarB(可外部使用)
定位:圆形进度条——以圆环/扇形方式显示进度,继承 ProgressBarBase 的所有公共成员,仅重写绘制逻辑。
一、作用
在控件区域内绘制一个居中的圆形进度环:
底层是一个填满的背景圆(颜色
ColorBack);上层是一个扇形进度(颜色
ColorCore),从 12 点方向开始顺时针扩展;最外层绘制一个圆环边框(
BorderColor/BorderSize);中央可显示文本
Text(ForeColor/Font)。
适用于:圆形下载/加载指示器、环形进度展示、仪表盘风格的状态指示等场景。
二、快速上手
using System.Drawing;
using System.Windows.Forms;
using CConUI;
// 1. 创建控件
var bar = new ProgressBarB();
// 2. 放入容器
bar.Parent = panel1;
bar.Dock = DockStyle.None;
bar.Size = new Size(120, 120); // 必须接近正方形,圆形才会是正圆
bar.Location = new Point(30, 30);
// 3. 设置进度范围与当前值
bar.Min = 0;
bar.Max = 100;
bar.Value = 45;
bar.Text = "45%";
// 4. 外观
bar.ColorBack = Color.FromArgb(50, 50, 50); // 背景圆
bar.ColorCore = Color.FromArgb(0, 200, 120); // 进度扇形
bar.BorderColor = Color.FromArgb(30, 30, 30); // 圆环
bar.BorderSize = 4;
bar.ForeColor = Color.White;
bar.Font = new Font("Microsoft YaHei", 10F, FontStyle.Bold);
// 5. 监听进度变化(请以 ProgressBarBase 实际事件名为准,
// 若基类使用 ValueChanged,则订阅它;若使用 Change,则改为 bar.Change)
bar.Value = 80;
bar.Invalidate(); // 若基类 Value 不自动重绘,可手动 Invalidate三、构造函数
public ProgressBarB()
| 项目 | 说明 |
|---|---|
| 参数 | 无(本类未定义构造函数,使用 C# 隐式默认构造函数) |
| 实际行为 | 调用 ProgressBarBase 的无参构造函数进行初始化 |
| 默认尺寸 | 请以 ProgressBarBase 为准;使用本控件时建议手动设置接近正方形的 Size(如 100×100、120×120),否则圆形会被拉伸成椭圆 |
var bar = new ProgressBarB
{
Parent = panel1,
Size = new Size(120, 120)
};四、公开成员
4.1 本类新增/重写的成员
| 成员 | 类型 | 可见性 | 说明 |
|---|---|---|---|
OnPaint(PaintEventArgs e) | 方法(override) | protected override | 重写绘制逻辑,改为绘制圆形进度环。外部无法直接调用,仅在控件需要重绘时由 WinForms 自动调用 |
ProgressBarB本身没有新增 public 属性、方法或事件,它的所有对外接口完全继承自ProgressBarBase。
4.2 继承自 ProgressBarBase 的成员(由本类绘制逻辑推断)
以下是 ProgressBarB.OnPaint 中实际访问到的成员,它们由 ProgressBarBase 提供,语义应与其同名成员一致:
| 成员 | 类型(推断) | 在本类中的作用 | 用法示例 |
|---|---|---|---|
Min | int | 进度下限;用于计算扇形角度 | bar.Min = 0; |
Max | int | 进度上限;用于计算扇形角度 | bar.Max = 100; |
Value | int | 当前进度;决定扇形扫过的角度 | bar.Value = 45; |
ColorBack | Color | 背景圆的填充色 | bar.ColorBack = Color.Gray; |
ColorCore | Color | 进度扇形的填充色 | bar.ColorCore = Color.Lime; |
BorderColor | Color | 圆环边框颜色 | bar.BorderColor = Color.Black; |
BorderSize | int | 圆环边框粗细(像素) | bar.BorderSize = 4; |
其它可能存在于
ProgressBarBase中的成员(例如文本/字体/前景色、事件Change或ValueChanged、等待特效等),本源码未直接引用,请以ProgressBarBase源码为准。常见场景下,基类至少会提供:
Text/Font/ForeColor(继承自Control,本类绘制中使用了Text、Font、ForeColor);
Change或ValueChanged事件(用于监听Value变化);
BorderSize的合理默认值、ColorBack/ColorCore/BorderColor的默认颜色。
4.3 绘制逻辑所使用到的 Control 继承成员
| 成员 | 来源 | 说明 |
|---|---|---|
Text | Control | 控件文本;本类在圆形中央居中绘制 |
Font | Control | 文本字体 |
ForeColor | Control | 文本颜色 |
ClientSize | Control | 用于计算圆的直径和位置 |
Invalidate() | Control | 属性变化后触发重绘 |
五、公开方法
ProgressBarB没有定义任何 public 方法,全部公开方法由ProgressBarBase与Control继承。若
ProgressBarBase中定义了类似LoadStart()/LoadPause()/LoadEnd()等“等待特效”方法(参考ProgressBarA),在ProgressBarB中不会被重写——ProgressBarB只重写了OnPaint,所以调用这些方法仍然有效,但由于绘制逻辑已被替换为“圆形进度”,等待特效的视觉效果不会体现在ProgressBarB的绘制里(除非ProgressBarBase.OnPaint里本身有相关逻辑被base.OnPaint(e)调用——实际上ProgressBarB第一行就调用了base.OnPaint(e),所以基类的绘制会被执行,但ProgressBarB会在其之上再次绘制圆形,可能造成视觉重叠)。
因此:
如需使用基类提供的“等待特效”,需要确认基类的
OnPaint是否会绘制矩形条;若是,则会与ProgressBarB的圆形绘制叠加,视觉效果混乱;建议只把
ProgressBarB用于“静态圆形进度”的场景。
六、绘制原理(深入理解)
以下分析帮助你在调整尺寸、边框、颜色时理解
ProgressBarB的具体表现。
6.1 计算外圆
float side = Math.Min(ClientSize.Width, ClientSize.Height); if (side
| 要点 | 说明 |
|---|---|
| 正方形判断 | 以 min(宽, 高) 作为直径,保证在非正方形控件中也是正圆(多出的空间留白) |
d = side - 1f | 减 1 像素:因为 GDI+ 的 DrawEllipse / FillPie 在抗锯齿模式下,如果直径恰好等于 side,最右/最下边缘会被裁掉半像素。减 1 让外圆完整落在控件内 |
ox / oy | 让外接正方形在客户区内居中:(Client - d) / 2 是左右/上下多余的半宽/半高 |
side ≤ 4 | 太小不绘制,避免出现异常半径导致绘制错误 |
6.2 计算边框粗细
int border = Math.Min(base.BorderSize, (int)(d / 2) - 1);
| 要点 | 说明 |
|---|---|
上限 d/2 - 1 | 边框半径不能超过圆的半径,否则整个圆都会被边框覆盖。减 1 是安全余量 |
| 最小值 | BorderSize 为负数或 0 时 border 为 0,跳过边框绘制 |
6.3 绘制背景圆
using (var b = new SolidBrush(base.ColorBack)) g.FillPie(b, outer.X, outer.Y, outer.Width, outer.Height, -90f, 360f);
| 要点 | 说明 |
|---|---|
用 FillPie 而不是 FillEllipse | 为了让背景圆与进度扇形走同一条 GDI+ 路径族(FillPie 在 Windows 下可能有细微的像素处理差异)。这样两者弧线才能完美重合,避免边缘出现“锯齿叠锯齿” |
-90f, 360f | 从 12 点方向(-90°)开始,扫过 360°,也就是完整圆。GDI+ 角度单位是度,0° 在 3 点方向,顺时针为正 |
6.4 绘制进度扇形
float sweep = 0f;
if (base.Max > base.Min)
{
int v = Math.Max(base.Min, Math.Min(base.Max, base.Value));
sweep = 360f * (v - base.Min) / (base.Max - base.Min);
}
if (sweep > 0f)
{
var fill = RectangleF.Inflate(outer, 0.5f, 0.5f); // 膨胀 0.5 像素
using (var b = new SolidBrush(base.ColorCore))
g.FillPie(b, fill.X, fill.Y, fill.Width, fill.Height, -90f, sweep);
}| 要点 | 说明 |
|---|---|
Max > Min 保护 | 如果 Max ≤ Min(例如默认 0/100 但用户误设 Max = 0),跳过绘制,避免除零得到 NaN |
Math.Max/Clamp | 先把 Value 夹到 [Min, Max] 内,防止越界导致角度超过 360° |
360f * (v - Min) / (Max - Min) | 线性映射:v = Min 时 sweep = 0;v = Max 时 sweep = 360 |
RectangleF.Inflate(outer, 0.5f, 0.5f) | 把外接矩形向外膨胀 0.5 像素,让进度弧比背景弧稍微大一点,从而覆盖掉背景圆在抗锯齿下可能露出的 1 像素“漏白” |
sweep > 0f | 进度为 0 时不绘制,避免画出一根发丝状的线 |
6.5 绘制文本
if (!string.IsNullOrEmpty(Text))
{
using (var b = new SolidBrush(ForeColor))
using (var sf = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
})
g.DrawString(Text, Font, b, outer, sf);
}| 要点 | 说明 |
|---|---|
绘制在 outer 内 | 即外接正方形,文字在圆的中心居中 |
Center / Center | 水平居中 + 垂直居中 |
6.6 绘制圆环边框
if (border > 0)
{
float half = border / 2f;
var penRect = RectangleF.Inflate(outer, -half, -half); // 向内缩 half
using (var p = new Pen(base.BorderColor, border))
g.DrawEllipse(p, penRect);
}| 要点 | 说明 |
|---|---|
RectangleF.Inflate(outer, -half, -half) | GDI+ 的 Pen 默认对齐方式是居中——描边会以绘制路径为中轴,向内外各扩展 border/2。如果直接 DrawEllipse(outer),一半边框会画到 outer 外面。向内缩 half,使描边的外边缘正好落在 outer 上 |
| 边框最后绘制 | 为什么最后画:进度扇形膨胀了 0.5 像素,可能会盖住背景圆的边缘。边框放在最后绘制,可以覆盖掉这 0.5 像素的溢出,让边缘干净整齐 |
border 上限 | 前面已限制为不超过 d/2 - 1,保证 penRect 内接矩形仍然有效 |
七、公开成员速查表
| 成员 | 来源 | 类型 | 说明 |
|---|---|---|---|
ProgressBarB() | 本类(隐式) | 构造函数 | 默认无参构造,调用基类初始化 |
Min | ProgressBarBase | 属性(int) | 进度下限 |
Max | ProgressBarBase | 属性(int) | 进度上限 |
Value | ProgressBarBase | 属性(int) | 当前进度 |
ColorBack | ProgressBarBase | 属性(Color) | 背景圆颜色 |
ColorCore | ProgressBarBase | 属性(Color) | 进度扇形颜色 |
BorderColor | ProgressBarBase | 属性(Color) | 圆环颜色 |
BorderSize | ProgressBarBase | 属性(int) | 圆环粗细 |
Text | Control | 属性(string) | 圆中央文字 |
Font | Control | 属性(Font) | 文字字体 |
ForeColor | Control | 属性(Color) | 文字颜色 |
Size / ClientSize | Control | 属性(Size) | 建议设为正方形 |
Invalidate() | Control | 方法 | 触发重绘 |
OnPaint(e) | 本类(override) | 方法(protected) | 圆形绘制逻辑,外部不可直接调用 |
事件(如
Change/ValueChanged)与其它方法请参考ProgressBarBase源码。
八、完整使用示例
示例 1:基础圆形进度条
using System.Drawing;
using System.Windows.Forms;
using CConUI;
var bar = new ProgressBarB
{
Parent = panel1,
Size = new Size(120, 120),
Location = new Point(20, 20),
Min = 0,
Max = 100,
Value = 45,
Text = "45%",
ColorBack = Color.FromArgb(45, 45, 48),
ColorCore = Color.FromArgb(0, 200, 120),
BorderColor = Color.FromArgb(30, 30, 30),
BorderSize = 4,
ForeColor = Color.White,
Font = new Font("Microsoft YaHei", 10F, FontStyle.Bold)
};示例 2:配合计时器动态变化
var bar = new ProgressBarB
{
Parent = this,
Size = new Size(150, 150),
Min = 0,
Max = 100,
BorderSize = 6,
ColorBack = Color.FromArgb(50, 50, 50),
ColorCore = Color.OrangeRed,
BorderColor = Color.FromArgb(20, 20, 20),
Font = new Font("Segoe UI", 12F, FontStyle.Bold)
};
var timer = new Timer { Interval = 50 };
timer.Tick += (s, e) =>
{
if (bar.Value >= bar.Max)
{
timer.Stop();
bar.Text = "完成";
return;
}
bar.Value += 1;
bar.Text = bar.Value + "%";
bar.Invalidate(); // 若基类 Value 不自动刷新,需手动 Invalidate
};
timer.Start();示例 3:圆形下载指示器
var bar = new ProgressBarB
{
Parent = this,
Size = new Size(80, 80),
BorderSize = 3,
ColorBack = Color.FromArgb(240, 240, 240),
ColorCore = Color.DodgerBlue,
BorderColor = Color.LightGray,
Font = new Font("Microsoft YaHei", 8F)
};
// 模拟下载
int total = 500;
int current = 0;
bar.Max = total;
bar.Value = 0;
var timer = new Timer { Interval = 50 };
timer.Tick += (s, e) =>
{
current += 10;
if (current >= total)
{
current = total;
timer.Stop();
}
bar.Value = current;
bar.Text = (current * 100 / total) + "%";
bar.Invalidate();
};
timer.Start();示例 4:多个圆形进度条(网格排布)
for (int i = 0; i < 4; i++)
{
var bar = new ProgressBarB
{
Parent = panel1,
Size = new Size(90, 90),
Location = new Point(10 + i * 100, 10),
Min = 0,
Max = 100,
Value = 25 * (i + 1),
Text = (25 * (i + 1)) + "%",
ColorCore = Color.FromArgb(0, 150 + i * 30, 200 - i * 30),
BorderSize = 4
};
}转载请注明出处。