WinForm断续进度条自定义实现
这段时间用WinForm写了一个断续进度条,以下是代码示例。
public partial class SegmentProgressBar : UserControl
{
private const int MINIMUM_SEGMENTS = 1;
private int maximumSegments;
private bool showBorder = true;
private bool showText = true;
private Color borderColor = Color.Black;
private Color textColor = Color.White;
private Color notStartedColor = Color.LightGray;
private Color failedColor = Color.Red;
private Color inProgressColor = Color.Yellow;
private Color completedColor = Color.Green;
private string text;
private SegmentState[] segments;
private int updateIndex;
public int UpdateProgressBarTimes { get; set; } = 3;
public bool OnlyUpdateMustArea = false;
public SegmentProgressBar()
{
InitializeComponent();
Reset();
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
private void Reset()
{
//ensure maximum segments is at least 1...
this.maximumSegments = Math.Max(1, this.maximumSegments);
this.segments = new SegmentState[maximumSegments];
this.Invalidate();
}
public void UpdateSegment(int index, SegmentState state)
{
if (index >= 0 && index < maximumSegments)
{
if (this.segments[index] != state)
{
this.segments[index] = state;
if (updateIndex>UpdateProgressBarTimes)
{
if (OnlyUpdateMustArea)
{
// 仅重绘改变状态的段的区域
float segmentWidth = (float)this.Width / this.segments.Length;
Rectangle invalidRect = new Rectangle(
(int)(index * segmentWidth),
0,
(int)segmentWidth,
this.Height);
this.Invalidate(invalidRect);
}
else
{
this.Invalidate();
}
updateIndex = 0;
}
else
{
updateIndex++;
}
}
return;
}
// throw new IndexOutOfRangeException("...");
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
float segmentWidth = (float)this.Width / this.segments.Length;
int startSegment = (int)(e.ClipRectangle.Left / segmentWidth);
int endSegment = (int)Math.Ceiling((float)e.ClipRectangle.Right / segmentWidth);
if (OnlyUpdateMustArea)
{
// 仅重绘被标记为无效的段
for (int j = startSegment; j < Math.Min(endSegment, this.segments.Length); j++)
{
float x = j * segmentWidth;
e.Graphics.FillRectangle(new SolidBrush(ColorFromSegmentState(this.segments[j])), x, 0, segmentWidth, this.Height);
}
}
else
{
DrawSegments(e.Graphics);
}
if (ShowText) DrawText(e.Graphics);
if (ShowBorder) DrawBorder(e.Graphics);
}
//protected override void OnPaint(PaintEventArgs e)
//{
// base.OnPaint(e);
// DrawSegments(e.Graphics);
// if (ShowText)
// {
// DrawText(e.Graphics);
// }
// if (ShowBorder)
// {
// DrawBorder(e.Graphics);
// }
//}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Invalidate();
}
private void DrawBorder(Graphics g)
{
g.DrawRectangle(new Pen(Color.Black), 0, 0, this.Width - 1, this.Height - 1);
}
private void DrawText(Graphics g)
{
SizeF textSize = g.MeasureString(this.Text, this.Font);
g.DrawString(this.text, this.Font, new SolidBrush(TextColor), new Point((int)(this.Width / 2 - textSize.Width / 2), (int)(this.Height / 2 - textSize.Height / 2)));
}
//private void DrawSegments(Graphics g)
//{
// //these must be cast as float to have the sum a float, otherwise it rounds down to int
// float segmentWidth =(float)this.Width / (float)this.segments.Length;
// for (int j = 0; j < this.segments.Length; j++)
// {
// float x = j * segmentWidth;
// g.FillRectangle(new SolidBrush(ColorFromSegmentState(this.segments[j])), x, 0, segmentWidth, this.Height);
// }
//}
private void DrawSegments(Graphics g)
{
int totalWidth = this.Width;
int totalSegments = this.segments.Length;
for (int j = 0; j < totalSegments; j++)
{
// 计算每个段的宽度,确保最后一个段能够填满剩余空间
float x = (float)totalWidth * j / totalSegments;
float nextX = (float)totalWidth * (j + 1) / totalSegments;
float segmentWidth = nextX - x;
g.FillRectangle(new SolidBrush(ColorFromSegmentState(this.segments[j])), x, 0, segmentWidth, this.Height);
}
}
private Color ColorFromSegmentState(SegmentState state)
{
switch (state)
{
default:
case SegmentState.NOT_STARTED:
return NotStartedColor;
case SegmentState.IN_PROGRESS:
return InProgressColor;
case SegmentState.COMPLETED:
return CompletedColor;
case SegmentState.FAILED:
return FailedColor;
}
}
[Description("Maximum segments of the progress bar."), DefaultValue(100), Browsable(true)]
public int MaximumSegments
{
get { return this.maximumSegments; }
set
{
if (value < MINIMUM_SEGMENTS)
{
throw new Exception("Minimum segment value must be at least 1");
}
this.maximumSegments = value; this.Reset();
}
}
[Description("Is the border shown?"), DefaultValue(true), Browsable(true)]
public bool ShowBorder
{
get { return this.showBorder; }
set { this.showBorder = value; this.Invalidate(); }
}
[Description("Is the text shown?"), DefaultValue(true), Browsable(true)]
public bool ShowText
{
get { return this.showText; }
set { this.showText = value; this.Invalidate(); }
}
[Description("Color of the border."), Category("Progress"), Browsable(true)]
public Color BorderColor
{
get { return this.borderColor; }
set { this.borderColor = value; this.Invalidate(); }
}
[Description("Color of the text."), Category("Progress"), Browsable(true)]
public Color TextColor
{
get { return this.textColor; }
set { this.textColor = value; this.Invalidate(); }
}
[Description("Color of non-started segments."), Category("Progress"), Browsable(true)]
public Color NotStartedColor
{
get { return this.notStartedColor; }
set { this.notStartedColor = value; this.Invalidate(); }
}
[Description("Color of working segments."), Category("Progress"), Browsable(true)]
public Color InProgressColor
{
get { return this.inProgressColor; }
set { this.inProgressColor = value; this.Invalidate(); }
}
[Description("Color of completed segments."), Category("Progress"), Browsable(true)]
public Color CompletedColor
{
get { return this.completedColor; }
set { this.completedColor = value; this.Invalidate(); }
}
[Description("Color of failed segments."), Category("Progress"), Browsable(true)]
public Color FailedColor
{
get { return this.failedColor; }
set { this.failedColor = value; this.Invalidate(); }
}
[Description("Text value of the progress bar."), Category("Progress"), Browsable(true)]
public override string Text
{
get { return this.text; }
set { this.text = value; this.Invalidate(); }
}
public int SegmentsCompleted
{
get
{
return GetSegmentsOfType(SegmentState.COMPLETED);
}
}
public int SegmentsFailed
{
get
{
return GetSegmentsOfType(SegmentState.FAILED);
}
}
public int SegmentsInProgress
{
get
{
return GetSegmentsOfType(SegmentState.IN_PROGRESS);
}
}
public int SegmentsNotStarted
{
get
{
return GetSegmentsOfType(SegmentState.NOT_STARTED);
}
}
private int GetSegmentsOfType(SegmentState state)
{
int total = 0;
foreach (SegmentState setState in this.segments)
{
if (setState == state)
{
total++;
}
}
return total;
}
public void ClearProgressBar()
{
for (int i = 0; i < maximumSegments; i++)
{
segments[i] = SegmentState.NOT_STARTED;
}
Invalidate();
}
}