(七十二)c#Winform自定義控制項-雷達圖

来源:https://www.cnblogs.com/bfyx/archive/2019/09/25/11584514.html
-Advertisement-
Play Games

前提 入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。 GitHub:https://github.com/kwwwvagaa/NetWinformControl 碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_contr ...


前提

入行已經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+畫的,不會的可以先百度瞭解下

開始

添加一個類UCRadarChart ,繼承 UserControl

添加一些控制屬性

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

屬性改變時處理工作區域

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

重繪

  1 protected override void OnPaint(PaintEventArgs e)
  2         {
  3             base.OnPaint(e);
  4             var g = e.Graphics;
  5             g.SetGDIHigh();
  6 
  7             if (!string.IsNullOrEmpty(title))
  8             {
  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             }
 11 
 12             if (radarPositions.Length <= 2)
 13             {
 14                 g.DrawString("至少需要3個頂點", Font, new SolidBrush(Color.Black), m_rectWorking, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
 15                 return;
 16             }
 17 
 18             var y = m_rectWorking.Top - 20 - (intLineValueRowCount * (10 + lineValueTypeSize.Height));
 19 
 20             for (int i = 0; i < intLineValueRowCount; i++)
 21             {
 22                 var x = 0f;
 23                 int intCount = intLineValueComCount;
 24                 if (i == intLineValueRowCount - 1)
 25                 {
 26                     intCount = lines.Length % intLineValueComCount;
 27 
 28                 }
 29                 x = m_rectWorking.Left + (m_rectWorking.Width - intCount * (lineValueTypeSize.Width + 25)) / 2;
 30 
 31                 for (int j = 0; j < intCount; j++)
 32                 {
 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                     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                 }
 36             }
 37 
 38             float fltSplitAngle = 360F / radarPositions.Length;
 39             float fltRadiusWidth = m_rectWorking.Width / 2;
 40             float fltSplitRadiusWidth = fltRadiusWidth / splitCount;
 41             PointF centrePoint = new PointF(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Height / 2);
 42 
 43             List<List<PointF>> lstRingPoints = new List<List<PointF>>(splitCount);
 44             //分割點
 45             for (int i = 0; i < radarPositions.Length; i++)
 46             {
 47                 float fltAngle = 270 + fltSplitAngle * i;
 48                 fltAngle = fltAngle % 360;
 49                 for (int j = 0; j < splitCount; j++)
 50                 {
 51                     if (i == 0)
 52                     {
 53                         lstRingPoints.Add(new List<PointF>());
 54                     }
 55                     PointF _point = GetPointByAngle(centrePoint, fltAngle, fltSplitRadiusWidth * (splitCount - j));
 56                     lstRingPoints[j].Add(_point);
 57                 }
 58             }
 59 
 60             for (int i = 0; i < lstRingPoints.Count; i++)
 61             {
 62                 var ring = lstRingPoints[i];
 63                 GraphicsPath path = new GraphicsPath();
 64                 path.AddLines(ring.ToArray());
 65                 if ((lstRingPoints.Count - i) % 2 == 0)
 66                 {
 67                     g.FillPath(new SolidBrush(splitEvenColor), path);
 68                 }
 69                 else
 70                 {
 71                     g.FillPath(new SolidBrush(splitOddColor), path);
 72                 }
 73             }
 74 
 75             //畫環
 76             foreach (var ring in lstRingPoints)
 77             {
 78                 ring.Add(ring[0]);
 79                 g.DrawLines(new Pen(new SolidBrush(lineColor)), ring.ToArray());
 80             }
 81             //分割線
 82             foreach (var item in lstRingPoints[0])
 83             {
 84                 g.DrawLine(new Pen(new SolidBrush(lineColor)), centrePoint, item);
 85             }
 86 
 87             //
 88             for (int i = 0; i < lines.Length; i++)
 89             {
 90                 var line = lines[i];
 91                 if (line.Values.Length != radarPositions.Length)//如果數據長度和節點長度不一致則不繪製
 92                     continue;
 93                 if (line.LineColor == null || line.LineColor == Color.Empty || line.LineColor == Color.Transparent)
 94                     line.LineColor = ControlHelper.Colors[i + 13];
 95                 List<PointF> ps = new List<PointF>();
 96                 for (int j = 0; j < radarPositions.Length; j++)
 97                 {
 98                     float fltAngle = 270 + fltSplitAngle * j;
 99                     fltAngle = fltAngle % 360;
100                     PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth * (float)(line.Values[j] / radarPositions[i].MaxValue));
101                     ps.Add(_point);
102                 }
103                 ps.Add(ps[0]);
104                 if (line.FillColor != null && line.FillColor != Color.Empty && line.FillColor != Color.Transparent)
105                 {
106                     GraphicsPath path = new GraphicsPath();
107                     path.AddLines(ps.ToArray());
108                     g.FillPath(new SolidBrush(line.FillColor.Value), path);
109                 }
110                 g.DrawLines(new Pen(new SolidBrush(line.LineColor.Value), 2), ps.ToArray());
111 
112                 for (int j = 0; j < radarPositions.Length; j++)
113                 {
114                     var item = ps[j];
115                     g.FillEllipse(new SolidBrush(Color.White), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
116                     g.DrawEllipse(new Pen(new SolidBrush(line.LineColor.Value)), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
117                     if (line.ShowValueText)
118                     {
119                         var valueSize = g.MeasureString(line.Values[j].ToString("0.##"), Font);

              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這是大佬老A寫的一篇介紹Asp.Net core框架的文章https://www.cnblogs.com/artech/p/inside-asp-net-core-framework.html 2001年,微軟推出了Asp.Net ,2009年,推出了Asp.Net MVC .Net Framewo ...
  • 一、多態 多態是從繼承中引出來的概念,即不同的派生類對基類的相同方法表現出不同的行為。如下麵例子中動物的游泳方法: 當用戶使用派生類雞的游泳方法時,由於基類的游泳方法滿足雞的需求,則直接調用基類的游泳方法返回不會;當用戶使用派生類狗和蛙的游泳方法時,由於基類的游泳方法的實現不滿足狗和蛙的需求,所以狗 ...
  • 你是不是羡慕Java SpringBoot里功能強大的@註解功能,Spring Boot倡導是一種開箱即用、方便快捷、約定優於配置的開發流程,雖然現在.NET Core也往相同的方向走,但在使用上總有點彆扭,目前市面上貌似還沒有輕量級的真正意義上的開箱即用的基於.NET Core的框架。 想想多年前 ...
  • 場景 Winforn中設置ZedGraph曲線圖的屬性、坐標軸屬性、刻度屬性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100112573 在主窗體中有一個ZedGraphControl控制項,如果要在本窗體獲取此控制項對象則通 ...
  • 前段時間因為公司的一個 WebFrom 項目設計到跨時區的問題,處理了一段時間,終於解決了,寫個博客記錄一下,方便以後回顧以及給他人提供一個參考的方法。 本次的項目因為跨越了多個時區,在一些時間上會受到時區的影響,比如在美國分部使用系統插入了一條數據,在美國分部顯示的時間是“2019-09-25 0 ...
  • 問題 前同事編寫的對中控考勤機數據集成項目當中,打卡數據不能實時進行上傳到平臺當中,一直靠定時全量上傳來同步數據。 閱讀代碼後,發現代碼中有實時上傳數據的邏輯,但是運行一段時間後,中控zkemkeeper SDK中的事件失效,導致員工打卡數據沒有實時上傳。 原因 查看中控SDK Demo中的示例代碼 ...
  • 場景 Winforn中設置ZedGraph曲線圖的屬性、坐標軸屬性、刻度屬性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100112573 初次載入ZedGraph後,可以進行一些曲線圖屬性的設置,使曲線圖重新載入。 思路: ...
  • 場景 Winforn中設置ZedGraph曲線圖的屬性、坐標軸屬性、刻度屬性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100112573 初次載入ZedGraphControl時可以通過其屬性設置其Size大小,然後實現一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...