请选择 进入手机版 | 继续访问电脑版

马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#问题入口 ASP.NET问题入口

【C#问题提交】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接毕业设计】 面试-葵花宝典下载

官方一群:

官方二群:

查看: 63|回复: 0

c#Winform自定义控件-雷达图

[复制链接]
  • TA的每日心情
    开心
    前天 09:04
  • 签到天数: 1482 天

    [LV.10]以坛为家III

    1429

    主题

    3338

    帖子

    9万

    积分

    管理员

    IBC编程社区-原道楠

    Rank: 9Rank: 9Rank: 9

    积分
    95498

    推广达人突出贡献优秀版主荣誉管理论坛元老

    发表于 2019-9-26 09:17:42 | 显示全部楼层 |阅读模式

    马上加入IBC,查看更多教程

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x

    条件

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

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

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

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

    接待前来互换探究: 企鹅群568015492

    092050rxv2wivruyycoe60.png

    麻烦博客下方点个【保举】,谢谢

    NuGet

    1. Install-Package HZH_Controls
    复制代码

    目次

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

    用处及效果

    092050lhrzbloxxbi71xtx.png

    预备工作

    GDI+画的,不会的可以先百度了解下

    开始

    添加一个类UCRadarChart ,继承 UserControl

    添加一些控制属性

    1. 1 /// <summary>
    2. 2 /// The split count
    3. 3 /// </summary>
    4. 4 private int splitCount = 5;
    5. 5 /// <summary>
    6. 6 /// Gets or sets the split count.
    7. 7 /// </summary>
    8. 8 /// <value>The split count.</value>
    9. 9 [Browsable(true)]
    10. 10 [Category("自定义")]
    11. 11 [Description("获取或设置分隔份数")]
    12. 12 public int SplitCount
    13. 13 {
    14. 14 get { return splitCount; }
    15. 15 set
    16. 16 {
    17. 17 splitCount = value;
    18. 18 Invalidate();
    19. 19 }
    20. 20 }
    21. 21
    22. 22 /// <summary>
    23. 23 /// The split odd color
    24. 24 /// </summary>
    25. 25 private Color splitOddColor = Color.White;
    26. 26 /// <summary>
    27. 27 /// 分隔奇数栏配景色
    28. 28 /// </summary>
    29. 29 /// <value>The color of the split odd.</value>
    30. 30 [Browsable(true)]
    31. 31 [Category("自定义")]
    32. 32 [Description("获取或设置分隔奇数栏配景色")]
    33. 33 public Color SplitOddColor
    34. 34 {
    35. 35 get { return splitOddColor; }
    36. 36 set
    37. 37 {
    38. 38 splitOddColor = value;
    39. 39 Invalidate();
    40. 40 }
    41. 41 }
    42. 42 /// <summary>
    43. 43 /// The split even color
    44. 44 /// </summary>
    45. 45 private Color splitEvenColor = Color.FromArgb(232, 232, 232);
    46. 46 /// <summary>
    47. 47 /// 分隔偶数栏配景色
    48. 48 /// </summary>
    49. 49 /// <value>The color of the split even.</value>
    50. 50 [Browsable(true)]
    51. 51 [Category("自定义")]
    52. 52 [Description("获取或设置分隔偶数栏配景色")]
    53. 53 public Color SplitEvenColor
    54. 54 {
    55. 55 get { return splitEvenColor; }
    56. 56 set { splitEvenColor = value; }
    57. 57 }
    58. 58
    59. 59 /// <summary>
    60. 60 /// The line color
    61. 61 /// </summary>
    62. 62 private Color lineColor = Color.FromArgb(153, 153, 153);
    63. 63 /// <summary>
    64. 64 /// Gets or sets the color of the line.
    65. 65 /// </summary>
    66. 66 /// <value>The color of the line.</value>
    67. 67 [Browsable(true)]
    68. 68 [Category("自定义")]
    69. 69 [Description("获取或设置线条色")]
    70. 70 public Color LineColor
    71. 71 {
    72. 72 get { return lineColor; }
    73. 73 set
    74. 74 {
    75. 75 lineColor = value;
    76. 76 Invalidate();
    77. 77 }
    78. 78 }
    79. 79
    80. 80 /// <summary>
    81. 81 /// The radar positions
    82. 82 /// </summary>
    83. 83 private RadarPosition[] radarPositions;
    84. 84 /// <summary>
    85. 85 /// 节点列表,至少必要3个
    86. 86 /// </summary>
    87. 87 /// <value>The radar positions.</value>
    88. 88 [Browsable(true)]
    89. 89 [Category("自定义")]
    90. 90 [Description("获取或设置节点,至少必要3个")]
    91. 91 public RadarPosition[] RadarPositions
    92. 92 {
    93. 93 get { return radarPositions; }
    94. 94 set
    95. 95 {
    96. 96 radarPositions = value;
    97. 97 Invalidate();
    98. 98 }
    99. 99 }
    100. 100
    101. 101 /// <summary>
    102. 102 /// The title
    103. 103 /// </summary>
    104. 104 private string title;
    105. 105 /// <summary>
    106. 106 /// 标题
    107. 107 /// </summary>
    108. 108 /// <value>The title.</value>
    109. 109 [Browsable(true)]
    110. 110 [Category("自定义")]
    111. 111 [Description("获取或设置标题")]
    112. 112 public string Title
    113. 113 {
    114. 114 get { return title; }
    115. 115 set
    116. 116 {
    117. 117 title = value;
    118. 118 ResetTitleSize();
    119. 119 Invalidate();
    120. 120 }
    121. 121 }
    122. 122
    123. 123 /// <summary>
    124. 124 /// The title font
    125. 125 /// </summary>
    126. 126 private Font titleFont = new Font("微软雅黑", 12);
    127. 127 /// <summary>
    128. 128 /// Gets or sets the title font.
    129. 129 /// </summary>
    130. 130 /// <value>The title font.</value>
    131. 131 [Browsable(true)]
    132. 132 [Category("自定义")]
    133. 133 [Description("获取或设置标题字体")]
    134. 134 public Font TitleFont
    135. 135 {
    136. 136 get { return titleFont; }
    137. 137 set
    138. 138 {
    139. 139 titleFont = value;
    140. 140 ResetTitleSize();
    141. 141 Invalidate();
    142. 142 }
    143. 143 }
    144. 144
    145. 145 /// <summary>
    146. 146 /// The title color
    147. 147 /// </summary>
    148. 148 private Color titleColor = Color.Black;
    149. 149 /// <summary>
    150. 150 /// Gets or sets the color of the title.
    151. 151 /// </summary>
    152. 152 /// <value>The color of the title.</value>
    153. 153 [Browsable(true)]
    154. 154 [Category("自定义")]
    155. 155 [Description("获取或设置标题文本颜色")]
    156. 156 public Color TitleColor
    157. 157 {
    158. 158 get { return titleColor; }
    159. 159 set
    160. 160 {
    161. 161 titleColor = value;
    162. 162 Invalidate();
    163. 163 }
    164. 164 }
    165. 165
    166. 166 /// <summary>
    167. 167 /// The lines
    168. 168 /// </summary>
    169. 169 private RadarLine[] lines;
    170. 170 /// <summary>
    171. 171 /// Gets or sets the lines.
    172. 172 /// </summary>
    173. 173 /// <value>The lines.</value>
    174. 174 [Browsable(true)]
    175. 175 [Category("自定义")]
    176. 176 [Description("获取或设置值线条,Values长度必须与RadarPositions长度一致,否则无法显示")]
    177. 177 public RadarLine[] Lines
    178. 178 {
    179. 179 get { return lines; }
    180. 180 set
    181. 181 {
    182. 182 lines = value;
    183. 183 Invalidate();
    184. 184 }
    185. 185 }
    186. 186
    187. 187
    188. 188 /// <summary>
    189. 189 /// The title size
    190. 190 /// </summary>
    191. 191 SizeF titleSize = SizeF.Empty;
    192. 192 /// <summary>
    193. 193 /// The m rect working
    194. 194 /// </summary>
    195. 195 private RectangleF m_rectWorking = Rectangle.Empty;
    196. 196 /// <summary>
    197. 197 /// The line value type size
    198. 198 /// </summary>
    199. 199 SizeF lineValueTypeSize = SizeF.Empty;
    200. 200 /// <summary>
    201. 201 /// The int line value COM count
    202. 202 /// </summary>
    203. 203 int intLineValueComCount = 0;
    204. 204 /// <summary>
    205. 205 /// The int line value row count
    206. 206 /// </summary>
    207. 207 int intLineValueRowCount = 0;
    复制代码

    属性改变时处置惩罚工作区域

    1. 1 /// <summary>
    2. 2 /// Handles the SizeChanged event of the UCRadarChart control.
    3. 3 /// </summary>
    4. 4 /// <param name="sender">The source of the event.</param>
    5. 5 /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    6. 6 void UCRadarChart_SizeChanged(object sender, EventArgs e)
    7. 7 {
    8. 8 ResetWorkingRect();
    9. 9 }
    10. 10
    11. 11 /// <summary>
    12. 12 /// Resets the working rect.
    13. 13 /// </summary>
    14. 14 private void ResetWorkingRect()
    15. 15 {
    16. 16 if (lines != null && lines.Length > 0)
    17. 17 {
    18. 18 using (Graphics g = this.CreateGraphics())
    19. 19 {
    20. 20 foreach (var item in lines)
    21. 21 {
    22. 22 var s = g.MeasureString(item.Name, Font);
    23. 23 if (s.Width > lineValueTypeSize.Width)
    24. 24 lineValueTypeSize = s;
    25. 25 }
    26. 26 }
    27. 27 }
    28. 28 var lineTypePanelHeight = 0f;
    29. 29 if (lineValueTypeSize != SizeF.Empty)
    30. 30 {
    31. 31 intLineValueComCount = (int)(this.Width / (lineValueTypeSize.Width + 25));
    32. 32
    33. 33 intLineValueRowCount = lines.Length / intLineValueComCount;
    34. 34 if (lines.Length % intLineValueComCount != 0)
    35. 35 {
    36. 36 intLineValueRowCount++;
    37. 37 }
    38. 38 lineTypePanelHeight = (lineValueTypeSize.Height + 10) * intLineValueRowCount;
    39. 39 }
    40. 40 var min = Math.Min(this.Width, this.Height - titleSize.Height - lineTypePanelHeight);
    41. 41 var rectWorking = new RectangleF((this.Width - min) / 2 + 10, titleSize.Height + lineTypePanelHeight + 10, min - 10, min - 10);
    42. 42 //处置惩罚文字
    43. 43 float fltSplitAngle = 360F / radarPositions.Length;
    44. 44 float fltRadiusWidth = rectWorking.Width / 2;
    45. 45 float minX = rectWorking.Left;
    46. 46 float maxX = rectWorking.Right;
    47. 47 float minY = rectWorking.Top;
    48. 48 float maxY = rectWorking.Bottom;
    49. 49 using (Graphics g = this.CreateGraphics())
    50. 50 {
    51. 51 PointF centrePoint = new PointF(rectWorking.Left + rectWorking.Width / 2, rectWorking.Top + rectWorking.Height / 2);
    52. 52 for (int i = 0; i < radarPositions.Length; i++)
    53. 53 {
    54. 54 float fltAngle = 270 + fltSplitAngle * i;
    55. 55 fltAngle = fltAngle % 360;
    56. 56 PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth);
    57. 57 var _txtSize = g.MeasureString(radarPositions[i].Text, Font);
    58. 58 if (_point.X < centrePoint.X)//左
    59. 59 {
    60. 60 if (_point.X - _txtSize.Width < minX)
    61. 61 {
    62. 62 minX = rectWorking.Left + _txtSize.Width;
    63. 63 }
    64. 64 }
    65. 65 else//右
    66. 66 {
    67. 67 if (_point.X + _txtSize.Width > maxX)
    68. 68 {
    69. 69 maxX = rectWorking.Right - _txtSize.Width;
    70. 70 }
    71. 71 }
    72. 72 if (_point.Y < centrePoint.Y)//上
    73. 73 {
    74. 74 if (_point.Y - _txtSize.Height < minY)
    75. 75 {
    76. 76 minY = rectWorking.Top + _txtSize.Height;
    77. 77 }
    78. 78 }
    79. 79 else//下
    80. 80 {
    81. 81 if (_point.Y + _txtSize.Height > maxY)
    82. 82 {
    83. 83 maxY = rectWorking.Bottom - _txtSize.Height;
    84. 84 }
    85. 85 }
    86. 86 }
    87. 87 }
    88. 88
    89. 89 min = Math.Min(maxX - minX, maxY - minY);
    90. 90 m_rectWorking = new RectangleF(minX, minY, min, min);
    91. 91 }
    复制代码

    重绘

    1. 1 protected override void OnPaint(PaintEventArgs e)
    2. 2 {
    3. 3 base.OnPaint(e);
    4. 4 var g = e.Graphics;
    5. 5 g.SetGDIHigh();
    6. 6
    7. 7 if (!string.IsNullOrEmpty(title))
    8. 8 {
    9. 9 g.DrawString(title, titleFont, new SolidBrush(titleColor), new RectangleF(m_rectWorking.Left + (m_rectWorking.Width - titleSize.Width) / 2, m_rectWorking.Top - titleSize.Height - 10 - (intLineValueRowCount * (10 + lineValueTypeSize.Height)), titleSize.Width, titleSize.Height));
    10. 10 }
    11. 11
    12. 12 if (radarPositions.Length <= 2)
    13. 13 {
    14. 14 g.DrawString("至少必要3个极点", Font, new SolidBrush(Color.Black), m_rectWorking, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
    15. 15 return;
    16. 16 }
    17. 17
    18. 18 var y = m_rectWorking.Top - 20 - (intLineValueRowCount * (10 + lineValueTypeSize.Height));
    19. 19
    20. 20 for (int i = 0; i < intLineValueRowCount; i++)
    21. 21 {
    22. 22 var x = 0f;
    23. 23 int intCount = intLineValueComCount;
    24. 24 if (i == intLineValueRowCount - 1)
    25. 25 {
    26. 26 intCount = lines.Length % intLineValueComCount;
    27. 27
    28. 28 }
    29. 29 x = m_rectWorking.Left + (m_rectWorking.Width - intCount * (lineValueTypeSize.Width + 25)) / 2;
    30. 30
    31. 31 for (int j = 0; j < intCount; j++)
    32. 32 {
    33. 33 g.FillRectangle(new SolidBrush(lines[i * intLineValueComCount + j].LineColor.Value), new RectangleF(x + (lineValueTypeSize.Width + 25)*j, y + lineValueTypeSize.Height * i, 15, lineValueTypeSize.Height));
    34. 34 g.DrawString(lines[i * intLineValueComCount + j].Name, Font, new SolidBrush(lines[i * intLineValueComCount + j].LineColor.Value), new PointF(x + (lineValueTypeSize.Width + 25) * j + 20, y + lineValueTypeSize.Height * i));
    35. 35 }
    36. 36 }
    37. 37
    38. 38 float fltSplitAngle = 360F / radarPositions.Length;
    39. 39 float fltRadiusWidth = m_rectWorking.Width / 2;
    40. 40 float fltSplitRadiusWidth = fltRadiusWidth / splitCount;
    41. 41 PointF centrePoint = new PointF(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Height / 2);
    42. 42
    43. 43 List<List<PointF>> lstRingPoints = new List<List<PointF>>(splitCount);
    44. 44 //分割点
    45. 45 for (int i = 0; i < radarPositions.Length; i++)
    46. 46 {
    47. 47 float fltAngle = 270 + fltSplitAngle * i;
    48. 48 fltAngle = fltAngle % 360;
    49. 49 for (int j = 0; j < splitCount; j++)
    50. 50 {
    51. 51 if (i == 0)
    52. 52 {
    53. 53 lstRingPoints.Add(new List<PointF>());
    54. 54 }
    55. 55 PointF _point = GetPointByAngle(centrePoint, fltAngle, fltSplitRadiusWidth * (splitCount - j));
    56. 56 lstRingPoints[j].Add(_point);
    57. 57 }
    58. 58 }
    59. 59
    60. 60 for (int i = 0; i < lstRingPoints.Count; i++)
    61. 61 {
    62. 62 var ring = lstRingPoints[i];
    63. 63 GraphicsPath path = new GraphicsPath();
    64. 64 path.AddLines(ring.ToArray());
    65. 65 if ((lstRingPoints.Count - i) % 2 == 0)
    66. 66 {
    67. 67 g.FillPath(new SolidBrush(splitEvenColor), path);
    68. 68 }
    69. 69 else
    70. 70 {
    71. 71 g.FillPath(new SolidBrush(splitOddColor), path);
    72. 72 }
    73. 73 }
    74. 74
    75. 75 //画环
    76. 76 foreach (var ring in lstRingPoints)
    77. 77 {
    78. 78 ring.Add(ring[0]);
    79. 79 g.DrawLines(new Pen(new SolidBrush(lineColor)), ring.ToArray());
    80. 80 }
    81. 81 //分割线
    82. 82 foreach (var item in lstRingPoints[0])
    83. 83 {
    84. 84 g.DrawLine(new Pen(new SolidBrush(lineColor)), centrePoint, item);
    85. 85 }
    86. 86
    87. 87 //值
    88. 88 for (int i = 0; i < lines.Length; i++)
    89. 89 {
    90. 90 var line = lines[i];
    91. 91 if (line.Values.Length != radarPositions.Length)//如果数据长度和节点长度不一致则不绘制
    92. 92 continue;
    93. 93 if (line.LineColor == null || line.LineColor == Color.Empty || line.LineColor == Color.Transparent)
    94. 94 line.LineColor = ControlHelper.Colors[i + 13];
    95. 95 List<PointF> ps = new List<PointF>();
    96. 96 for (int j = 0; j < radarPositions.Length; j++)
    97. 97 {
    98. 98 float fltAngle = 270 + fltSplitAngle * j;
    99. 99 fltAngle = fltAngle % 360;
    100. 100 PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth * (float)(line.Values[j] / radarPositions[i].MaxValue));
    101. 101 ps.Add(_point);
    102. 102 }
    103. 103 ps.Add(ps[0]);
    104. 104 if (line.FillColor != null && line.FillColor != Color.Empty && line.FillColor != Color.Transparent)
    105. 105 {
    106. 106 GraphicsPath path = new GraphicsPath();
    107. 107 path.AddLines(ps.ToArray());
    108. 108 g.FillPath(new SolidBrush(line.FillColor.Value), path);
    109. 109 }
    110. 110 g.DrawLines(new Pen(new SolidBrush(line.LineColor.Value), 2), ps.ToArray());
    111. 111
    112. 112 for (int j = 0; j < radarPositions.Length; j++)
    113. 113 {
    114. 114 var item = ps[j];
    115. 115 g.FillEllipse(new SolidBrush(Color.White), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
    116. 116 g.DrawEllipse(new Pen(new SolidBrush(line.LineColor.Value)), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
    117. 117 if (line.ShowValueText)
    118. 118 {
    119. 119 var valueSize = g.MeasureString(line.Values[j].ToString("0.##"), Font);
    120. 120 g.DrawString(line.Values[j].ToString("0.##"), Font, new SolidBrush(line.LineColor.Value), new PointF(item.X - valueSize.Width / 2, item.Y - valueSize.Height - 5));
    121. 121 }
    122. 122 }
    123. 123 }
    124. 124
    125. 125 //文本
    126. 126
    127. 127 for (int i = 0; i < radarPositions.Length; i++)
    128. 128 {
    129. 129 PointF point = lstRingPoints[0][i];
    130. 130 var txtSize = g.MeasureString(radarPositions[i].Text, Font);
    131. 131
    132. 132 if (point.X == centrePoint.X)
    133. 133 {
    134. 134 if (point.Y > centrePoint.Y)
    135. 135 {
    136. 136 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - txtSize.Width / 2, point.Y + 10));
    137. 137 }
    138. 138 else
    139. 139 {
    140. 140 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - txtSize.Width / 2, point.Y - 10 - txtSize.Height));
    141. 141 }
    142. 142 }
    143. 143 else if (point.Y == centrePoint.Y)
    144. 144 {
    145. 145 if (point.X < centrePoint.X)
    146. 146 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y - txtSize.Height / 2));
    147. 147 else
    148. 148 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y - txtSize.Height / 2));
    149. 149 }
    150. 150 else if (point.X < centrePoint.X)//左
    151. 151 {
    152. 152 if (point.Y < centrePoint.Y)//左上
    153. 153 {
    154. 154 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y - 10 + txtSize.Height / 2));
    155. 155 }
    156. 156 else//左下
    157. 157 {
    158. 158 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y + 10 - txtSize.Height / 2));
    159. 159 }
    160. 160 }
    161. 161 else
    162. 162 {
    163. 163 if (point.Y < centrePoint.Y)//右上
    164. 164 {
    165. 165 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y - 10 + txtSize.Height / 2));
    166. 166 }
    167. 167 else//右下
    168. 168 {
    169. 169 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y + 10 - txtSize.Height / 2));
    170. 170 }
    171. 171 }
    172. 172 }
    173. 173
    174. 174 }
    复制代码

    辅助函数

    1. 1 #region 根据中心点、角度、半径盘算圆边坐标点 English:Calculating the coordinate points of circular edge according to the center point, angle and radius
    2. 2 /// <summary>
    3. 3 /// 功能形貌:根据中心点、角度、半径盘算圆边坐标点 English:Calculating the coordinate points of circular edge according to the center point, angle and radius
    4. 4 /// 作  者:HZH
    5. 5 /// 创建日期:2019-09-25 09:46:32
    6. 6 /// 任务编号:POS
    7. 7 /// </summary>
    8. 8 /// <param name="centrePoint">centrePoint</param>
    9. 9 /// <param name="fltAngle">fltAngle</param>
    10. 10 /// <param name="fltRadiusWidth">fltRadiusWidth</param>
    11. 11 /// <returns>返回值</returns>
    12. 12 private PointF GetPointByAngle(PointF centrePoint, float fltAngle, float fltRadiusWidth)
    13. 13 {
    14. 14 PointF p = centrePoint;
    15. 15 if (fltAngle == 0)
    16. 16 {
    17. 17 p.X += fltRadiusWidth;
    18. 18 }
    19. 19 else if (fltAngle == 90)
    20. 20 {
    21. 21 p.Y += fltRadiusWidth;
    22. 22 }
    23. 23 else if (fltAngle == 180)
    24. 24 {
    25. 25 p.X -= fltRadiusWidth;
    26. 26 }
    27. 27 else if (fltAngle == 270)
    28. 28 {
    29. 29 p.Y -= fltRadiusWidth;
    30. 30 }
    31. 31 else if (fltAngle > 0 && fltAngle < 90)
    32. 32 {
    33. 33 p.Y += (float)Math.Sin(Math.PI * (fltAngle / 180.00F)) * fltRadiusWidth;
    34. 34 p.X += (float)Math.Cos(Math.PI * (fltAngle / 180.00F)) * fltRadiusWidth;
    35. 35 }
    36. 36 else if (fltAngle > 90 && fltAngle < 180)
    37. 37 {
    38. 38 p.Y += (float)Math.Sin(Math.PI * ((180 - fltAngle) / 180.00F)) * fltRadiusWidth;
    39. 39 p.X -= (float)Math.Cos(Math.PI * ((180 - fltAngle) / 180.00F)) * fltRadiusWidth;
    40. 40 }
    41. 41 else if (fltAngle > 180 && fltAngle < 270)
    42. 42 {
    43. 43 p.Y -= (float)Math.Sin(Math.PI * ((fltAngle - 180) / 180.00F)) * fltRadiusWidth;
    44. 44 p.X -= (float)Math.Cos(Math.PI * ((fltAngle - 180) / 180.00F)) * fltRadiusWidth;
    45. 45 }
    46. 46 else if (fltAngle > 270 && fltAngle < 360)
    47. 47 {
    48. 48 p.Y -= (float)Math.Sin(Math.PI * ((360 - fltAngle) / 180.00F)) * fltRadiusWidth;
    49. 49 p.X += (float)Math.Cos(Math.PI * ((360 - fltAngle) / 180.00F)) * fltRadiusWidth;
    50. 50 }
    51. 51 return p;
    52. 52 }
    53. 53 #endregion
    54. 54
    55. 55 /// <summary>
    56. 56 /// Resets the size of the title.
    57. 57 /// </summary>
    58. 58 private void ResetTitleSize()
    59. 59 {
    60. 60 if (!string.IsNullOrEmpty(title))
    61. 61 {
    62. 62 using (Graphics g = this.CreateGraphics())
    63. 63 {
    64. 64 titleSize = g.MeasureString(title, titleFont);
    65. 65 }
    66. 66 }
    67. 67 else
    68. 68 {
    69. 69 titleSize = SizeF.Empty;
    70. 70 }
    71. 71 titleSize.Height += 20;
    72. 72 ResetWorkingRect();
    73. 73 }
    复制代码

    完整代码

    092051i0elzz6fculpiruc.gif
    092051fdunnenndnfve8n8.gif
    1. 1 // ***********************************************************************
    2. 2 // Assembly : HZH_Controls
    3. 3 // Created : 2019-09-25
    4. 4 //
    5. 5 // ***********************************************************************
    6. 6 // <copyright file="UCRadarChart.cs">
    7. 7 // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
    8. 8 // </copyright>
    9. 9 //
    10. 10 // Blog: https://www.cnblogs.com/bfyx
    11. 11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl
    12. 12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
    13. 13 //
    14. 14 // If you use this code, please keep this note.
    15. 15 // ***********************************************************************
    16. 16 using System;
    17. 17 using System.Collections.Generic;
    18. 18 using System.Linq;
    19. 19 using System.Text;
    20. 20 using System.Windows.Forms;
    21. 21 using System.Drawing;
    22. 22 using System.Drawing.Drawing2D;
    23. 23 using System.ComponentModel;
    24. 24
    25. 25 namespace HZH_Controls.Controls
    26. 26 {
    27. 27 /// <summary>
    28. 28 /// Class UCRadarChart.
    29. 29 /// Implements the <see cref="System.Windows.Forms.UserControl" />
    30. 30 /// </summary>
    31. 31 /// <seealso cref="System.Windows.Forms.UserControl" />
    32. 32 public class UCRadarChart : UserControl
    33. 33 {
    34. 34 /// <summary>
    35. 35 /// The split count
    36. 36 /// </summary>
    37. 37 private int splitCount = 5;
    38. 38 /// <summary>
    39. 39 /// Gets or sets the split count.
    40. 40 /// </summary>
    41. 41 /// <value>The split count.</value>
    42. 42 [Browsable(true)]
    43. 43 [Category("自定义")]
    44. 44 [Description("获取或设置分隔份数")]
    45. 45 public int SplitCount
    46. 46 {
    47. 47 get { return splitCount; }
    48. 48 set
    49. 49 {
    50. 50 splitCount = value;
    51. 51 Invalidate();
    52. 52 }
    53. 53 }
    54. 54
    55. 55 /// <summary>
    56. 56 /// The split odd color
    57. 57 /// </summary>
    58. 58 private Color splitOddColor = Color.White;
    59. 59 /// <summary>
    60. 60 /// 分隔奇数栏配景色
    61. 61 /// </summary>
    62. 62 /// <value>The color of the split odd.</value>
    63. 63 [Browsable(true)]
    64. 64 [Category("自定义")]
    65. 65 [Description("获取或设置分隔奇数栏配景色")]
    66. 66 public Color SplitOddColor
    67. 67 {
    68. 68 get { return splitOddColor; }
    69. 69 set
    70. 70 {
    71. 71 splitOddColor = value;
    72. 72 Invalidate();
    73. 73 }
    74. 74 }
    75. 75 /// <summary>
    76. 76 /// The split even color
    77. 77 /// </summary>
    78. 78 private Color splitEvenColor = Color.FromArgb(232, 232, 232);
    79. 79 /// <summary>
    80. 80 /// 分隔偶数栏配景色
    81. 81 /// </summary>
    82. 82 /// <value>The color of the split even.</value>
    83. 83 [Browsable(true)]
    84. 84 [Category("自定义")]
    85. 85 [Description("获取或设置分隔偶数栏配景色")]
    86. 86 public Color SplitEvenColor
    87. 87 {
    88. 88 get { return splitEvenColor; }
    89. 89 set { splitEvenColor = value; }
    90. 90 }
    91. 91
    92. 92 /// <summary>
    93. 93 /// The line color
    94. 94 /// </summary>
    95. 95 private Color lineColor = Color.FromArgb(153, 153, 153);
    96. 96 /// <summary>
    97. 97 /// Gets or sets the color of the line.
    98. 98 /// </summary>
    99. 99 /// <value>The color of the line.</value>
    100. 100 [Browsable(true)]
    101. 101 [Category("自定义")]
    102. 102 [Description("获取或设置线条色")]
    103. 103 public Color LineColor
    104. 104 {
    105. 105 get { return lineColor; }
    106. 106 set
    107. 107 {
    108. 108 lineColor = value;
    109. 109 Invalidate();
    110. 110 }
    111. 111 }
    112. 112
    113. 113 /// <summary>
    114. 114 /// The radar positions
    115. 115 /// </summary>
    116. 116 private RadarPosition[] radarPositions;
    117. 117 /// <summary>
    118. 118 /// 节点列表,至少必要3个
    119. 119 /// </summary>
    120. 120 /// <value>The radar positions.</value>
    121. 121 [Browsable(true)]
    122. 122 [Category("自定义")]
    123. 123 [Description("获取或设置节点,至少必要3个")]
    124. 124 public RadarPosition[] RadarPositions
    125. 125 {
    126. 126 get { return radarPositions; }
    127. 127 set
    128. 128 {
    129. 129 radarPositions = value;
    130. 130 Invalidate();
    131. 131 }
    132. 132 }
    133. 133
    134. 134 /// <summary>
    135. 135 /// The title
    136. 136 /// </summary>
    137. 137 private string title;
    138. 138 /// <summary>
    139. 139 /// 标题
    140. 140 /// </summary>
    141. 141 /// <value>The title.</value>
    142. 142 [Browsable(true)]
    143. 143 [Category("自定义")]
    144. 144 [Description("获取或设置标题")]
    145. 145 public string Title
    146. 146 {
    147. 147 get { return title; }
    148. 148 set
    149. 149 {
    150. 150 title = value;
    151. 151 ResetTitleSize();
    152. 152 Invalidate();
    153. 153 }
    154. 154 }
    155. 155
    156. 156 /// <summary>
    157. 157 /// The title font
    158. 158 /// </summary>
    159. 159 private Font titleFont = new Font("微软雅黑", 12);
    160. 160 /// <summary>
    161. 161 /// Gets or sets the title font.
    162. 162 /// </summary>
    163. 163 /// <value>The title font.</value>
    164. 164 [Browsable(true)]
    165. 165 [Category("自定义")]
    166. 166 [Description("获取或设置标题字体")]
    167. 167 public Font TitleFont
    168. 168 {
    169. 169 get { return titleFont; }
    170. 170 set
    171. 171 {
    172. 172 titleFont = value;
    173. 173 ResetTitleSize();
    174. 174 Invalidate();
    175. 175 }
    176. 176 }
    177. 177
    178. 178 /// <summary>
    179. 179 /// The title color
    180. 180 /// </summary>
    181. 181 private Color titleColor = Color.Black;
    182. 182 /// <summary>
    183. 183 /// Gets or sets the color of the title.
    184. 184 /// </summary>
    185. 185 /// <value>The color of the title.</value>
    186. 186 [Browsable(true)]
    187. 187 [Category("自定义")]
    188. 188 [Description("获取或设置标题文本颜色")]
    189. 189 public Color TitleColor
    190. 190 {
    191. 191 get { return titleColor; }
    192. 192 set
    193. 193 {
    194. 194 titleColor = value;
    195. 195 Invalidate();
    196. 196 }
    197. 197 }
    198. 198
    199. 199 /// <summary>
    200. 200 /// The lines
    201. 201 /// </summary>
    202. 202 private RadarLine[] lines;
    203. 203 /// <summary>
    204. 204 /// Gets or sets the lines.
    205. 205 /// </summary>
    206. 206 /// <value>The lines.</value>
    207. 207 [Browsable(true)]
    208. 208 [Category("自定义")]
    209. 209 [Description("获取或设置值线条,Values长度必须与RadarPositions长度一致,否则无法显示")]
    210. 210 public RadarLine[] Lines
    211. 211 {
    212. 212 get { return lines; }
    213. 213 set
    214. 214 {
    215. 215 lines = value;
    216. 216 Invalidate();
    217. 217 }
    218. 218 }
    219. 219
    220. 220
    221. 221 /// <summary>
    222. 222 /// The title size
    223. 223 /// </summary>
    224. 224 SizeF titleSize = SizeF.Empty;
    225. 225 /// <summary>
    226. 226 /// The m rect working
    227. 227 /// </summary>
    228. 228 private RectangleF m_rectWorking = Rectangle.Empty;
    229. 229 /// <summary>
    230. 230 /// The line value type size
    231. 231 /// </summary>
    232. 232 SizeF lineValueTypeSize = SizeF.Empty;
    233. 233 /// <summary>
    234. 234 /// The int line value COM count
    235. 235 /// </summary>
    236. 236 int intLineValueComCount = 0;
    237. 237 /// <summary>
    238. 238 /// The int line value row count
    239. 239 /// </summary>
    240. 240 int intLineValueRowCount = 0;
    241. 241 /// <summary>
    242. 242 /// Initializes a new instance of the <see cref="UCRadarChart"/> class.
    243. 243 /// </summary>
    244. 244 public UCRadarChart()
    245. 245 {
    246. 246 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
    247. 247 this.SetStyle(ControlStyles.DoubleBuffer, true);
    248. 248 this.SetStyle(ControlStyles.ResizeRedraw, true);
    249. 249 this.SetStyle(ControlStyles.Selectable, true);
    250. 250 this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    251. 251 this.SetStyle(ControlStyles.UserPaint, true);
    252. 252 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
    253. 253 this.SizeChanged += UCRadarChart_SizeChanged;
    254. 254 Size = new System.Drawing.Size(150, 150);
    255. 255 radarPositions = new RadarPosition[0];
    256. 256 if (ControlHelper.IsDesignMode())
    257. 257 {
    258. 258 radarPositions = new RadarPosition[6];
    259. 259 for (int i = 0; i < 6; i++)
    260. 260 {
    261. 261 radarPositions[i] = new RadarPosition
    262. 262 {
    263. 263 Text = "Item" + (i + 1),
    264. 264 MaxValue = 100
    265. 265 };
    266. 266 }
    267. 267 }
    268. 268
    269. 269 lines = new RadarLine[0];
    270. 270 if (ControlHelper.IsDesignMode())
    271. 271 {
    272. 272 Random r = new Random();
    273. 273 lines = new RadarLine[2];
    274. 274 for (int i = 0; i < 2; i++)
    275. 275 {
    276. 276 lines[i] = new RadarLine()
    277. 277 {
    278. 278 Name = "line" + i
    279. 279 };
    280. 280 lines[i].Values = new double[radarPositions.Length];
    281. 281 for (int j = 0; j < radarPositions.Length; j++)
    282. 282 {
    283. 283 lines[i].Values[j] = r.Next(20, (int)radarPositions[j].MaxValue);
    284. 284 }
    285. 285 }
    286. 286 }
    287. 287 }
    288. 288
    289. 289 /// <summary>
    290. 290 /// Handles the SizeChanged event of the UCRadarChart control.
    291. 291 /// </summary>
    292. 292 /// <param name="sender">The source of the event.</param>
    293. 293 /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    294. 294 void UCRadarChart_SizeChanged(object sender, EventArgs e)
    295. 295 {
    296. 296 ResetWorkingRect();
    297. 297 }
    298. 298
    299. 299 /// <summary>
    300. 300 /// Resets the working rect.
    301. 301 /// </summary>
    302. 302 private void ResetWorkingRect()
    303. 303 {
    304. 304 if (lines != null && lines.Length > 0)
    305. 305 {
    306. 306 using (Graphics g = this.CreateGraphics())
    307. 307 {
    308. 308 foreach (var item in lines)
    309. 309 {
    310. 310 var s = g.MeasureString(item.Name, Font);
    311. 311 if (s.Width > lineValueTypeSize.Width)
    312. 312 lineValueTypeSize = s;
    313. 313 }
    314. 314 }
    315. 315 }
    316. 316 var lineTypePanelHeight = 0f;
    317. 317 if (lineValueTypeSize != SizeF.Empty)
    318. 318 {
    319. 319 intLineValueComCount = (int)(this.Width / (lineValueTypeSize.Width + 25));
    320. 320
    321. 321 intLineValueRowCount = lines.Length / intLineValueComCount;
    322. 322 if (lines.Length % intLineValueComCount != 0)
    323. 323 {
    324. 324 intLineValueRowCount++;
    325. 325 }
    326. 326 lineTypePanelHeight = (lineValueTypeSize.Height + 10) * intLineValueRowCount;
    327. 327 }
    328. 328 var min = Math.Min(this.Width, this.Height - titleSize.Height - lineTypePanelHeight);
    329. 329 var rectWorking = new RectangleF((this.Width - min) / 2 + 10, titleSize.Height + lineTypePanelHeight + 10, min - 10, min - 10);
    330. 330 //处置惩罚文字
    331. 331 float fltSplitAngle = 360F / radarPositions.Length;
    332. 332 float fltRadiusWidth = rectWorking.Width / 2;
    333. 333 float minX = rectWorking.Left;
    334. 334 float maxX = rectWorking.Right;
    335. 335 float minY = rectWorking.Top;
    336. 336 float maxY = rectWorking.Bottom;
    337. 337 using (Graphics g = this.CreateGraphics())
    338. 338 {
    339. 339 PointF centrePoint = new PointF(rectWorking.Left + rectWorking.Width / 2, rectWorking.Top + rectWorking.Height / 2);
    340. 340 for (int i = 0; i < radarPositions.Length; i++)
    341. 341 {
    342. 342 float fltAngle = 270 + fltSplitAngle * i;
    343. 343 fltAngle = fltAngle % 360;
    344. 344 PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth);
    345. 345 var _txtSize = g.MeasureString(radarPositions[i].Text, Font);
    346. 346 if (_point.X < centrePoint.X)//左
    347. 347 {
    348. 348 if (_point.X - _txtSize.Width < minX)
    349. 349 {
    350. 350 minX = rectWorking.Left + _txtSize.Width;
    351. 351 }
    352. 352 }
    353. 353 else//右
    354. 354 {
    355. 355 if (_point.X + _txtSize.Width > maxX)
    356. 356 {
    357. 357 maxX = rectWorking.Right - _txtSize.Width;
    358. 358 }
    359. 359 }
    360. 360 if (_point.Y < centrePoint.Y)//上
    361. 361 {
    362. 362 if (_point.Y - _txtSize.Height < minY)
    363. 363 {
    364. 364 minY = rectWorking.Top + _txtSize.Height;
    365. 365 }
    366. 366 }
    367. 367 else//下
    368. 368 {
    369. 369 if (_point.Y + _txtSize.Height > maxY)
    370. 370 {
    371. 371 maxY = rectWorking.Bottom - _txtSize.Height;
    372. 372 }
    373. 373 }
    374. 374 }
    375. 375 }
    376. 376
    377. 377 min = Math.Min(maxX - minX, maxY - minY);
    378. 378 m_rectWorking = new RectangleF(minX, minY, min, min);
    379. 379 }
    380. 380
    381. 381 /// <summary>
    382. 382 /// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 变乱。
    383. 383 /// </summary>
    384. 384 /// <param name="e">包罗变乱数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param>
    385. 385 protected override void OnPaint(PaintEventArgs e)
    386. 386 {
    387. 387 base.OnPaint(e);
    388. 388 var g = e.Graphics;
    389. 389 g.SetGDIHigh();
    390. 390
    391. 391 if (!string.IsNullOrEmpty(title))
    392. 392 {
    393. 393 g.DrawString(title, titleFont, new SolidBrush(titleColor), new RectangleF(m_rectWorking.Left + (m_rectWorking.Width - titleSize.Width) / 2, m_rectWorking.Top - titleSize.Height - 10 - (intLineValueRowCount * (10 + lineValueTypeSize.Height)), titleSize.Width, titleSize.Height));
    394. 394 }
    395. 395
    396. 396 if (radarPositions.Length <= 2)
    397. 397 {
    398. 398 g.DrawString("至少必要3个极点", Font, new SolidBrush(Color.Black), m_rectWorking, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
    399. 399 return;
    400. 400 }
    401. 401
    402. 402 var y = m_rectWorking.Top - 20 - (intLineValueRowCount * (10 + lineValueTypeSize.Height));
    403. 403
    404. 404 for (int i = 0; i < intLineValueRowCount; i++)
    405. 405 {
    406. 406 var x = 0f;
    407. 407 int intCount = intLineValueComCount;
    408. 408 if (i == intLineValueRowCount - 1)
    409. 409 {
    410. 410 intCount = lines.Length % intLineValueComCount;
    411. 411
    412. 412 }
    413. 413 x = m_rectWorking.Left + (m_rectWorking.Width - intCount * (lineValueTypeSize.Width + 25)) / 2;
    414. 414
    415. 415 for (int j = 0; j < intCount; j++)
    416. 416 {
    417. 417 g.FillRectangle(new SolidBrush(lines[i * intLineValueComCount + j].LineColor.Value), new RectangleF(x + (lineValueTypeSize.Width + 25)*j, y + lineValueTypeSize.Height * i, 15, lineValueTypeSize.Height));
    418. 418 g.DrawString(lines[i * intLineValueComCount + j].Name, Font, new SolidBrush(lines[i * intLineValueComCount + j].LineColor.Value), new PointF(x + (lineValueTypeSize.Width + 25) * j + 20, y + lineValueTypeSize.Height * i));
    419. 419 }
    420. 420 }
    421. 421
    422. 422 float fltSplitAngle = 360F / radarPositions.Length;
    423. 423 float fltRadiusWidth = m_rectWorking.Width / 2;
    424. 424 float fltSplitRadiusWidth = fltRadiusWidth / splitCount;
    425. 425 PointF centrePoint = new PointF(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Height / 2);
    426. 426
    427. 427 List<List<PointF>> lstRingPoints = new List<List<PointF>>(splitCount);
    428. 428 //分割点
    429. 429 for (int i = 0; i < radarPositions.Length; i++)
    430. 430 {
    431. 431 float fltAngle = 270 + fltSplitAngle * i;
    432. 432 fltAngle = fltAngle % 360;
    433. 433 for (int j = 0; j < splitCount; j++)
    434. 434 {
    435. 435 if (i == 0)
    436. 436 {
    437. 437 lstRingPoints.Add(new List<PointF>());
    438. 438 }
    439. 439 PointF _point = GetPointByAngle(centrePoint, fltAngle, fltSplitRadiusWidth * (splitCount - j));
    440. 440 lstRingPoints[j].Add(_point);
    441. 441 }
    442. 442 }
    443. 443
    444. 444 for (int i = 0; i < lstRingPoints.Count; i++)
    445. 445 {
    446. 446 var ring = lstRingPoints[i];
    447. 447 GraphicsPath path = new GraphicsPath();
    448. 448 path.AddLines(ring.ToArray());
    449. 449 if ((lstRingPoints.Count - i) % 2 == 0)
    450. 450 {
    451. 451 g.FillPath(new SolidBrush(splitEvenColor), path);
    452. 452 }
    453. 453 else
    454. 454 {
    455. 455 g.FillPath(new SolidBrush(splitOddColor), path);
    456. 456 }
    457. 457 }
    458. 458
    459. 459 //画环
    460. 460 foreach (var ring in lstRingPoints)
    461. 461 {
    462. 462 ring.Add(ring[0]);
    463. 463 g.DrawLines(new Pen(new SolidBrush(lineColor)), ring.ToArray());
    464. 464 }
    465. 465 //分割线
    466. 466 foreach (var item in lstRingPoints[0])
    467. 467 {
    468. 468 g.DrawLine(new Pen(new SolidBrush(lineColor)), centrePoint, item);
    469. 469 }
    470. 470
    471. 471 //值
    472. 472 for (int i = 0; i < lines.Length; i++)
    473. 473 {
    474. 474 var line = lines[i];
    475. 475 if (line.Values.Length != radarPositions.Length)//如果数据长度和节点长度不一致则不绘制
    476. 476 continue;
    477. 477 if (line.LineColor == null || line.LineColor == Color.Empty || line.LineColor == Color.Transparent)
    478. 478 line.LineColor = ControlHelper.Colors[i + 13];
    479. 479 List<PointF> ps = new List<PointF>();
    480. 480 for (int j = 0; j < radarPositions.Length; j++)
    481. 481 {
    482. 482 float fltAngle = 270 + fltSplitAngle * j;
    483. 483 fltAngle = fltAngle % 360;
    484. 484 PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth * (float)(line.Values[j] / radarPositions[i].MaxValue));
    485. 485 ps.Add(_point);
    486. 486 }
    487. 487 ps.Add(ps[0]);
    488. 488 if (line.FillColor != null && line.FillColor != Color.Empty && line.FillColor != Color.Transparent)
    489. 489 {
    490. 490 GraphicsPath path = new GraphicsPath();
    491. 491 path.AddLines(ps.ToArray());
    492. 492 g.FillPath(new SolidBrush(line.FillColor.Value), path);
    493. 493 }
    494. 494 g.DrawLines(new Pen(new SolidBrush(line.LineColor.Value), 2), ps.ToArray());
    495. 495
    496. 496 for (int j = 0; j < radarPositions.Length; j++)
    497. 497 {
    498. 498 var item = ps[j];
    499. 499 g.FillEllipse(new SolidBrush(Color.White), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
    500. 500 g.DrawEllipse(new Pen(new SolidBrush(line.LineColor.Value)), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
    501. 501 if (line.ShowValueText)
    502. 502 {
    503. 503 var valueSize = g.MeasureString(line.Values[j].ToString("0.##"), Font);
    504. 504 g.DrawString(line.Values[j].ToString("0.##"), Font, new SolidBrush(line.LineColor.Value), new PointF(item.X - valueSize.Width / 2, item.Y - valueSize.Height - 5));
    505. 505 }
    506. 506 }
    507. 507 }
    508. 508
    509. 509 //文本
    510. 510
    511. 511 for (int i = 0; i < radarPositions.Length; i++)
    512. 512 {
    513. 513 PointF point = lstRingPoints[0][i];
    514. 514 var txtSize = g.MeasureString(radarPositions[i].Text, Font);
    515. 515
    516. 516 if (point.X == centrePoint.X)
    517. 517 {
    518. 518 if (point.Y > centrePoint.Y)
    519. 519 {
    520. 520 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - txtSize.Width / 2, point.Y + 10));
    521. 521 }
    522. 522 else
    523. 523 {
    524. 524 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - txtSize.Width / 2, point.Y - 10 - txtSize.Height));
    525. 525 }
    526. 526 }
    527. 527 else if (point.Y == centrePoint.Y)
    528. 528 {
    529. 529 if (point.X < centrePoint.X)
    530. 530 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y - txtSize.Height / 2));
    531. 531 else
    532. 532 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y - txtSize.Height / 2));
    533. 533 }
    534. 534 else if (point.X < centrePoint.X)//左
    535. 535 {
    536. 536 if (point.Y < centrePoint.Y)//左上
    537. 537 {
    538. 538 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y - 10 + txtSize.Height / 2));
    539. 539 }
    540. 540 else//左下
    541. 541 {
    542. 542 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y + 10 - txtSize.Height / 2));
    543. 543 }
    544. 544 }
    545. 545 else
    546. 546 {
    547. 547 if (point.Y < centrePoint.Y)//右上
    548. 548 {
    549. 549 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y - 10 + txtSize.Height / 2));
    550. 550 }
    551. 551 else//右下
    552. 552 {
    553. 553 g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y + 10 - txtSize.Height / 2));
    554. 554 }
    555. 555 }
    556. 556 }
    557. 557
    558. 558 }
    559. 559
    560. 560 #region 根据中心点、角度、半径盘算圆边坐标点 English:Calculating the coordinate points of circular edge according to the center point, angle and radius
    561. 561 /// <summary>
    562. 562 /// 功能形貌:根据中心点、角度、半径盘算圆边坐标点 English:Calculating the coordinate points of circular edge according to the center point, angle and radius
    563. 563 /// 作  者:HZH
    564. 564 /// 创建日期:2019-09-25 09:46:32
    565. 565 /// 任务编号:POS
    566. 566 /// </summary>
    567. 567 /// <param name="centrePoint">centrePoint</param>
    568. 568 /// <param name="fltAngle">fltAngle</param>
    569. 569 /// <param name="fltRadiusWidth">fltRadiusWidth</param>
    570. 570 /// <returns>返回值</returns>
    571. 571 private PointF GetPointByAngle(PointF centrePoint, float fltAngle, float fltRadiusWidth)
    572. 572 {
    573. 573 PointF p = centrePoint;
    574. 574 if (fltAngle == 0)
    575. 575 {
    576. 576 p.X += fltRadiusWidth;
    577. 577 }
    578. 578 else if (fltAngle == 90)
    579. 579 {
    580. 580 p.Y += fltRadiusWidth;
    581. 581 }
    582. 582 else if (fltAngle == 180)
    583. 583 {
    584. 584 p.X -= fltRadiusWidth;
    585. 585 }
    586. 586 else if (fltAngle == 270)
    587. 587 {
    588. 588 p.Y -= fltRadiusWidth;
    589. 589 }
    590. 590 else if (fltAngle > 0 && fltAngle < 90)
    591. 591 {
    592. 592 p.Y += (float)Math.Sin(Math.PI * (fltAngle / 180.00F)) * fltRadiusWidth;
    593. 593 p.X += (float)Math.Cos(Math.PI * (fltAngle / 180.00F)) * fltRadiusWidth;
    594. 594 }
    595. 595 else if (fltAngle > 90 && fltAngle < 180)
    596. 596 {
    597. 597 p.Y += (float)Math.Sin(Math.PI * ((180 - fltAngle) / 180.00F)) * fltRadiusWidth;
    598. 598 p.X -= (float)Math.Cos(Math.PI * ((180 - fltAngle) / 180.00F)) * fltRadiusWidth;
    599. 599 }
    600. 600 else if (fltAngle > 180 && fltAngle < 270)
    601. 601 {
    602. 602 p.Y -= (float)Math.Sin(Math.PI * ((fltAngle - 180) / 180.00F)) * fltRadiusWidth;
    603. 603 p.X -= (float)Math.Cos(Math.PI * ((fltAngle - 180) / 180.00F)) * fltRadiusWidth;
    604. 604 }
    605. 605 else if (fltAngle > 270 && fltAngle < 360)
    606. 606 {
    607. 607 p.Y -= (float)Math.Sin(Math.PI * ((360 - fltAngle) / 180.00F)) * fltRadiusWidth;
    608. 608 p.X += (float)Math.Cos(Math.PI * ((360 - fltAngle) / 180.00F)) * fltRadiusWidth;
    609. 609 }
    610. 610 return p;
    611. 611 }
    612. 612 #endregion
    613. 613
    614. 614 /// <summary>
    615. 615 /// Resets the size of the title.
    616. 616 /// </summary>
    617. 617 private void ResetTitleSize()
    618. 618 {
    619. 619 if (!string.IsNullOrEmpty(title))
    620. 620 {
    621. 621 using (Graphics g = this.CreateGraphics())
    622. 622 {
    623. 623 titleSize = g.MeasureString(title, titleFont);
    624. 624 }
    625. 625 }
    626. 626 else
    627. 627 {
    628. 628 titleSize = SizeF.Empty;
    629. 629 }
    630. 630 titleSize.Height += 20;
    631. 631 ResetWorkingRect();
    632. 632 }
    633. 633 }
    634. 634 }
    复制代码
    View Code

    末了的话

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







    来源:https://www.cnblogs.com/bfyx/archive/2019/09/25/11584514.html
    C#论坛 www.ibcibc.com IBC编程社区
    C#
    C#论坛
    IBC编程社区
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则