65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.39/5 (21投票s)

2008年12月19日

CPOL

8分钟阅读

viewsIcon

66091

downloadIcon

2973

从零开始制作您自己的进度条 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` 属性。
© . All rights reserved.