加载等待控件----------WinForm控件开发系列

加载等待控件----------WinForm控件开发系列

  /// <summary>
  /// 加载进度控件
  /// </summary>
  [ToolboxItem(true)]
  [Description("加载进度控件")]
  [DefaultProperty("Active")]
  public partial class LoadProgressExt : Control
  {
    #region 属性

    private LoadProgressType progressType = LoadProgressType.Line;
    /// <summary>
    /// 加载进度条类型
    /// </summary>
    [Description("加载进度条类型")]
    [DefaultValue(typeof(LoadProgressType), "Line")]
    public LoadProgressType ProgressType
    {
      get { return this.progressType; }
      set
      {
        if (this.progressType == value)
          return;
        this.progressType = value;
        if (value == LoadProgressType.Line || value == LoadProgressType.Dot)
        {
          this.InitializeAngles();
          this.InitializeColors();
        }
        this.Invalidate();
      }
    }

    private int drawCircleRadius = 16;
    /// <summary>
    /// 画板半径大小(仅限Line、Dot、Arc、MultiArc)
    /// </summary>
    [Description("画板半径大小(仅限Line、Dot、Arc、MultiArc)")]
    [DefaultValue(16)]
    public int DrawCircleRadius
    {
      get
      {
        return this.drawCircleRadius;
      }
      set
      {
        if (this.drawCircleRadius == value && value < 1)
          return;
        this.drawCircleRadius = value;
        this.Invalidate();
      }
    }

    private int thickness = 4;
    /// <summary>
    /// 画笔粗细程度
    /// </summary>
    [Description("画笔粗细程度")]
    [DefaultValue(4)]
    public int Thickness
    {
      get
      {
        return this.thickness;
      }
      set
      {
        if (this.thickness == value || value < 1)
          return;
        this.thickness = value;
        this.Invalidate();
      }
    }

    private Color thicknessColor = Color.OliveDrab;
    /// <summary>
    /// 画笔颜色
    /// </summary>
    [Description("画笔颜色")]
    [DefaultValue(typeof(Color), "OliveDrab")]
    public Color ThicknessColor
    {
      get
      {
        return this.thicknessColor;
      }
      set
      {
        if (this.thicknessColor == value)
          return;
        this.thicknessColor = value;
        if (this.ProgressType == LoadProgressType.Line || this.ProgressType == LoadProgressType.Dot)
        {
          this.InitializeColors();
        }
        this.Invalidate();
      }
    }

    private int lineDotNumber = 8;
    /// <summary>
    /// 直线或圆点的数量(限制Line、Dot类型)
    /// </summary>
    [Description("直线或圆点的数量(限制Line、Dot类型)")]
    [DefaultValue(8)]
    public int LineDotNumber
    {
      get
      {
        return this.lineDotNumber;
      }
      set
      {
        if (this.lineDotNumber == value && value < 1)
          return;
        this.lineDotNumber = value;
        if (this.ProgressType == LoadProgressType.Line || this.ProgressType == LoadProgressType.Dot)
        {
          this.InitializeColors();
          this.InitializeAngles();
        }
        this.Invalidate();
      }
    }

    private int lineLenght = 8;
    /// <summary>
    /// 直线长度(仅限Line)
    /// </summary>
    [Description("直线长度(仅限Line)")]
    [DefaultValue(8)]
    public int LineLenght
    {
      get
      {
        return this.lineLenght;
      }
      set
      {
        if (this.lineLenght == value)
          return;
        this.lineLenght = value;
        this.Invalidate();
      }
    }

    private bool active = false;
    /// <summary>
    /// 是否激活
    /// </summary>
    [Description("是否激活")]
    [DefaultValue(false)]
    public bool Active
    {
      get
      {
        return this.active;
      }
      set
      {
        if (this.active == value)
          return;
        this.active = value;
        this.positiveProgress = 0;
        this.negativeProgress = 0;
        if (this.ProgressType == LoadProgressType.Line || this.ProgressType == LoadProgressType.Dot)
        {
          this.InitializeColors();
        }
        this.timer.Enabled = value;
        this.Invalidate();
      }
    }

    private bool textShow = false;
    /// <summary>
    /// 是否显示文本
    /// </summary>
    [Description("是否显示文本")]
    [DefaultValue(false)]
    public bool TextShow
    {
      get
      {
        return this.textShow;
      }
      set
      {
        if (this.textShow == value)
          return;
        this.textShow = value;
        this.Invalidate();
      }
    }

    /// <summary>
    /// 动画时间间隔
    /// </summary>
    [Description("动画时间间隔")]
    [DefaultValue(100)]
    public int Interval
    {
      get
      {
        return this.timer.Interval;
      }
      set
      {
        if (this.timer.Interval == value)
          return;
        this.timer.Interval = value;
      }
    }

    protected override Size DefaultSize
    {
      get
      {
        return new Size(40, 40);
      }
    }

    /// <summary>
    /// 定时器
    /// </summary>
    private Timer timer;
    /// <summary>
    /// 正向进度条值
    /// </summary>
    private int positiveProgress = 0;
    /// <summary>
    /// 负向进度条值
    /// </summary>
    private int negativeProgress = 0;
    /// <summary>
    /// 每条直线角度
    /// </summary>
    private List<double> lineAngles;
    /// <summary>
    /// 每条直线颜色
    /// </summary>
    private List<Color> lineColors;

    #endregion

    public LoadProgressExt()
    {
      this.SetStyle(ControlStyles.UserPaint, true);
      this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
      this.SetStyle(ControlStyles.ResizeRedraw, true);
      this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
      this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
      InitializeComponent();

      this.InitializeAngles();
      this.InitializeColors();

      this.timer = new Timer();
      this.timer.Interval = this.Interval;
      this.timer.Tick += new EventHandler(this.timer_Tick);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      base.OnPaint(e);

      Graphics g = e.Graphics;
      g.SmoothingMode = SmoothingMode.AntiAlias;
      g.CompositingQuality = CompositingQuality.HighQuality;
      g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;

      #region 图案
      switch (this.ProgressType)
      {
        case LoadProgressType.Line:
          {
            #region
            int node = this.positiveProgress;
            for (int i = 0; i < this.LineDotNumber; i++)
            {
              node = node % this.LineDotNumber;
              PointF point1 = this.GetCoordinate(e.ClipRectangle, this.DrawCircleRadius - this.LineLenght, this.lineAngles[node]);
              PointF point2 = this.GetCoordinate(e.ClipRectangle, this.DrawCircleRadius, this.lineAngles[node]);

              Pen line_pen = new Pen(this.lineColors[i], this.Thickness);
              line_pen.StartCap = LineCap.Round;
              line_pen.EndCap = LineCap.Round;
              g.DrawLine(line_pen, point1, point2);
              line_pen.Dispose();

              node++;
            }
            break;
            #endregion
          }
        case LoadProgressType.Dot:
          {
            #region
            int node = this.positiveProgress;
            for (int i = 0; i < this.LineDotNumber; i++)
            {
              node = node % this.LineDotNumber;
              PointF point = this.GetCoordinate(e.ClipRectangle, this.DrawCircleRadius, this.lineAngles[node]);

              SolidBrush dot_sb = new SolidBrush(this.lineColors[i]);
              g.FillEllipse(dot_sb, point.X - this.Thickness / 2, point.Y - this.Thickness / 2, this.Thickness, this.Thickness);
              dot_sb.Dispose();

              node++;
            }
            break;
            #endregion
          }
        case LoadProgressType.Arc:
          {
            #region
            int arc_w = this.DrawCircleRadius * 2;
            int arc_h = this.DrawCircleRadius * 2;
            Rectangle arc_rect = new Rectangle((e.ClipRectangle.Width - arc_w) / 2, (e.ClipRectangle.Height - arc_h) / 2, arc_w, arc_h);

            Pen arc_pen = new Pen(this.ThicknessColor, this.Thickness);
            g.DrawArc(arc_pen, arc_rect, this.positiveProgress, 290);
            arc_pen.Dispose();
            break;
            #endregion
          }
        case LoadProgressType.MultiArc:
          {
            #region
            int multiArc_w = this.DrawCircleRadius * 2;
            int multiArc_h = this.DrawCircleRadius * 2;
            Rectangle multiArc_rect = new Rectangle((e.ClipRectangle.Width - multiArc_w) / 2, (e.ClipRectangle.Height - multiArc_h) / 2, multiArc_w, multiArc_h);

            Pen multiArc_pen = new Pen(this.ThicknessColor, this.thickness);
            g.DrawArc(multiArc_pen, multiArc_rect, this.positiveProgress, 90);//外1弧度

            int out2 = this.positiveProgress + 180;
            if (out2 > 360)
              out2 -= 360;
            g.DrawArc(multiArc_pen, multiArc_rect, out2, 90);//外2弧度

            Rectangle interior_rect = new Rectangle(multiArc_rect.X + multiArc_rect.Width / 4, multiArc_rect.Y + multiArc_rect.Height / 4, multiArc_rect.Width / 2, multiArc_rect.Height / 2);
            int interior1 = this.negativeProgress + 90;
            if (interior1 > 360)
              interior1 -= 360;
            g.DrawArc(multiArc_pen, interior_rect, interior1, 90);//内1弧度

            int interior2 = interior1 + 180;
            if (interior2 > 360)
              interior2 -= 360;
            g.DrawArc(multiArc_pen, interior_rect, interior2, 90);//内2弧度

            multiArc_pen.Dispose();
            break;
            #endregion
          }
        case LoadProgressType.Bar:
          {
            #region
            int line_c = 9;//线条数量
            int bar_w = this.Thickness * line_c;
            int bar_h = this.Thickness * line_c;
            int bar_x = (e.ClipRectangle.Width - bar_w) / 2;
            int bar_y = (e.ClipRectangle.Height - bar_h) / 2;
            int line_min_h = bar_h / 2;

            Pen bar_pen = new Pen(this.ThicknessColor, this.Thickness);
            for (int i = 0; i < line_c; i++)
            {
              if (i % 2 == 0)
              {
                int num = i / 2;//只绘制偶数线条
                float differ = Math.Abs(this.positiveProgress - num);//指定线条与进度值线条的差用于计算缩放比例

                float reality_h = bar_h - differ * (bar_h / 4);//线条要绘制的高度
                if (reality_h < line_min_h)
                  reality_h = line_min_h;

                float line_x1 = bar_x + i * this.Thickness;
                float line_y1 = bar_y + (bar_h - reality_h) / 2;
                float line_x2 = line_x1;
                float line_y2 = bar_y + (bar_h - reality_h) / 2 + reality_h;
                g.DrawLine(bar_pen, line_x1, line_y1, line_x2, line_y2);
              }
            }
            bar_pen.Dispose();
            break;
            #endregion
          }
      }
      #endregion

      #region 文本
      if (this.TextShow && !String.IsNullOrWhiteSpace(this.Text))
      {
        SolidBrush text_sb = new SolidBrush(this.ForeColor);
        StringFormat text_sf = new StringFormat();
        text_sf.Alignment = StringAlignment.Center;
        text_sf.LineAlignment = StringAlignment.Far;
        text_sf.Trimming = StringTrimming.EllipsisCharacter;
        SizeF text_sizef = g.MeasureString(this.Text, this.Font);
        g.DrawString(this.Text, this.Font, text_sb, new RectangleF(0.0f, e.ClipRectangle.Bottom - text_sizef.Height, (float)e.ClipRectangle.Width, text_sizef.Height), text_sf);
      }
      #endregion

    }

    /// <summary>
    /// 进度定时器
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void timer_Tick(object sender, EventArgs e)
    {
      switch (this.ProgressType)
      {
        case LoadProgressType.Arc:
          {
            this.positiveProgress += 25;
            if (this.positiveProgress > 360)
              this.positiveProgress -= 360;
            break;
          }
        case LoadProgressType.MultiArc:
          {
            this.positiveProgress += 25;
            if (this.positiveProgress > 360)
              this.positiveProgress -= 360;

            this.negativeProgress -= 28;
            if (this.negativeProgress < 0)
              this.negativeProgress += 360;
            break;
          }
        case LoadProgressType.Bar:
          {
            this.positiveProgress += 1;
            if (this.positiveProgress > 4)
              this.positiveProgress -= 4;
            break;
          }
        default:
          {
            this.positiveProgress += 1;
            if (this.positiveProgress > this.LineDotNumber - 1)
              this.positiveProgress -= this.LineDotNumber - 1;
            break;
          }
      }
      this.Invalidate();
    }

    /// <summary>
    /// 初始化每条直线或圆点角度
    /// </summary>
    /// <returns></returns>
    private void InitializeAngles()
    {
      this.lineAngles = new List<double>();
      double avgAngle = 360d / (double)this.LineDotNumber;
      for (int i = 0; i < this.LineDotNumber; i++)
      {
        this.lineAngles.Add((i + 1) * avgAngle);
      }
    }

    /// <summary>
    /// 初始化每条直线或圆点颜色
    /// </summary>
    /// <returns></returns>
    private void InitializeColors()
    {
      this.lineColors = new List<Color>();

      byte transparent = 0;//颜色透明度
      byte transparentIncrement = (byte)(byte.MaxValue / this.LineDotNumber);//颜色透明度增量
      for (int i = 0; i < this.LineDotNumber; i++)
      {
        Color color = this.ThicknessColor;
        if (this.Active && i > 0)
        {
          transparent += transparentIncrement;
          transparent = Math.Min(transparent, byte.MaxValue);
          color = Color.FromArgb(transparent, Math.Min(this.ThicknessColor.R, byte.MaxValue), Math.Min(this.ThicknessColor.G, byte.MaxValue), Math.Min(this.ThicknessColor.B, byte.MaxValue));
        }
        this.lineColors.Add(color);
      }
    }

    /// <summary>
    /// 已绘图区中心坐标根据角度获取圆环上对应坐标
    /// </summary>
    /// <param name="rect">绘图区</param>
    /// <param name="radius">圆环半径</param>
    /// <param name="angle">角度</param>
    /// <returns>圆环上对应坐标</returns>
    private PointF GetCoordinate(Rectangle rect, int radius, double angle)
    {
      //经纬度转化成弧度(弧度=经纬度 * Math.PI / 180d);
      double dblAngle = angle * Math.PI / 180d;
      return new PointF(rect.Width / 2 + radius * (float)Math.Cos(dblAngle), rect.Height / 2 + radius * (float)Math.Sin(dblAngle));
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
        if (this.timer != null)
          this.timer.Dispose();
      }
      base.Dispose(disposing);
    }

    /// <summary>
    /// 直线或圆点的角度和颜色
    /// </summary>
    [Description("直线或圆点的角度和颜色")]
    public class AnglesColor
    {
      /// <summary>
      /// 直线或圆点的角度
      /// </summary>
      [Description("直线或圆点的角度")]
      public double Angles { get; set; }
      /// <summary>
      /// 直线或圆点的颜色
      /// </summary>
      [Description("直线或圆点的颜色")]
      public Color Color { get; set; }
    }

  }

  /// <summary>
  /// 加载进度条类型
  /// </summary>
  [Description("加载进度条类型")]
  public enum LoadProgressType
  {
    /// <summary>
    /// 直线
    /// </summary>
    Line,
    /// <summary>
    /// 圆球
    /// </summary>
    Dot,
    /// <summary>
    ///圆弧 
    /// </summary>
    Arc,
    /// <summary>
    /// 多圆弧
    /// </summary>
    MultiArc,
    /// <summary>
    /// 条形
    /// </summary>
    Bar
  }

 

 源码下载:加载等待控件.zip

加载等待控件----------WinForm控件开发系列

上一篇:C#中int[] 转 string[] 的代码


下一篇:温度计控件----------WinForm控件开发系列