温度计控件----------WinForm控件开发系列

温度计控件----------WinForm控件开发系列

 /// <summary>
  /// 温度计控件
  /// </summary>
  [ToolboxItem(true)]
  [DefaultProperty("Value")]
  [DefaultEvent("ValueChanged")]
  [Description("温度计控件")]
  public partial class ThermometerExt : Control
  {
    public delegate void EventHandler(object sender, TemperatureEventArgs e);

    private readonly int angle = 45;
    private readonly int paddingBottom = 10;
    private readonly int paddingTop = 10;
    private readonly int paddingRight = 6;
    private readonly int paddingLeft = 6;
    private readonly int lineExtent = 10;

    #region

    private event EventHandler valueChanged;
    /// <summary>
    /// 温度值更改事件
    /// </summary>
    [Description("温度值更改事件")]
    public event EventHandler ValueChanged
    {
      add { this.valueChanged += value; }
      remove { this.valueChanged -= value; }
    }

    private int circleRadius = 10;
    /// <summary>
    /// 温度计圆点半径
    /// </summary>
    [DefaultValue(10)]
    [Description("温度计圆点半径")]
    public int CircleRadius
    {
      get { return this.circleRadius; }
      set
      {
        if (this.circleRadius == value)
          return;
        this.circleRadius = value;
        this.Invalidate();
      }
    }

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

    private bool scaleShow = true;
    /// <summary>
    /// 是否显示刻度线
    /// </summary>
    [DefaultValue(true)]
    [Description("是否显示刻度线")]
    public bool ScaleShow
    {
      get { return this.scaleShow; }
      set
      {
        if (this.scaleShow == value)
          return;
        this.scaleShow = value;
        this.Invalidate();
      }
    }

    private ScaleDirection scaleDirectionType = ScaleDirection.Left;
    /// <summary>
    /// 刻度线显示位置
    /// </summary>
    [DefaultValue(ScaleDirection.Left)]
    [Description("刻度线显示位置")]
    public ScaleDirection ScaleDirectionType
    {
      get { return this.scaleDirectionType; }
      set
      {
        if (this.scaleDirectionType == value)
          return;
        this.scaleDirectionType = value;
        this.Invalidate();
      }
    }

    private Color scaleLineColor = Color.DimGray;
    /// <summary>
    /// 刻度线颜色
    /// </summary>
    [DefaultValue(typeof(Color), "DimGray")]
    [Description("刻度线颜色")]
    public Color ScaleLineColor
    {
      get { return this.scaleLineColor; }
      set
      {
        if (this.scaleLineColor == value)
          return;
        this.scaleLineColor = value;
        this.Invalidate();
      }
    }

    private int scaleCutCount = 5;
    /// <summary>
    /// 一个间隔刻度分割成多少个子刻度
    /// </summary>
    [DefaultValue(5)]
    [Description("一个间隔刻度分割成多少个子刻度")]
    public int ScaleCutCount
    {
      get { return this.scaleCutCount; }
      set
      {
        if (this.scaleCutCount == value || value < 1)
          return;
        this.scaleCutCount = value;
        this.Invalidate();
      }
    }

    private Color scaleCutLineColor = Color.DimGray;
    /// <summary>
    /// 子刻度颜色
    /// </summary>
    [DefaultValue(typeof(Color), "DimGray")]
    [Description("子刻度颜色")]
    public Color TcaleCutLineColor
    {
      get { return this.scaleCutLineColor; }
      set
      {
        if (this.scaleCutLineColor == value)
          return;
        this.scaleCutLineColor = value;
        this.Invalidate();
      }
    }

    private bool scaleTextShow = true;
    /// <summary>
    /// 是否显示刻度线值
    /// </summary>
    [DefaultValue(true)]
    [Description("是否显示刻度线值")]
    public bool ScaleTextShow
    {
      get { return this.scaleTextShow; }
      set
      {
        if (this.scaleTextShow == value)
          return;
        this.scaleTextShow = value;
        this.Invalidate();
      }
    }

    private Font scaleTextFont = new Font("宋体", 10);
    /// <summary>
    /// 刻度线值字体
    /// </summary>
    [DefaultValue(typeof(Font), "宋体, 10pt")]
    [Description("刻度线值字体")]
    public Font ScaleTextFont
    {
      get { return this.scaleTextFont; }
      set
      {
        if (this.scaleTextFont == value)
          return;
        this.scaleTextFont = value;
        this.Invalidate();
      }
    }

    private Color scaleTextColor = Color.DimGray;
    /// <summary>
    /// 刻度线文字颜色
    /// </summary>
    [DefaultValue(typeof(Color), "DimGray")]
    [Description("刻度线文字颜色")]
    public Color ScaleTextColor
    {
      get { return this.scaleTextColor; }
      set
      {
        if (this.scaleTextColor == value)
          return;
        this.scaleTextColor = value;
        this.Invalidate();
      }
    }

    private float intervalValue = 10f;
    /// <summary>
    /// 间隔刻度大小
    /// </summary>
    [DefaultValue(10f)]
    [Description("间隔刻度大小")]
    public float IntervalValue
    {
      get { return this.intervalValue; }
      set
      {
        if (this.intervalValue == value)
          return;
        this.intervalValue = value;
        this.Invalidate();
      }
    }

    private int borderWidth = 3;
    /// <summary>
    /// 边框宽度
    /// </summary>
    [DefaultValue(3)]
    [Description("边框宽度")]
    public int BorderWidth
    {
      get { return this.borderWidth; }
      set
      {
        if (this.borderWidth == value)
          return;
        this.borderWidth = value;
        this.Invalidate();
      }
    }

    private Color borderColor = Color.DimGray;
    /// <summary>
    /// 边框颜色
    /// </summary>
    [DefaultValue(typeof(Color), "DimGray")]
    [Description("边框颜色")]
    public Color BorderColor
    {
      get { return this.borderColor; }
      set
      {
        if (this.borderColor == value)
          return;
        this.borderColor = value;
        this.Invalidate();
      }
    }

    private Color valueColor = Color.Tomato;
    /// <summary>
    /// 值颜色
    /// </summary>
    [DefaultValue(typeof(Color), "Tomato")]
    [Description("值颜色")]
    public Color ValueColor
    {
      get { return this.valueColor; }
      set
      {
        if (this.valueColor == value)
          return;
        this.valueColor = value;
        this.Invalidate();
      }
    }

    private float maxValue = 100f;
    /// <summary>
    /// 最大值
    /// </summary>
    [DefaultValue(100f)]
    [Description("最大值")]
    public float MaxValue
    {
      get { return this.maxValue; }
      set
      {
        if (this.maxValue == value || value < this.minValue)
          return;
        this.maxValue = value;
        this.Invalidate();
      }
    }

    private float minValue = -20f;
    /// <summary>
    /// 最小值
    /// </summary>
    [DefaultValue(-20f)]
    [Description("最小值")]
    public float MinValue
    {
      get { return this.minValue; }
      set
      {
        if (this.minValue == value || value > this.maxValue)
          return;
        this.minValue = value;
        this.Invalidate();
      }
    }

    private float value = 0f;
    /// <summary>
    /// 当前值
    /// </summary>
    [DefaultValue(0f)]
    [Description("当前值")]
    public float Value
    {
      get { return this.value; }
      set
      {
        if (this.value == value)
          return;
        this.value = value;
        if (this.valueChanged != null)
        {
          this.valueChanged(this, new TemperatureEventArgs() { Value = value });
        }
        this.Invalidate();
      }
    }

    public new string Text
    {
      get
      {
        return base.Text;
      }
      set
      {
        if (base.Text == value)
          return;
        base.Text = value;
        this.Invalidate();
      }
    }

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

    #endregion

    public ThermometerExt()
    {
      SetStyle(ControlStyles.UserPaint, true);
      SetStyle(ControlStyles.AllPaintingInWmPaint, true);
      SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
      SetStyle(ControlStyles.ResizeRedraw, true);
      SetStyle(ControlStyles.SupportsTransparentBackColor, true);

      InitializeComponent();
    }

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

      Graphics g = e.Graphics;
      SmoothingMode sm = g.SmoothingMode;
      g.SmoothingMode = SmoothingMode.AntiAlias;

      int diameter = this.circleRadius * 2;
      Rectangle bounds_rect = e.ClipRectangle;
      RectangleF text_rect = new RectangleF(0, 0, 0, 0);//文本rect
      if (this.TextShow)
      {
        SizeF text_size = g.MeasureString(this.Text, this.Font);
        text_rect.Width = text_size.Width;
        text_rect.Height = text_size.Height;
        text_rect.X = bounds_rect.X + ((float)bounds_rect.Width - text_size.Width) / 2;
        text_rect.Y = bounds_rect.Bottom - text_size.Height;
      }
      float scale_width = (float)Math.Sqrt(Math.Pow(this.CircleRadius, 2) * 2);//温度计刻度部分rect的宽度
      float scale_height = bounds_rect.Height - this.paddingBottom - text_rect.Height - this.CircleRadius - scale_width / 2 - scale_width / 2 - this.paddingTop;
      Rectangle circle_rect = new Rectangle(this.paddingLeft, bounds_rect.Bottom - this.paddingBottom - (int)text_rect.Height - diameter, diameter, diameter);//圆的rect
      if (this.scaleDirectionType == ScaleDirection.Right)
      {
        circle_rect.X = bounds_rect.Right - this.paddingRight - diameter;
      }
      RectangleF scale_rect = new RectangleF(circle_rect.X + (this.circleRadius - scale_width / 2), bounds_rect.Y + this.paddingTop + scale_width / 2, scale_width, scale_height);//温度计刻度部分rect

      float sumValue = 0;
      if (this.MaxValue > 0 && this.MinValue >= 0)
      {
        sumValue = this.MaxValue - this.MinValue;
      }
      else if (this.MaxValue > 0 && this.MinValue < 0)
      {
        sumValue = this.MaxValue - this.MinValue;
      }
      else if (this.MaxValue < 0 && this.MinValue < 0)
      {
        sumValue = Math.Abs(this.MinValue) - Math.Abs(this.MaxValue);
      }

      #region Text
      if (this.TextShow)
      {
        SolidBrush text_sb = new SolidBrush(this.ForeColor);
        g.DrawString(this.Text, this.Font, text_sb, text_rect.X, text_rect.Y);
        text_sb.Dispose();
      }
      #endregion

      #region 值背景
      SolidBrush value_sb = new SolidBrush(this.ValueColor);
      GraphicsPath value_gp = new GraphicsPath();
      value_gp.AddArc(circle_rect, 270 + (90 - this.angle), 360 - (90 - this.angle) * 2);
      if (this.Value < this.MaxValue)
      {
        float x = circle_rect.X + (circle_rect.Width - scale_width) / 2;
        float y = scale_rect.Bottom - scale_height / (sumValue / (this.Value + Math.Abs(this.MinValue)));
        value_gp.AddLine(x, y, x + scale_width, y);
      }
      else
      {
        float x = circle_rect.X + (circle_rect.Width - scale_width) / 2;
        float y = this.paddingTop;
        value_gp.AddArc(new RectangleF(x, y, scale_width, scale_width), 180, 180);
      }
      value_gp.CloseFigure();
      g.FillPath(value_sb, value_gp);
      value_gp.Dispose();
      value_sb.Dispose();
      #endregion

      #region 边框
      Pen border_pen = new Pen(this.BorderColor, this.BorderWidth);
      GraphicsPath border_gp = new GraphicsPath();
      border_gp.AddArc(circle_rect, 270 + (90 - this.angle), 360 - (90 - this.angle) * 2);
      border_gp.AddArc(new RectangleF(circle_rect.X + (circle_rect.Width - scale_width) / 2, this.paddingTop, scale_width, scale_width), 180, 180);
      border_gp.CloseFigure();
      g.DrawPath(border_pen, border_gp);
      border_gp.Dispose();
      border_pen.Dispose();
      #endregion

      g.SmoothingMode = sm;

      #region  刻度

      if (this.ScaleShow)
      {
        Pen scaleLine_pen = new Pen(this.ScaleLineColor, 2);
        Pen scaleCutLine_pen = new Pen(this.scaleCutLineColor, 1);
        SolidBrush scaleLineText_sb = new SolidBrush(this.ScaleTextColor);

        float maxValueYU = Math.Abs(this.MaxValue % this.IntervalValue);
        float minValueYU = Math.Abs(this.MinValue % this.IntervalValue);
        int count = 0;
        float v = sumValue;
        if (maxValueYU != 0)
          v -= maxValueYU;
        if (minValueYU != 0)
          v -= minValueYU;
        count = (int)(v / this.IntervalValue);//分了多少个间隔

        //count*pixel+(maxValueYU/this.TickFrequency)*pixel+(minValueYU/this.TickFrequency)*pixel=scale_height;
        float pixel = scale_height / (count + maxValueYU / this.IntervalValue + minValueYU / this.IntervalValue);//一个间隔代表像素

        if (maxValueYU != 0)
          count++;
        if (minValueYU != 0)
          count++;
        float line_y = scale_rect.Bottom;
        float str = 0;
        for (int i = 0; i <= count; i++)
        {
          if (i == 0)
          {
            str = this.MinValue;
          }
          else if (i == 1)
          {
            if (minValueYU != 0)
            {
              line_y -= (minValueYU / this.IntervalValue) * pixel;
              str += minValueYU;
            }
            else
            {
              line_y -= pixel;
              str += this.IntervalValue;
            }
          }
          else if (i == count)
          {
            if (maxValueYU != 0)
            {
              line_y -= (maxValueYU / this.IntervalValue) * pixel;
              str += maxValueYU;
            }
            else
            {
              line_y -= pixel;
              str += this.IntervalValue;
            }
          }
          else
          {
            line_y -= pixel;
            str += this.IntervalValue;
          }
          float line_x1 = scale_rect.Right;
          float line_x2 = scale_rect.Right + this.lineExtent;
          if (this.scaleDirectionType == ScaleDirection.Right)
          {
            line_x1 = scale_rect.X - this.lineExtent;
            line_x2 = scale_rect.X;
          }
          g.DrawLine(scaleLine_pen, line_x1, line_y, line_x2, line_y);


          #region 子刻度线
          if (this.ScaleCutCount > 1)
          {
            float group_y = line_y;
            if (!((i == 0) || (i == 1 && minValueYU != 0) || (i == count && maxValueYU != 0)))//排除第一个和不完整的
            {
              for (int j = 0; j < this.ScaleCutCount - 1; j++)
              {
                group_y += pixel / this.ScaleCutCount;
                float group_x1 = scale_rect.Right;
                float group_x2 = scale_rect.Right + this.lineExtent / 2;
                if (this.scaleDirectionType == ScaleDirection.Right)
                {
                  group_x1 = scale_rect.X - this.lineExtent / 2;
                  group_x2 = scale_rect.X;
                }
                g.DrawLine(scaleCutLine_pen, group_x1, group_y, group_x2, group_y);
              }
            }
          }
          #endregion

          #region  刻度值
          if (this.scaleTextShow)
          {
            SizeF str_size = g.MeasureString(str.ToString(), this.Font);
            float text_x1 = line_x2;
            if (this.scaleDirectionType == ScaleDirection.Right)
            {
              text_x1 = scale_rect.X - this.lineExtent - str_size.Width;
            }
            g.DrawString(str.ToString(), this.ScaleTextFont, scaleLineText_sb, text_x1, line_y - str_size.Height / 2);
          }
          #endregion

        }
        scaleLineText_sb.Dispose();
        scaleCutLine_pen.Dispose();
        scaleLine_pen.Dispose();
      }
      #endregion


    }

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

    /// <summary>
    /// 刻度线显示位置
    /// </summary>
    [Description("刻度线显示位置")]
    public enum ScaleDirection
    {
      /// <summary>
      ////// </summary>
      Left,
      /// <summary>
      ////// </summary>
      Right
    }

    /// <summary>
    /// 温度计事件参数
    /// </summary>
    [Description("温度计事件参数")]
    public class TemperatureEventArgs : EventArgs
    {
      /// <summary>
      /// 温度值
      /// </summary>
      [Description("温度值")]
      public float Value { get; set; }
    }
  }

 

 源码下载:温度计控件.zip

温度计控件----------WinForm控件开发系列

上一篇:加载等待控件----------WinForm控件开发系列


下一篇:雷达扫描控件----------WinForm控件开发系列