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


    官网

    http://www.hzhcontrols.com

    前提

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

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

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

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

    欢迎前来交流探讨: 企鹅群568015492 企鹅群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 点个星星吧

  • 相关阅读:
    分数加减法
    两点距离
    1的个数
    Swift 了解(1)
    ARC快速入门
    ARC基本概念
    autorelease注意事项
    autorelease基本使用
    NSTimer的使用
    如何监听控件的行为
  • 原文地址:https://www.cnblogs.com/bfyx/p/11397997.html
Copyright © 2020-2023  润新知