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

一个简单的自定义进度条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (26投票s)

2009年12月21日

CPOL

3分钟阅读

viewsIcon

76210

downloadIcon

4196

一个简单的自定义进度条。

引言

在本文中,我绘制了一个简单的自定义进度条,它包含四个部分,并根据状态和填充百分比显示不同的颜色。该类的编写是为了适应我公司的软件,但您可以轻松地根据自己的需求进行修改。进度条是显示任何类型数据的好方法,因为您可以从远处看到最“重要”的信息,而无需阅读文本。添加不同的颜色可以进一步增强这一点。

我使用了 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 - 添加文章。
© . All rights reserved.