(四十五)c#Winform自定义控件-水波图表

拥有回忆 提交于 2019-11-28 07:10:32

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 

麻烦博客下方点个【推荐】,谢谢

NuGet

Install-Package HZH_Controls

目录

https://www.cnblogs.com/bfyx/p/11364884.html

用处及效果

准备工作

这个用到GDI+画的,请先了解一下GDI+

还有用到了基类控件UCControlBase来控制圆角和背景色,如果还不了解请移步查看

(一)c#Winform自定义控件-基类控件

开始

添加一个类UCWaveWithSource ,继承UCControlBase

添加属性

  private int m_waveActualWidth = 50;            private int m_waveWidth = 50;            [Description("波形宽度"), Category("自定义")]          public int WaveWidth          {              get { return m_waveWidth; }              set              {                  if (value <= 0)                      return;                  m_waveWidth = value;                  ResetWaveCount();                  Refresh();              }          }            private int m_sleepTime = 1000;          /// <summary>          /// 波运行速度(运行时间间隔,毫秒)          /// </summary>          [Description("运行速度(运行时间间隔,毫秒)"), Category("自定义")]          public int SleepTime          {              get { return m_sleepTime; }              set              {                  if (value <= 0)                      return;                  m_sleepTime = value;                  if (timer != null)                  {                      timer.Enabled = false;                      timer.Interval = value;                      timer.Enabled = true;                  }              }          }            private float m_lineTension = 0.5f;          /// <summary>          /// 线弯曲程度          /// </summary>          [Description("线弯曲程度(0-1)"), Category("自定义")]          public float LineTension          {              get { return m_lineTension; }              set              {                  if (!(value >= 0 && value <= 1))                  {                      return;                  }                  m_lineTension = value;                  Refresh();              }          }            private Color m_lineColor = Color.FromArgb(150, 73, 119, 232);            [Description("曲线颜色"), Category("自定义")]          public Color LineColor          {              get { return m_lineColor; }              set              {                  m_lineColor = value;                  Refresh();                }          }            private Color m_gridLineColor = Color.FromArgb(50, 73, 119, 232);            [Description("网格线颜色"), Category("自定义")]          public Color GridLineColor          {              get { return m_gridLineColor; }              set              {                  m_gridLineColor = value;                  Refresh();              }          }            private Color m_gridLineTextColor = Color.FromArgb(150, 73, 119, 232);            [Description("网格文本颜色"), Category("自定义")]          public Color GridLineTextColor          {              get { return m_gridLineTextColor; }              set              {                  m_gridLineTextColor = value;                  Refresh();              }          }            public override Font Font          {              get              {                  return base.Font;              }              set              {                  base.Font = value;              }          }          /// <summary>          /// 数据源,用以缓存所有需要显示的数据          /// </summary>          List<KeyValuePair<string, double>> m_dataSource = new List<KeyValuePair<string, double>>();          /// <summary>          /// 当前需要显示的数据          /// </summary>          List<KeyValuePair<string, double>> m_currentSource = new List<KeyValuePair<string, double>>();          Timer timer = new Timer();          /// <summary>          /// 画图区域          /// </summary>          Rectangle m_drawRect;            int m_waveCount = 0;

构造函数中初始化一下样式

 1         public UCWaveWithSource()   2         {   3             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);   4             this.SetStyle(ControlStyles.DoubleBuffer, true);   5             this.SetStyle(ControlStyles.ResizeRedraw, true);   6             this.SetStyle(ControlStyles.Selectable, true);   7             this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);   8             this.SetStyle(ControlStyles.UserPaint, true);   9   10             this.SizeChanged += UCWaveWithSource_SizeChanged;  11             this.IsShowRect = true;  12             this.RectColor = Color.FromArgb(232, 232, 232);  13             this.FillColor = Color.FromArgb(197, 229, 250);  14             this.RectWidth = 1;  15             this.ConerRadius = 10;  16             this.IsRadius = true;  17             this.Size = new Size(300, 200);  18   19             timer.Interval = m_sleepTime;  20             timer.Tick += timer_Tick;  21             this.VisibleChanged += UCWave_VisibleChanged;  22         }

