
(四十五)c#Winform自定义控件-水波图表-HZHControls
View Code
发布日期: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 Listlst1 = 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 }
最后的话
如果你喜欢的话,请到 点个星星吧
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年05月02日 07时40分36秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
设计模式(18)——中介者模式
2019-03-09
推荐几篇近期必看的视觉综述,含GAN、Transformer、人脸超分辨、遥感等
2019-03-09
一文理解设计模式--命令模式(Command)
2019-03-09
VTK:可视化之RandomProbe
2019-03-09
block多队列分析 - 2. block多队列的初始化
2019-03-09
Java时间
2019-03-09
不编译只打包system或者vendor image命令
2019-03-09
【编程】C语言入门:1到 100 的所有整数中出现多少个数字9
2019-03-09
flink启动(二)
2019-03-09
pair的用法
2019-03-09
Flex 布局的自适应子项内容过长导致其被撑大问题
2019-03-09
PL/SQL 动态Sql拼接where条件
2019-03-09
Thymeleaf sec:authorize 标签不生效
2019-03-11
Flask--简介
2019-03-11
Frame--Api框架
2019-03-11
Boostrap技能点整理之【网格系统】
2019-03-11
javaWeb服务详解(含源代码,测试通过,注释) ——Emp的Dao层
2019-03-11
Git简单理解与使用
2019-03-11
echarts 基本图表开发小结
2019-03-11