一个简单的自定义进度条






4.84/5 (26投票s)
一个简单的自定义进度条。
引言
在本文中,我绘制了一个简单的自定义进度条,它包含四个部分,并根据状态和填充百分比显示不同的颜色。该类的编写是为了适应我公司的软件,但您可以轻松地根据自己的需求进行修改。进度条是显示任何类型数据的好方法,因为您可以从远处看到最“重要”的信息,而无需阅读文本。添加不同的颜色可以进一步增强这一点。
我使用了 Arun Reginald 前段时间发布的极好的扩展: https://codeproject.org.cn/KB/GDI-plus/ExtendedGraphicsII.aspx,来获得圆角。
背景
回到 VB 6 时代,一切都有控件。无论你想做什么,总有一些控件可以做到。我的公司使用一个简单的进度条,上面有一些文字来显示锯木厂的生产数据。在我们新版本的软件中,我们制作了一个更好看的表单版本。我们很喜欢它,直到有一天我们不得不通过 56K 远程控制;)。然而,客户并不喜欢。他们说太多不重要的图形了。所以我们听取了他们的意见,又回到了进度条的想法。 .NET 自带的那个在很多方面都不错,但有时你就是想要更多。我的朋友 Google 这次没有解决这个问题,所以我不得不自己编写一个。
Using the Code
一旦导入和编译,您就可以像在 Visual Studio 中使用任何其他控件一样使用此控件,或者您可以像这样添加它
HarrProgressBar pgb = new HarrProgressBar();
pgb.Padding = new Padding(5);
pgb.LeftText = "1";
pgb.MainText = "47x100x5400 - 20/100";
pgb.FillDegree = 20;
pgb.RightText = "1";
pgb.StatusText = "Raw";
pgb.StatusBarColor = 0;
pgb.Size = s;
pgb.Anchor = AnchorStyles.Left | AnchorStyles.Right;
this.flowLayoutPanel1.Controls.Add(pgb);
此控件基于 System.Windows.Forms.Panel
,因此支持所有正常行为,如 Anchor 和 Docking。我添加了一个内部填充,以在实际面板区域和绘制区域之间创建距离,以便能够切换背景颜色以获得“选定”的外观和感觉。
不同的颜色代码是硬编码的,以保持简单。要隐藏部分,只需将 sectionsize
设置为 0。
关注点
我还没有真正使用过太多 GDI+,所以做这个变化很有趣。我很快意识到圆角矩形看起来更好。但这并不容易,我很高兴找到了 Arun 的扩展,这使我的生活更加轻松。棘手的部分是计算要绘制的区域
private Rectangle GetLeftArea()
{
return new Rectangle(
Padding.Left,
Padding.Top,
LeftBarSize,
this.ClientRectangle.Height - Padding.Bottom - Padding.Top);
}
private Rectangle GetStatusArea()
{
return new Rectangle(
Padding.Left + LeftBarSize,
Padding.Top,
StatusBarSize,
this.ClientRectangle.Height - Padding.Bottom - Padding.Top);
}
private Rectangle GetMainArea()
{
return new Rectangle(
Padding.Left + LeftBarSize + StatusBarSize,
Padding.Top,
Convert.ToInt32(((this.ClientRectangle.Width -
(Padding.Left + LeftBarSize + StatusBarSize +
RightBarSize + Padding.Right)) * FillDegree) / 100),
this.ClientRectangle.Height - Padding.Bottom - Padding.Top);
}
private Rectangle GetMainAreaBackground()
{
return new Rectangle(
Padding.Left + LeftBarSize + StatusBarSize,
Padding.Top,
this.ClientRectangle.Width - (Padding.Left +
LeftBarSize + StatusBarSize + RightBarSize + Padding.Right),
this.ClientRectangle.Height - Padding.Bottom - Padding.Top);
}
private Rectangle GetRightArea()
{
return new Rectangle(
this.ClientRectangle.Width - (RightBarSize + Padding.Right),
Padding.Top,
RightBarSize,
this.ClientRectangle.Height - Padding.Bottom - Padding.Top);
}
我必须有两个不同的“主”部分才能绘制文本和灰色背景。一旦我有了这些矩形,绘制这些部分就很容易了
public void paintThis(Graphics _graphics)
{
// Textformat
StringFormat f = new StringFormat();
f.Alignment = StringAlignment.Center;
f.LineAlignment = StringAlignment.Center;
// Misc
_graphics = this.CreateGraphics();
System.Drawing.Drawing2D.LinearGradientBrush _LeftAndRightBrush =
new LinearGradientBrush(GetMainArea(), Color.DimGray,
Color.Black, LinearGradientMode.Vertical);
System.Drawing.Drawing2D.LinearGradientBrush _StatusBrush =
new LinearGradientBrush(GetMainArea(), StatusColor1,
StatusColor2, LinearGradientMode.Vertical);
System.Drawing.Drawing2D.LinearGradientBrush _MainBrush =
new LinearGradientBrush(GetMainArea(), FirstColor,
SecondColor, LinearGradientMode.Vertical);
// Draw left
if (LeftBarSize > 0)
{
_graphics.FillRoundedRectangle(_LeftAndRightBrush,
this.GetLeftArea(), this.RoundedCornerAngle,
RectangleEdgeFilter.TopLeft | RectangleEdgeFilter.BottomLeft);
_graphics.DrawString(this.LeftText, this.Font,
Brushes.White, this.GetLeftArea(), f);
}
// Draw status
if (StatusBarSize > 0)
{
_graphics.FillRoundedRectangle(_StatusBrush, this.GetStatusArea(),
this.RoundedCornerAngle, RectangleEdgeFilter.None);
_graphics.DrawString(this.StatusText, this.Font,
Brushes.White, this.GetStatusArea(), f);
}
// Draw main background
_graphics.FillRoundedRectangle(Brushes.DimGray,
GetMainAreaBackground(), this.RoundedCornerAngle,
RectangleEdgeFilter.None);
// Draw main
_graphics.FillRoundedRectangle(_MainBrush, this.GetMainArea(),
this.RoundedCornerAngle, RectangleEdgeFilter.None);
_graphics.DrawString(this.MainText, this.Font,
Brushes.White, this.GetMainAreaBackground(), f);
// Draw right
if (RightBarSize > 0)
{
_graphics.FillRoundedRectangle(_LeftAndRightBrush,
this.GetRightArea(), this.RoundedCornerAngle,
RectangleEdgeFilter.TopRight | RectangleEdgeFilter.BottomRight);
_graphics.DrawString(this.RightText, this.Font,
Brushes.White, this.GetRightArea(), f);
}
// Clean up
_LeftAndRightBrush.Dispose();
_MainBrush.Dispose();
_StatusBrush.Dispose();
}
拖放
为了使此控件更有用,我向其添加了拖放功能,由 AllowDrag
控制。为了使控件能够被“选中”,我必须防止在 MouseDown
上触发 DoDragDrop()
。这通过添加一个小检查来解决,因此您必须将控件拖动到小半径之外才能触发它。我还有 _isDragging
才能在 OnMouseMove
覆盖中触发 DoDragDrop();
。
protected override void OnMouseDown(MouseEventArgs e)
{
this.Focus();
base.OnMouseDown(e);
_mX = e.X;
_mY = e.Y;
this._isDragging = false;
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (!_isDragging)
{
// This is a check to see if the mouse is moving while pressed.
// Without this, the DragDrop is fired directly
// when the control is clicked, now you have to drag a few pixels first.
if (e.Button == MouseButtons.Left &&
_DDradius > 0 && this.AllowDrag)
{
int num1 = _mX - e.X;
int num2 = _mY - e.Y;
if (((num1 * num1) + (num2 * num2)) > _DDradius)
{
DoDragDrop(this, DragDropEffects.All);
_isDragging = true;
return;
}
}
base.OnMouseMove(e);
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
_isDragging = false;
base.OnMouseUp(e);
}
选择
我的目的是在 FlowLayoutPanel
中使用此控件,并使其看起来像一个 ListView
,因此我希望能够“选择”这些项目。这是通过在聚焦时更改背景颜色来实现的。这不是很完美,但对我来说已经足够好了。
protected override void OnGotFocus(EventArgs e)
{
this.BackColor = Color.SandyBrown;
base.OnGotFocus(e);
}
protected override void OnLostFocus(EventArgs e)
{
this.BackColor = Color.Transparent;
base.OnLostFocus(e);
}
protected override void OnClick(EventArgs e)
{
this.Focus();
base.OnClick(e);
}
最终想法
这个小小的圣诞作坊实际上效果很好。我可以添加更多的功能和更好看的图形和动画,但由于我的客户不想要或不需要它,我想我暂时会保持这样。
查看我的另一篇关于 FlowLayoutPanel
的文章,了解我计划如何使用它。
历史
- 2009-12-21 - v1.0 - 添加文章。