更好的进度条 - 使用面板!






4.39/5 (21投票s)
从零开始制作您自己的进度条 UserControl。
引言
进度条控件构成了 Windows UI 的很大一部分;没错,没有它们我们该怎么办?无论何时我们需要知道计算机在某个任务上的进展程度,它们都在那里。在 .NET 框架中,它们非常简单易用,因此,用几个面板和一个 UserControl 就可以轻松制作。只需几个快速的属性和函数,您就可以拥有自己的进度条控件,用于您的 WinForms 应用程序。
然而,在微软某栋大楼的深处,一位程序员创建了 Windows 进度条控件,依我看,它相当不友好。即使付出了巨大的努力,也无法改变条的颜色,甚至可能根本无法改变!好吧……我们很快就会改变这一切。
背景
我们的最终结果将是简洁的奇迹和设计的胜利,类似这样
条的颜色、未填充条的颜色、边框颜色、边框可见性以及光泽可见性都将完全可自定义,为您的应用程序增添一些额外的亮点。
现在,为了实现这一点,我们不会编写大量的复杂代码。别告诉我的 IT 老师,但我们会使用……面板。是的!面板!卑微的面板将在我们的项目中得到充分利用。事实上,整个控件都围绕着它们构建,精确地说,是四个。但是,在你们任何人开始问我为什么不直接使用 GDI+ 之前,那是因为面板就足够了。何必过度复杂化呢?
使用代码
首先,我们将创建一个新的 VB Express 2008 类库项目,删除 'Class1',然后添加一个名为“ColourProgressBar
”的新 UserControl,并在设计器中将控件的大小调整为大约 200 像素乘以 30 像素。您已经可以看到它成形了!速度真快!
添加一个 `Panel`,命名为 `ProgressFull`,并将其停靠在左侧;然后是另一个,停靠在 'Fill
',命名为 `ProgressEmpty`。将 `ProgressFull` 的 `BackColor` 属性更改为您喜欢的任何颜色,除了 'Control
'(这只是为了让我们能够看到我们工作的结果)。您会注意到它越来越像一个进度条,但我们仍然需要添加光泽。将一个 `Panel` 放在右侧 `Panel` 内。将其顶部停靠,将其高度调整为 10,并命名为 `GlossRight`;在左侧执行相同的操作并命名为 `GlossLeft`。然后,我们将 `BackColor` 更改为 100, 255, 255, 255。这会将光泽面板的 `BackColor` 设置为半透明的白色,从而增强控件的整体美感。
最后,将容纳我们所有面板的实际控件的内边距设置为 1,1,1,1。这会在我们的进度条周围创建一个细边框,这意味着,我们要做的就是改变边框颜色,只需更改背景颜色即可。
继续点击“debug”。在 `TestContainer` 中更改控件的 `BackColor`,看看边框颜色如何变化。很酷,不是吗?
好了!现在,我们的控件看起来就像最终结果一样
现在,我们只需要让它工作,这真的不难。首先,我们需要导入一些东西来帮助编写我们的代码,这真的就像在代码顶部添加这些行一样简单
Imports System.ComponentModel
Imports System.Drawing
这些行只是导入了我们将需要编写进度条代码的所有必要的 .NET 框架部分。接下来,一些全局变量用于在我们的函数之间传递数据
Private ProgressUnit As Integer = 20
- 进度条递增的像素量。Private ProgressValue As Integer = 1
- 已填充 `MaxValue` 的量。Private MaximumValue As Integer = 10
- 进度条的最大值。Private IsBorderEnabled As Boolean = True
- 设置进度条上是否启用了边框。Private ShowGloss As Boolean = True
- 设置进度条上是否显示光泽。
好了,既然如此,让我们概述一下我们的主要函数。这些函数很简单,而且只有两个。
UpdateProgress()
– 一个全能函数,用于更新进度条,根据全局变量进行更改。UpadateGloss()
- 一个单独的函数,用于根据全局变量更改光泽。
到目前为止,`UpdateGloss()` 函数是最简单的。它只执行一个非常简单的操作,根据 UserControl 的大小调整每个 `GlossPanel` 的大小
Private Function UpdateGloss() As Boolean
Try
'Hide Each GlossPanel [
GlossPanelLeft.Height = (Me.Height / 3)
GlossPanelRight.Height = GlossPanelLeft.Height
']
Catch MyException As Exception
'Return A Failure And Exit [
Return False
Exit Function
']
End Try
'Return A Success [
Return True
']
End Function
`UpdateProgress()` 函数较长,但原理相似。
Private Function UpdateProgress() As Boolean
Try
'Recalculate Globals [
ProgressUnit = (Me.Width / MaximumValue)
ProgressFull.Width = (ProgressValue * ProgressUnit)
']
'Hide Or Show GlossPanels According To Globals [
If ShowGloss Then
GlossPanelLeft.Visible = True
GlossPanelRight.Visible = True
Else
GlossPanelLeft.Visible = False
GlossPanelRight.Visible = False
End If
']
'If At Maximum Value, Fill The ProgressBar [
If ProgressValue = MaximumValue Then
If IsBorderEnabled Then
ProgressFull.Width = (Me.Width - 2)
Else
ProgressFull.Width = Me.Width
End If
End If
']
'Hide Or Show The Borders According To Globals [
If IsBorderEnabled Then
Me.Padding = New Windows.Forms.Padding(1)
Else
Me.Padding = New Windows.Forms.Padding(0)
End If
']
Catch MyException As Exception
'Return A Failure And Exit [
Return False
Exit Function
']
End Try
'Return A Success [
Return True
']
End Function
从代码中可以清楚地看到,几乎所有东西都围绕着全局变量。这会造成不友好的编程界面吗?绝对不会。在 .NET 和其他面向对象编程方法出现之前,编程非常线性:接收用户输入,处理,然后输出,就是这么简单。但现在,有了 .NET,我们可以创造更多。进入有史以来最伟大的编程成就之一!属性!
我们的控件通过属性接收如何在 Forms Designer 和程序本身中执行的指令,我们的 UserControl 使用了其中的许多。一些用于控制外观和美感,一些用于使事物移动并以进度条应有的方式工作
ProgressMaximumValue As Integer
– 进度条的最大值。BorderColor As Color
– 进度条边框的颜色。ShowBorder As Boolean
– 是否显示边框。IsGlossy As Boolean
– 是否显示两个 `GlossPanel`。BarColor As Color
– 进度条填充部分的颜色。EmptyColor As Color
– 进度条未填充部分的颜色。
我不会在本文中介绍所有这些属性,因为它们大多是标准的 `Get`-`Set` 样式属性;但是,其中有几个特别值得注意。
<DefaultValue(1), _
Description("The total progress of the ProgressBar."), _
Category("ProgressBar Properties")> _
Public Property Value() As Integer
Get
'Return The Property [
Return ProgressValue
']
End Get
Set(ByVal value As Integer)
'Don't Allow More Than The Maximum Value [
If value <= MaximumValue Then
ProgressValue = value
Else
ProgressValue = MaximumValue
End If
']
'Update The ProgressBar [
UpdateProgress()
']
End Set
End Property
首先,请注意函数末尾调用了 `UpdateProgress()`。这非常重要,因为是 `UpdateProgress()` 函数根据全局变量更新进度条。没有它,属性将毫无作用!
接下来,请注意我们不允许在进度条属性中输入超过进度条最大值的值。如果输入的值过高,进度条将默认设置为最大值,并且不会超出控件本身范围,这可能会导致许多不便。但是,为了确保健壮的编程,我们还必须对 `ProgressMaximumValue` 属性施加限制
<DefaultValue(10), _
Description("The maximum value of the ProgressBar."), _
Category("ProgressBar Properties")> _
Public Property ProgressMaximumValue() As Integer
Get
'Return The Property [
Return MaximumValue
']
End Get
Set(ByVal value As Integer)
If value > Me.Width Then
MaximumValue = Me.Width
Else
MaximumValue = value
End If
'
'Update The ProgressBar [
UpdateProgress()
']
End Set
End Property
首先,`MaximumValue` 不能超过控件的像素宽度。这可能会造成 *严重* 问题,甚至可能导致进度条根本不显示,如果 `MaximumValue` 设置得太高,例如 10000。并且,标准做法是,最后调用 `UpdateProgress()`。
接下来,我们在控件的某些部分添加了一些事件处理程序,这些处理程序将影响一个或多个我们的面板
ColourProgressBar_Load
– 只需调用 `UpdateProgress()` 函数即可初始化进度条。ColourProgressBar_PaddingChanged
– 不允许内边距超过 `IsBorderEnabled` 全局变量指定的量。ColourProgressBar_Resized
– 根据高度调整光泽的大小,然后调用 `UpdateProgress()`。ColourProgressBar_DockChanged
– 原因与 `Resized` 事件几乎相同,因为控件在停靠时会调整大小。
让我们快速看一下其中两个的内容:`PaddingChanged` 和 `Resize` 事件
If IsBorderEnabled Then
Me.Padding = New Windows.Forms.Padding(1)
Else
Me.Padding = New Windows.Forms.Padding(0)
End If
这是 `PaddingChanged` 事件的内容。它所做的只是确保进度条具有正确的内边距,具体取决于 `IsBorderEnabled` 变量。`Resized` 事件处理程序执行类似的任务。
If Value <= MaximumValue Then
UpdateProgress()
End If
调用 `UpdateGloss` 函数会重新对齐所有内容,以反映进度条控件的大小。但是,我们还没有完成。我们需要为我们的控件添加一些事件。要添加的一个重要事件是改进的 `Click` 事件。这很重要,因为目前只有实际控件会响应单击,如果我们单击任何面板,则不会触发该事件。但这现在很复杂。我们只需要添加一行代码
Public Shadows Event Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
小菜一碟,看到了吗?我们一举创建了 `Click` 事件的引用。现在,我们只需为我们四个面板中的每一个添加 `Click` 事件处理程序,每个事件都包含这行代码
RaiseEvent Click(Me, e)
这只是为实际控件引发 `Click` 事件,而不是内部的面板,以便在控件包含在应用程序中时方便编码。如果此处未涵盖任何内容,请查看示例代码和应用程序。我喜欢认为我已经很好地注释了它们。
搞定!
很有可能,创建自己的进度条的最简单方法刚刚展现在大家面前,而且更重要的是,事实证明,一个依赖于面板的 UserControl 与 GDI+ 普通类库一样有效!所以,就这样了,一个控件,希望它能作为您自己控件的起点,或者当 Windows 进度条太丑、太不友好,或者根本不适合您预期的目的时,可以在您自己的应用程序中使用。
致谢
- 非常感谢 Mark James 的 Silk Icon Pack(在演示应用程序中使用)。请访问他的网站 这里。
历史
- 19/12/08 - 文章上传于 21:12。
- 22/12/08 - 文章更新于 10:20 -- `ProgressBarValue` 已更改为 `Value`,以更好地替代标准进度条。已添加 `GlossOpacity` 属性。