(四十五)c#Winform自定义控件-水波图表-HZHControls
发布日期:2021-05-09 00:53:05 浏览次数:28 分类:博客文章

本文共 17783 字,大约阅读时间需要 59 分钟。

官网

前提

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

GitHub:

码云:

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

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

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

NuGet

Install-Package HZH_Controls

目录

用处及效果

准备工作

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

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

开始

添加一个类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;        ///         /// 波运行速度(运行时间间隔,毫秒)        ///         [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;        ///         /// 线弯曲程度        ///         [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;            }        }        ///         /// 数据源,用以缓存所有需要显示的数据        ///         List
> m_dataSource = new List
>(); ///
/// 当前需要显示的数据 /// List
> m_currentSource = new List
>(); Timer timer = new Timer(); ///
/// 画图区域 /// 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  /// 2         /// 添加需要显示的数据3         /// 4         /// 名称5         /// 值6         public void AddSource(string key, double value)7         {8             m_dataSource.Add(new KeyValuePair
(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
lst1 = new List
();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 ///  2         /// 得到当前需要画图的数据 3         ///  4         /// 
5 private List
> 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
("", 0));13 }14 }15 16 var lst = m_dataSource.GetRange(0, m_waveCount);17 if (lst.Count == 1)18 lst.Insert(0, new KeyValuePair
("", 0));19 return lst;20 }21 22 ///
23 /// 计算需要显示的个数24 /// 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
("", 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         ///  34         /// 波运行速度(运行时间间隔,毫秒) 35         ///  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         ///  56         /// 线弯曲程度 57         ///  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 GridLineTextColor104         {105             get { return m_gridLineTextColor; }106             set107             {108                 m_gridLineTextColor = value;109                 Refresh();110             }111         }112 113         public override Font Font114         {115             get116             {117                 return base.Font;118             }119             set120             {121                 base.Font = value;122             }123         }124         /// 125         /// 数据源,用以缓存所有需要显示的数据126         /// 127         List
> m_dataSource = new List
>();128 ///
129 /// 当前需要显示的数据130 /// 131 List
> m_currentSource = new List
>();132 Timer timer = new Timer();133 ///
134 /// 画图区域135 /// 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 ///
164 /// 添加需要显示的数据165 /// 166 ///
名称167 ///
值168 public void AddSource(string key, double value)169 {170 m_dataSource.Add(new KeyValuePair
(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
lst1 = new List
();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 ///
262 /// 得到当前需要画图的数据263 /// 264 ///
265 private List
> 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
("", 0));273 }274 }275 276 var lst = m_dataSource.GetRange(0, m_waveCount);277 if (lst.Count == 1)278 lst.Insert(0, new KeyValuePair
("", 0));279 return lst;280 }281 282 ///
283 /// 计算需要显示的个数284 /// 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
("", 0));296 }297 }298 }299 }300 }
View Code

 

最后的话

如果你喜欢的话,请到  点个星星吧

上一篇:(四十六)c#Winform自定义控件-水波进度条-HZHControls
下一篇:(四十四)c#Winform自定义控件-水波-HZHControls

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年05月02日 07时40分36秒