一个数据添加的函数

1  /// <summary>  2         /// 添加需要显示的数据  3         /// </summary>  4         /// <param name="key">名称</param>  5         /// <param name="value">值</param>  6         public void AddSource(string key, double value)  7         {  8             m_dataSource.Add(new KeyValuePair<string, double>(key, value));  9         }

重绘

 1 protected override void OnPaint(PaintEventArgs e)   2         {   3             base.OnPaint(e);   4             var g = e.Graphics;   5             g.SetGDIHigh();   6    7             int intLineSplit = m_drawRect.Height / 4;   8             for (int i = 0; i <= 4; i++)   9             {  10                 var pen = new Pen(new SolidBrush(m_gridLineColor), 1);  11                 // pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;  12                 g.DrawLine(pen, m_drawRect.Left, m_drawRect.Bottom - 1 - i * intLineSplit, m_drawRect.Right, m_drawRect.Bottom - 1 - i * intLineSplit);  13             }  14   15             if (m_currentSource == null || m_currentSource.Count <= 0)  16             {  17                 for (int i = 0; i <= 4; i++)  18                 {  19                     string strText = (100 / 4 * i).ToString();  20                     System.Drawing.SizeF _numSize = g.MeasureString(strText, this.Font);  21                     g.DrawString(strText, Font, new SolidBrush(m_gridLineTextColor), m_drawRect.Left - _numSize.Width - 1, m_drawRect.Bottom - 1 - i * intLineSplit - (_numSize.Height / 2));  22                 }  23                 return;  24             }  25             List<Point> lst1 = new List<Point>();  26             double dblValue = m_currentSource.Max(p => p.Value);  27             int intValue = (int)dblValue;  28             int intDivisor = ("1".PadRight(intValue.ToString().Length - 1, '0')).ToInt();  29             if (intDivisor < 100)  30                 intDivisor = 100;  31             int intTop = intValue;  32             if (intValue % intDivisor != 0)  33             {  34                 intTop = (intValue / intDivisor + 1) * intDivisor;  35             }  36             if (intTop == 0)  37                 intTop = 100;  38   39             for (int i = 0; i <= 4; i++)  40             {  41                 string strText = (intTop / 4 * i).ToString();  42                 System.Drawing.SizeF _numSize = g.MeasureString(strText, this.Font);  43                 g.DrawString(strText, Font, new SolidBrush(m_gridLineTextColor), m_drawRect.Left - _numSize.Width - 1, m_drawRect.Bottom - 1 - i * intLineSplit - (_numSize.Height / 2));  44             }  45   46             int intEndX = 0;  47             int intEndY = 0;  48             for (int i = 0; i < m_currentSource.Count; i++)  49             {  50                 intEndX = i * m_waveActualWidth + m_drawRect.X;  51                 intEndY = m_drawRect.Bottom - 1 - (int)(m_currentSource[i].Value / intTop * m_drawRect.Height);  52                 lst1.Add(new Point(intEndX, intEndY));  53                 if (!string.IsNullOrEmpty(m_currentSource[i].Key))  54                 {  55                     System.Drawing.SizeF _numSize = g.MeasureString(m_currentSource[i].Key, this.Font);  56                     int txtX = intEndX - (int)(_numSize.Width / 2) + 1;  57                     g.DrawString(m_currentSource[i].Key, Font, new SolidBrush(m_gridLineTextColor), new PointF(txtX, m_drawRect.Bottom + 5));  58                 }  59             }  60   61             int intFirstY = m_drawRect.Bottom - 1 - (int)(m_currentSource[0].Value / intTop * m_drawRect.Height);  62   63   64             GraphicsPath path1 = new GraphicsPath();  65             path1.AddCurve(lst1.ToArray(), m_lineTension);  66             g.DrawPath(new Pen(new SolidBrush(m_lineColor), 1), path1);  67   68         }

辅助函数

 1 /// <summary>   2         /// 得到当前需要画图的数据   3         /// </summary>   4         /// <returns></returns>   5         private List<KeyValuePair<string, double>> GetCurrentList()   6         {   7             if (m_dataSource.Count < m_waveCount)   8             {   9                 int intCount = m_waveCount - m_dataSource.Count;  10                 for (int i = 0; i < intCount; i++)  11                 {  12                     m_dataSource.Add(new KeyValuePair<string, double>("", 0));  13                 }  14             }  15   16             var lst = m_dataSource.GetRange(0, m_waveCount);  17             if (lst.Count == 1)  18                 lst.Insert(0, new KeyValuePair<string, double>("", 0));  19             return lst;  20         }  21   22         /// <summary>  23         /// 计算需要显示的个数  24         /// </summary>  25         private void ResetWaveCount()  26         {  27             m_waveCount = m_drawRect.Width / m_waveWidth;  28             m_waveActualWidth = m_waveWidth + (m_drawRect.Width % m_waveWidth) / m_waveCount;  29             m_waveCount++;  30             if (m_dataSource.Count < m_waveCount)  31             {  32                 int intCount = m_waveCount - m_dataSource.Count;  33                 for (int i = 0; i < intCount; i++)  34                 {  35                     m_dataSource.Insert(0, new KeyValuePair<string, double>("", 0));  36                 }  37             }  38         }

完整代码

  1 using System;    2 using System.Collections.Generic;    3 using System.ComponentModel;    4 using System.Drawing;    5 using System.Drawing.Drawing2D;    6 using System.Linq;    7 using System.Text;    8 using System.Windows.Forms;    9    10 namespace HZH_Controls.Controls   11 {   12     public class UCWaveWithSource : UCControlBase   13     {   14         private int m_waveActualWidth = 50;   15    16         private int m_waveWidth = 50;   17    18         [Description("波形宽度"), Category("自定义")]   19         public int WaveWidth   20         {   21             get { return m_waveWidth; }   22             set   23             {   24                 if (value <= 0)   25                     return;   26                 m_waveWidth = value;   27                 ResetWaveCount();   28                 Refresh();   29             }   30         }   31    32         private int m_sleepTime = 1000;   33         /// <summary>   34         /// 波运行速度(运行时间间隔,毫秒)   35         /// </summary>   36         [Description("运行速度(运行时间间隔,毫秒)"), Category("自定义")]   37         public int SleepTime   38         {   39             get { return m_sleepTime; }   40             set   41             {   42                 if (value <= 0)   43                     return;   44                 m_sleepTime = value;   45                 if (timer != null)   46                 {   47                     timer.Enabled = false;   48                     timer.Interval = value;   49                     timer.Enabled = true;   50                 }   51             }   52         }   53    54         private float m_lineTension = 0.5f;   55         /// <summary>   56         /// 线弯曲程度   57         /// </summary>   58         [Description("线弯曲程度(0-1)"), Category("自定义")]   59         public float LineTension   60         {   61             get { return m_lineTension; }   62             set   63             {   64                 if (!(value >= 0 && value <= 1))   65                 {   66                     return;   67                 }   68                 m_lineTension = value;   69                 Refresh();   70             }   71         }   72    73         private Color m_lineColor = Color.FromArgb(150, 73, 119, 232);   74    75         [Description("曲线颜色"), Category("自定义")]   76         public Color LineColor   77         {   78             get { return m_lineColor; }   79             set   80             {   81                 m_lineColor = value;   82                 Refresh();   83    84             }   85         }   86    87         private Color m_gridLineColor = Color.FromArgb(50, 73, 119, 232);   88    89         [Description("网格线颜色"), Category("自定义")]   90         public Color GridLineColor   91         {   92             get { return m_gridLineColor; }   93             set   94             {   95                 m_gridLineColor = value;   96                 Refresh();   97             }   98         }   99   100         private Color m_gridLineTextColor = Color.FromArgb(150, 73, 119, 232);  101   102         [Description("网格文本颜色"), Category("自定义")]  103         public Color GridLineTextColor  104         {  105             get { return m_gridLineTextColor; }  106             set  107             {  108                 m_gridLineTextColor = value;  109                 Refresh();  110             }  111         }  112   113         public override Font Font  114         {  115             get  116             {  117                 return base.Font;  118             }  119             set  120             {  121                 base.Font = value;  122             }  123         }  124         /// <summary>  125         /// 数据源,用以缓存所有需要显示的数据  126         /// </summary>  127         List<KeyValuePair<string, double>> m_dataSource = new List<KeyValuePair<string, double>>();  128         /// <summary>  129         /// 当前需要显示的数据  130         /// </summary>  131         List<KeyValuePair<string, double>> m_currentSource = new List<KeyValuePair<string, double>>();  132         Timer timer = new Timer();  133         /// <summary>  134         /// 画图区域  135         /// </summary>  136         Rectangle m_drawRect;  137   138         int m_waveCount = 0;  139         public UCWaveWithSource()  140         {  141             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);  142             this.SetStyle(ControlStyles.DoubleBuffer, true);  143             this.SetStyle(ControlStyles.ResizeRedraw, true);  144             this.SetStyle(ControlStyles.Selectable, true);  145             this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);  146             this.SetStyle(ControlStyles.UserPaint, true);  147   148             this.SizeChanged += UCWaveWithSource_SizeChanged;  149             this.IsShowRect = true;  150             this.RectColor = Color.FromArgb(232, 232, 232);  151             this.FillColor = Color.FromArgb(197, 229, 250);  152             this.RectWidth = 1;  153             this.ConerRadius = 10;  154             this.IsRadius = true;  155             this.Size = new Size(300, 200);  156   157             timer.Interval = m_sleepTime;  158             timer.Tick += timer_Tick;  159             this.VisibleChanged += UCWave_VisibleChanged;  160         }  161   162        163         /// <summary>  164         /// 添加需要显示的数据  165         /// </summary>  166         /// <param name="key">名称</param>  167         /// <param name="value">值</param>  168         public void AddSource(string key, double value)  169         {  170             m_dataSource.Add(new KeyValuePair<string, double>(key, value));  171         }  172   173         void UCWave_VisibleChanged(object sender, EventArgs e)  174         {  175             if (!DesignMode)  176             {  177                 timer.Enabled = this.Visible;  178             }  179         }  180   181         void timer_Tick(object sender, EventArgs e)  182         {  183             m_currentSource = GetCurrentList();  184             m_dataSource.RemoveAt(0);  185             this.Refresh();  186         }  187         void UCWaveWithSource_SizeChanged(object sender, EventArgs e)  188         {  189             m_drawRect = new Rectangle(60, 20, this.Width - 80, this.Height - 60);  190             ResetWaveCount();  191         }  192   193         protected override void OnPaint(PaintEventArgs e)  194         {  195             base.OnPaint(e);  196             var g = e.Graphics;  197             g.SetGDIHigh();  198   199             int intLineSplit = m_drawRect.Height / 4;  200             for (int i = 0; i <= 4; i++)  201             {  202                 var pen = new Pen(new SolidBrush(m_gridLineColor), 1);  203                 // pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;  204                 g.DrawLine(pen, m_drawRect.Left, m_drawRect.Bottom - 1 - i * intLineSplit, m_drawRect.Right, m_drawRect.Bottom - 1 - i * intLineSplit);  205             }  206   207             if (m_currentSource == null || m_currentSource.Count <= 0)  208             {  209                 for (int i = 0; i <= 4; i++)  210                 {  211                     string strText = (100 / 4 * i).ToString();  212                     System.Drawing.SizeF _numSize = g.MeasureString(strText, this.Font);  213                     g.DrawString(strText, Font, new SolidBrush(m_gridLineTextColor), m_drawRect.Left - _numSize.Width - 1, m_drawRect.Bottom - 1 - i * intLineSplit - (_numSize.Height / 2));  214                 }  215                 return;  216             }  217             List<Point> lst1 = new List<Point>();  218             double dblValue = m_currentSource.Max(p => p.Value);  219             int intValue = (int)dblValue;  220             int intDivisor = ("1".PadRight(intValue.ToString().Length - 1, '0')).ToInt();  221             if (intDivisor < 100)  222                 intDivisor = 100;  223             int intTop = intValue;  224             if (intValue % intDivisor != 0)  225             {  226                 intTop = (intValue / intDivisor + 1) * intDivisor;  227             }  228             if (intTop == 0)  229                 intTop = 100;  230   231             for (int i = 0; i <= 4; i++)  232             {  233                 string strText = (intTop / 4 * i).ToString();  234                 System.Drawing.SizeF _numSize = g.MeasureString(strText, this.Font);  235                 g.DrawString(strText, Font, new SolidBrush(m_gridLineTextColor), m_drawRect.Left - _numSize.Width - 1, m_drawRect.Bottom - 1 - i * intLineSplit - (_numSize.Height / 2));  236             }  237   238             int intEndX = 0;  239             int intEndY = 0;  240             for (int i = 0; i < m_currentSource.Count; i++)  241             {  242                 intEndX = i * m_waveActualWidth + m_drawRect.X;  243                 intEndY = m_drawRect.Bottom - 1 - (int)(m_currentSource[i].Value / intTop * m_drawRect.Height);  244                 lst1.Add(new Point(intEndX, intEndY));  245                 if (!string.IsNullOrEmpty(m_currentSource[i].Key))  246                 {  247                     System.Drawing.SizeF _numSize = g.MeasureString(m_currentSource[i].Key, this.Font);  248                     int txtX = intEndX - (int)(_numSize.Width / 2) + 1;  249                     g.DrawString(m_currentSource[i].Key, Font, new SolidBrush(m_gridLineTextColor), new PointF(txtX, m_drawRect.Bottom + 5));  250                 }  251             }  252   253             int intFirstY = m_drawRect.Bottom - 1 - (int)(m_currentSource[0].Value / intTop * m_drawRect.Height);  254   255   256             GraphicsPath path1 = new GraphicsPath();  257             path1.AddCurve(lst1.ToArray(), m_lineTension);  258             g.DrawPath(new Pen(new SolidBrush(m_lineColor), 1), path1);  259   260         }  261         /// <summary>  262         /// 得到当前需要画图的数据  263         /// </summary>  264         /// <returns></returns>  265         private List<KeyValuePair<string, double>> GetCurrentList()  266         {  267             if (m_dataSource.Count < m_waveCount)  268             {  269                 int intCount = m_waveCount - m_dataSource.Count;  270                 for (int i = 0; i < intCount; i++)  271                 {  272                     m_dataSource.Add(new KeyValuePair<string, double>("", 0));  273                 }  274             }  275   276             var lst = m_dataSource.GetRange(0, m_waveCount);  277             if (lst.Count == 1)  278                 lst.Insert(0, new KeyValuePair<string, double>("", 0));  279             return lst;  280         }  281   282         /// <summary>  283         /// 计算需要显示的个数  284         /// </summary>  285         private void ResetWaveCount()  286         {  287             m_waveCount = m_drawRect.Width / m_waveWidth;  288             m_waveActualWidth = m_waveWidth + (m_drawRect.Width % m_waveWidth) / m_waveCount;  289             m_waveCount++;  290             if (m_dataSource.Count < m_waveCount)  291             {  292                 int intCount = m_waveCount - m_dataSource.Count;  293                 for (int i = 0; i < intCount; i++)  294                 {  295                     m_dataSource.Insert(0, new KeyValuePair<string, double>("", 0));  296                 }  297             }  298         }  299     }  300 }
View Code

 

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!