程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 報表設計器 (winform 設計端)開發與實現生成網頁的HTML報表,

C# 報表設計器 (winform 設計端)開發與實現生成網頁的HTML報表,

編輯:C#入門知識

C# 報表設計器 (winform 設計端)開發與實現生成網頁的HTML報表,


    記得2010年之前,公司的項目基本上都要用到報表,以前我們常用的方法就是針對客戶的需求來定制化開發(基本上是死寫代碼)來實現,經常導致項目經常性的延期,因為客戶的需求經常會變化,隨著用戶的使用認知度的提高,對報表的要求越來越高,導致程序員不停的修改代碼來實現,效率不高、結束遙遙無期。。。非常的痛苦;當然市面上有很多報表開發工具可以實現,但是針對小公司來說采購一套這樣的系統的成本也非常的高,所以我們決定自己來開發一套像目前的潤乾、FineReport 這樣的報表設計器,來實現快速的報表設計制作。

   當初為了開發這樣的系統,花費的了很長的時間學習查閱各種資料,其痛苦只有程序員才能體會,因為沒有任何現成的實例代碼可供參考,只有看別人的思路來一步步的摸索,本文將我們當初設計制作的報表設計器的功能分享出來,讓有需要的或想開發報表設計的朋友們提供一個參考,盡量少走很動彎路,設計端可以直接使用,但是計算引擎和網頁的計算的源碼就不能分享出來了(請不要介意,因為涉及到公司的保密原因)

   記得當初為了制作報表設計器,在網上查找有沒有相關的實例資料,找了很久,也是沒有找到合適的,後來發現 SourceGrid 可以實現單元格的合並拆分功能,所以決定修改實現winform端的報表設計。下面我將制作的E_Report 報表控件抽取出來建立一個簡易的Winform的可運行的實例提供給大伙下載,希望能給你的開發提供一點幫助和借鑒;當然你可以直接使用也可以,裡面的設計功能基本全部能。

   抽取出來的源碼包含:E_Report 報表設計自定義控件DLL源碼;  EReportDemo 建立的簡易Winform 端設計器使用DLL的實例源碼;

  一、運行效果

    實例中,只做了一個簡單的效果,工具欄的按鈕在單元格右擊屬性中都有,只是放了幾個常用的在工具導航欄中(右擊單元格屬性可以看到設計導航)

    可以進行單元格的合並、拆分、字體、顏色、背景、邊框等的設置,朋友們可以自己編寫保存發布等功能,實現報表的真實功能;

  

      例如單元格屬性(其他還有很多的屬性,自己下載源碼後運行起來就能看到了)

    

       對表格的斜線、斜線文字有很好的支持;可以設置表頭、表位、標題等 實際效果圖如下

    

 

二、使用介紹

1、頁面初始化的時候,通過 ReportDoc 類 初始報表的行列及單元格屬性

1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Drawing; 5 using System.Windows.Forms; 6 using System.Drawing.Drawing2D; 7 using System.Xml; 8 using System.Collections; 9 using E_Report; 10 11 namespace EReportDemo 12 { 13 /// <summary> 14 /// 報表表格對象 15 /// </summary> 16 public class ReportDoc 17 { 18 #region 變量參數定義 19 20 /// <summary> 21 /// 表格對象 22 /// </summary> 23 private EReport _nowReport; 24 25 /// <summary> 26 /// 報表配置編碼 27 /// </summary> 28 private string _reportCode = ""; 29 30 /// <summary> 31 /// 表報設計狀態 32 /// </summary> 33 private string _reportState = ""; 34 35 #endregion 36 37 #region 函數構造方法 38 39 /// <summary> 40 /// 構造函數 41 /// </summary> 42 public ReportDoc() 43 { 44 this._nowReport = null; 45 this._reportCode = ""; 46 this._reportState = ""; 47 48 } 49 50 51 /// <summary> 52 /// 獲取--設置--表格對象 53 /// </summary> 54 public EReport NowReport 55 { 56 get { return this._nowReport; } 57 set { this._nowReport = value; } 58 } 59 60 /// <summary> 61 /// 報表配置編碼 62 /// </summary> 63 public string ReportCode 64 { 65 get { return this._reportCode; } 66 set { this._reportCode = value; } 67 } 68 69 /// <summary> 70 /// 報表設計狀態 71 /// 新增、修改 兩種狀態 72 /// </summary> 73 public string ReportState 74 { 75 get { return this._reportState; } 76 set { this._reportState = value; } 77 } 78 79 /// <summary> 80 /// 資源釋放 81 /// </summary> 82 ~ReportDoc() 83 { 84 this._nowReport = null; 85 this._reportState = ""; 86 87 } 88 89 #endregion 90 91 #region 加載報表表格 92 93 /// <summary> 94 /// 初始化--報表表格 95 /// </summary> 96 public void InitReport() 97 { 98 99 int rCount = 41; // 41行 100 int cCount = 20; // 20列 101 102 _nowReport.Redim(rCount, cCount); 103 _nowReport.FixedRows = 1; 104 _nowReport.FixedColumns = 1; 105 106 InitCells(); 107 108 } 109 110 /// <summary> 111 /// 初始化--單元格 112 /// </summary> 113 public void InitCells() 114 { 115 // 第一行 第一列 116 _nowReport.Rows[0].Height = 23; 117 _nowReport.Columns[0].Width = 50; 118 119 // 設置00格 120 _nowReport[0, 0] = new E_Report.Cells.HeaderColumn(""); 121 122 // 設置行 123 for (int rr = 1; rr < _nowReport.RowsCount; rr++) 124 { 125 string tmRowT = rr.ToString(); 126 _nowReport[rr, 0] = new E_Report.Cells.HeaderRow(tmRowT); 127 } 128 129 // 設置列 130 for (int cc = 1; cc < _nowReport.ColumnsCount; cc++) 131 { 132 _nowReport[0, cc] = new E_Report.Cells.HeaderColumn(_nowReport.GetColumnHeadTileChar(cc)); 133 } 134 135 // 設置單元格 136 for (int iRow = 1; iRow < _nowReport.RowsCount; iRow++) 137 { 138 for (int iCol = 1; iCol < _nowReport.ColumnsCount; iCol++) 139 { 140 _nowReport[iRow, iCol] = new E_Report.Cells.Cell("", typeof(string)); 141 } 142 } 143 144 } 145 146 147 #endregion 148 149 } 150 } View Code

2、工具導航欄 設置單元格相關屬性

1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Windows.Forms; 8 using System.Collections; 9 using E_Report; 10 11 namespace EReportDemo 12 { 13 /// <summary> 14 /// 本程序只是Winform端的報表設計功能 15 /// 至於其他的功能,本實例沒有提供 16 /// 報表設計的設計效果:可以查看 www.sdpsoft.com SDP軟件快速開發平台 報表設計篇 17 /// </summary> 18 19 public partial class EReportMain : Form 20 { 21 private ReportDoc report; 22 private E_Report.Cells.Controllers.PopupMenu myPopupMenu; 23 24 public EReportMain() 25 { 26 InitializeComponent(); 27 } 28 29 private void EReportMain_Load(object sender, EventArgs e) 30 { 31 Cursor.Current = Cursors.WaitCursor; 32 gridMain.Rows.Clear(); 33 myPopupMenu = new E_Report.Cells.Controllers.PopupMenu(gridMain); 34 35 report = new ReportDoc(); 36 report.NowReport = gridMain; 37 report.InitReport(); 38 Cursor.Current = Cursors.Default; 39 } 40 41 private void gridMain_MouseMove(object sender, MouseEventArgs e) 42 { 43 this.lbl_X.Text = e.X.ToString(); 44 this.lbl_Y.Text = e.Y.ToString(); 45 } 46 47 /// <summary> 48 /// 工具欄報表單元格事件 49 /// </summary> 50 /// <param name="sender"></param> 51 /// <param name="e"></param> 52 private void btn_GridTools_Click(object sender, EventArgs e) 53 { 54 string sType = ((Button)sender).Tag.ToString().Trim().ToLower(); 55 switch (sType) 56 { 57 58 case "cellproperty": // 單元格屬性設置 59 myPopupMenu.CellProperty_Click(sender, e); 60 break; 61 case "fontset": // 單元格字體設置 62 myPopupMenu.CellFont_Click(sender, e); 63 break; 64 case "fontcolor": // 文本字體顏色 65 myPopupMenu.CellForColor_Click(sender, e); 66 break; 67 case "backcolor": // 單元格背景色 68 myPopupMenu.CellBackColor_Click(sender, e); 69 break; 70 case "cellborder": // 單元格邊框設置 71 myPopupMenu.CellBorder_Click(sender, e); 72 break; 73 case "lock": // 設置表格只讀 74 myPopupMenu.LockReport_Click(sender, e); 75 break; 76 case "unlock": // 設置表格編輯 77 myPopupMenu.UnLockReport_Click(sender, e); 78 break; 79 case "alignleft": // 水平居左對齊 80 myPopupMenu.AlignLeft_Click(sender, e); 81 break; 82 case "aligncenter": // 水平居中對齊 83 myPopupMenu.AlignCenter_Click(sender, e); 84 break; 85 case "alignright": // 水平居右對齊 86 myPopupMenu.AlignRight_Click(sender, e); 87 break; 88 case "aligntop": // 垂直居上對齊 89 myPopupMenu.AlignTop_Click(sender, e); 90 break; 91 case "alignmiddle": // 垂直居中對齊 92 myPopupMenu.AlignMiddle_Click(sender, e); 93 break; 94 case "alignbottom": // 垂直居下對齊 95 myPopupMenu.AlignBottom_Click(sender, e); 96 break; 97 case "addindent": // 增加文本縮進 98 myPopupMenu.AddIndent_Click(sender, e); 99 break; 100 case "delindent": // 清除文本縮進 101 myPopupMenu.RemoveIndent_Click(sender, e); 102 break; 103 case "insertrow": // 插入後一行 104 myPopupMenu.InsertRow_Click(sender, e); 105 break; 106 case "appendrow": // 表格追加行 107 myPopupMenu.AddRow_Click(sender, e); 108 break; 109 case "delrow": // 刪除選中行 110 myPopupMenu.DeleteRows_Click(sender, e); 111 break; 112 case "hiderow": // 隱藏選中行 113 myPopupMenu.HideSelectRows_Click(sender, e); 114 break; 115 case "showrow": // 顯示選中行 116 myPopupMenu.ShowSelectRows_Click(sender, e); 117 break; 118 case "showallrow": // 顯示所有行 119 myPopupMenu.ShowAllRows_Click(sender, e); 120 break; 121 case "insertcol": // 插入左側列 122 myPopupMenu.InsertColumn_Click(sender, e); 123 break; 124 case "addcol": // 插入右側列 125 myPopupMenu.AddColumn_Click(sender, e); 126 break; 127 case "delcol": // 刪除選中列 128 myPopupMenu.DeleteColumns_Click(sender, e); 129 break; 130 case "hidecol": // 隱藏選中列 131 myPopupMenu.HideSelectColumns_Click(sender, e); 132 break; 133 case "showcol": // 顯示選中列 134 myPopupMenu.ShowSelectColumns_Click(sender, e); 135 break; 136 case "showallcol": // 顯示所有列 137 myPopupMenu.ShowAllColumns_Click(sender, e); 138 break; 139 case "mergecell": // 合並單元格 140 myPopupMenu.MergeCell_Click(sender, e); 141 break; 142 case "splitcell": // 拆分單元格 143 myPopupMenu.SplitCell_Click(sender, e); 144 break; 145 } 146 } 147 } 148 } View Code

3、報表控件DLL類庫部分

    裡面有我們自定義的 條碼控件、圖片控件、圖表控件

  表格內自定義圖表控件(曲線、柱狀、餅狀)源碼

1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Drawing; 5 using System.Drawing.Drawing2D; 6 using System.Drawing.Text; 7 8 namespace E_Report 9 { 10 /// <summary> 11 /// 圖表屬性 12 /// </summary> 13 /// <summary> 14 /// 報表圖表類庫 15 /// </summary> 16 public class EChart 17 { 18 #region 屬性方法 19 20 #region 臨時變量 21 22 /// <summary> 23 /// 臨時變量--關聯單元格行號 24 /// </summary> 25 private int _row = 0; 26 27 /// <summary> 28 /// 獲取--設置--關聯單元格行號 29 /// </summary> 30 public int Row 31 { 32 get { return _row; } 33 set { _row = value; } 34 } 35 36 /// <summary> 37 /// 臨時變量--關聯單元格列號 38 /// </summary> 39 private int _col = 0; 40 41 /// <summary> 42 /// 獲取--設置--關聯單元格列號 43 /// </summary> 44 public int Col 45 { 46 get { return _col; } 47 set { _col = value; } 48 } 49 50 /// <summary> 51 /// 數據來源 52 /// </summary> 53 private string _t_DataFrom = "數據源"; 54 55 /// <summary> 56 /// 獲取--設置--數據來源 57 /// </summary> 58 public string T_DataFrom 59 { 60 get { return _t_DataFrom; } 61 set { _t_DataFrom = value; } 62 } 63 64 /// <summary> 65 /// 數據源名稱 66 /// </summary> 67 private string _t_DsName = ""; 68 69 /// <summary> 70 /// 獲取--設置--數據源名稱 71 /// </summary> 72 public string T_DsName 73 { 74 get { return _t_DsName; } 75 set { _t_DsName = value; } 76 } 77 78 /// <summary> 79 /// 項目名稱 80 /// </summary> 81 private string _t_ItemName = ""; 82 83 /// <summary> 84 /// 獲取--設置--項目名稱 85 /// </summary> 86 public string T_ItemName 87 { 88 get { return _t_ItemName; } 89 set { _t_ItemName = value; } 90 } 91 92 /// <summary> 93 /// 項目數值 94 /// </summary> 95 private string _t_ItemValue = ""; 96 97 /// <summary> 98 /// 獲取--設置--項目數值 99 /// </summary> 100 public string T_ItemValue 101 { 102 get { return _t_ItemValue; } 103 set { _t_ItemValue = value; } 104 } 105 106 /// <summary> 107 /// X軸刻度 108 /// </summary> 109 private string _t_XScale = ""; 110 111 /// <summary> 112 /// 獲取--設置--X軸刻度 113 /// </summary> 114 public string T_XScale 115 { 116 get { return _t_XScale; } 117 set { _t_XScale = value; } 118 } 119 120 121 #endregion 122 123 #region 圖表屬性 124 125 /// <summary> 126 /// 圖表名稱ID 127 /// </summary> 128 private string _name = ""; 129 130 /// <summary> 131 /// 獲取--設置--圖表名稱ID 132 /// </summary> 133 public string Name 134 { 135 get { return _name; } 136 set { _name = value; } 137 } 138 139 /// <summary> 140 /// 圖表類型 141 /// </summary> 142 private EChartType _chartType = EChartType.Curve; 143 144 /// <summary> 145 /// 獲取--設置--圖表類型 146 /// 默認:Line 折曲線 147 /// </summary> 148 public EChartType ChartType 149 { 150 get { return _chartType; } 151 set { _chartType = value; } 152 } 153 154 /// <summary> 155 /// 圖表寬度 156 /// </summary> 157 private int _chartWidth = 0; 158 159 /// <summary> 160 /// 獲取--設置--圖表寬度 161 /// </summary> 162 public int ChartWidth 163 { 164 get { return _chartWidth; } 165 set { _chartWidth = value; } 166 } 167 168 /// <summary> 169 /// 圖表高度 170 /// </summary> 171 private int _chartHeight = 0; 172 173 /// <summary> 174 /// 獲取--設置--圖表高度 175 /// </summary> 176 public int ChartHeight 177 { 178 get { return _chartHeight; } 179 set { _chartHeight = value; } 180 } 181 182 /// <summary> 183 /// 圖表背景顏色 184 /// </summary> 185 private Color _backColor = Color.White; 186 187 /// <summary> 188 /// 獲取--設置--圖表背景顏色 189 /// </summary> 190 public Color BackColor 191 { 192 get { return _backColor; } 193 set { _backColor = value; } 194 } 195 196 /// <summary> 197 /// 是否顯示圖表邊框 198 /// </summary> 199 private bool _showBorder = true; 200 201 /// <summary> 202 /// 獲取--設置--是否顯示圖表邊框 203 /// 默認:true 顯示 204 /// </summary> 205 public bool ShowBorder 206 { 207 get { return _showBorder; } 208 set { _showBorder = value; } 209 } 210 211 /// <summary> 212 /// 圖表邊框顏色 213 /// </summary> 214 private Color _borderColor = Color.LightGray; 215 216 /// <summary> 217 /// 獲取--設置--圖表邊框顏色 218 /// </summary> 219 public Color BorderColor 220 { 221 get { return _borderColor; } 222 set { _borderColor = value; } 223 } 224 225 /// <summary> 226 /// 是否顯示網格線 227 /// </summary> 228 private bool _showGrid = true; 229 230 /// <summary> 231 /// 獲取--設置--是否顯示網格線 232 /// 默認:true 顯示 233 /// </summary> 234 public bool ShowGrid 235 { 236 get { return _showGrid; } 237 set { _showGrid = value; } 238 } 239 240 /// <summary> 241 /// 線條張力系數 242 /// </summary> 243 private float _lineTension = 0.3f; 244 245 /// <summary> 246 /// 獲取--設置--線條張力系數 247 /// 默認:0.3 248 /// </summary> 249 public float LineTension 250 { 251 get { return _lineTension; } 252 set 253 { 254 if (value < 0.0f && value > 1.0f) 255 _lineTension = 0.5f; 256 else 257 _lineTension = value; 258 } 259 } 260 261 #endregion 262 263 #region 標題屬性 264 265 /// <summary> 266 /// 是否顯示主標題 267 /// </summary> 268 private bool _showTitle = true; 269 270 /// <summary> 271 /// 獲取--設置--是否顯示主標題 272 /// 默認:true 顯示 273 /// </summary> 274 public bool ShowTitle 275 { 276 get { return _showTitle; } 277 set { _showTitle = value; } 278 } 279 280 /// <summary> 281 /// 主標題文本 282 /// </summary> 283 private string _title = ""; 284 285 /// <summary> 286 /// 獲取--設置--主標題文本 287 /// </summary> 288 public string Title 289 { 290 get { return _title; } 291 set { _title = value; } 292 } 293 294 /// <summary> 295 /// 主標題字體 296 /// </summary> 297 private Font _titleFont = new Font("黑體", 12); 298 299 /// <summary> 300 /// 獲取--設置--主標題字體 301 /// </summary> 302 public Font TitleFont 303 { 304 get { return _titleFont; } 305 set { _titleFont = value; } 306 } 307 308 /// <summary> 309 /// 主標題顏色 310 /// </summary> 311 private Color _titleColor = Color.Black; 312 313 /// <summary> 314 /// 獲取--設置--主標題顏色 315 /// </summary> 316 public Color TitleColor 317 { 318 get { return _titleColor; } 319 set { _titleColor = value; } 320 } 321 322 /// <summary> 323 /// 主標題對齊方式 324 /// </summary> 325 private EAlign _titleAlign = EAlign.center; 326 327 /// <summary> 328 /// 獲取--設置--主標題對齊方式 329 /// </summary> 330 public EAlign TitleAlign 331 { 332 get { return _titleAlign; } 333 set { _titleAlign = value; } 334 } 335 336 /// <summary> 337 /// 是否顯示副標題 338 /// </summary> 339 private bool _showSubTilte = true; 340 341 /// <summary> 342 /// 獲取--設置--是否顯示副標題 343 /// 默認:true 顯示 344 /// </summary> 345 public bool ShowSubTitle 346 { 347 get { return _showSubTilte; } 348 set { _showSubTilte = value; } 349 } 350 351 /// <summary> 352 /// 副標題文本 353 /// </summary> 354 private string _subTitle = ""; 355 356 /// <summary> 357 /// 獲取--設置--副標題文本 358 /// </summary> 359 public string SubTitle 360 { 361 get { return _subTitle; } 362 set { _subTitle = value; } 363 } 364 365 /// <summary> 366 /// 副標題字體 367 /// </summary> 368 private Font _subTitleFont = new Font("黑體", 10); 369 370 /// <summary> 371 /// 獲取--設置--副標題字體 372 /// </summary> 373 public Font SubTitleFont 374 { 375 get { return _subTitleFont; } 376 set { _subTitleFont = value; } 377 } 378 379 /// <summary> 380 /// 副標題顏色 381 /// </summary> 382 private Color _subTitleColor = Color.Blue; 383 384 /// <summary> 385 /// 獲取--設置--副標題顏色 386 /// </summary> 387 public Color SubTitleColor 388 { 389 get { return _subTitleColor; } 390 set { _subTitleColor = value; } 391 } 392 393 /// <summary> 394 /// 副標題對齊方式 395 /// </summary> 396 private EAlign _subTitleAlign = EAlign.center; 397 398 /// <summary> 399 /// 獲取--設置--副標題對齊方式 400 /// </summary> 401 public EAlign SubTitleAlign 402 { 403 get { return _subTitleAlign; } 404 set { _subTitleAlign = value; } 405 } 406 407 /// <summary> 408 /// 副標題水平方向偏移量 409 /// + - 整數 410 /// </summary> 411 private int _subTitleOffset = 0; 412 413 /// <summary> 414 /// 獲取--設置--副標題水平方向偏移量 415 /// </summary> 416 public int SubTitleOffset 417 { 418 get { return _subTitleOffset; } 419 set { _subTitleOffset = value; } 420 } 421 422 #endregion 423 424 #region 圖例屬性 425 426 /// <summary> 427 /// 是否顯示圖例 428 /// </summary> 429 private bool _showLegend = true; 430 431 /// <summary> 432 /// 是否顯示圖例 433 /// </summary> 434 public bool ShowLegend 435 { 436 get { return _showLegend; } 437 set { _showLegend = value; } 438 } 439 440 /// <summary> 441 /// 圖例字體 442 /// </summary> 443 private Font _legendFont = new Font("宋體", 9); 444 445 /// <summary> 446 /// 獲取--設置--圖例字體 447 /// </summary> 448 public Font LegendFont 449 { 450 get { return _legendFont; } 451 set { _legendFont = value; } 452 } 453 454 /// <summary> 455 /// 圖例字體顏色 456 /// </summary> 457 private Color _legendColor = Color.Black; 458 459 /// <summary> 460 /// 獲取--設置--圖例字體顏色 461 /// </summary> 462 public Color LegendColor 463 { 464 get { return _legendColor; } 465 set { _legendColor = value; } 466 } 467 468 /// <summary> 469 /// 圖例對齊方式 470 /// </summary> 471 private EAlign _legendAlign = EAlign.center; 472 473 /// <summary> 474 /// 獲取--設置--圖例對齊方式 475 /// </summary> 476 public EAlign LegendAlign 477 { 478 get { return _legendAlign; } 479 set { _legendAlign = value; } 480 } 481 482 #endregion 483 484 #region 坐標屬性 485 486 /// <summary> 487 /// 獲取--X軸分割段數 488 /// </summary> 489 public int XSplitNum 490 { 491 get { return _xScaleValues.Count; } 492 } 493 494 /// <summary> 495 /// Y軸分割段數 496 /// </summary> 497 private int _ySplitNum = 5; 498 499 /// <summary> 500 /// 獲取--設置--分割段數 501 /// 默認:5 502 /// 范圍:最小5 503 /// </summary> 504 public int YSplitNum 505 { 506 get { return _ySplitNum; } 507 set 508 { 509 if (value < 5) 510 _ySplitNum = 5; 511 else 512 _ySplitNum = value; 513 514 } 515 } 516 517 /// <summary> 518 /// X 軸標 519 /// </summary> 520 private string _xAxisText = ""; 521 522 /// <summary> 523 /// 獲取--設置--X 軸標 524 /// </summary> 525 public string XAxisText 526 { 527 get { return _xAxisText; } 528 set { _xAxisText = value; } 529 } 530 531 /// <summary> 532 /// Y 軸標 533 /// </summary> 534 private string _yAxisText = ""; 535 536 /// <summary> 537 /// 獲取--設置--Y 軸標 538 /// </summary> 539 public string YAxisText 540 { 541 get { return _yAxisText; } 542 set { _yAxisText = value; } 543 } 544 545 /// <summary> 546 /// X軸文本旋轉角度 547 /// 默認:0 548 /// 范圍:0~90 549 /// </summary> 550 private float _xRotateAngle = 0.0f; 551 552 /// <summary> 553 /// 獲取--設置--X軸文本旋轉角度 554 /// </summary> 555 public float XRotateAngle 556 { 557 get { return _xRotateAngle; } 558 set 559 { 560 if (value >= 0.0f && value <= 90.0f) 561 _xRotateAngle = value; 562 else 563 _xRotateAngle = 0.0f; 564 } 565 } 566 567 #endregion 568 569 #region 繪圖變量 570 571 /// <summary> 572 /// 繪圖對象 573 /// </summary> 574 private Graphics g = null; 575 576 /// <summary> 577 /// 圖表顏色數組 578 /// </summary> 579 private static Color[] ChartColor = { 580 Color.Red, Color.Blue, Color.Orange, Color.Green, Color.Cyan, Color.Purple, 581 Color.Coral, Color.Chocolate, Color.Gray, Color.Gold, Color.Lavender, Color.Linen, 582 Color.Magenta, Color.Moccasin, Color.Navy, Color.Olive, Color.Peru, Color.Plum, 583 Color.Purple, Color.Salmon, Color.Sienna, Color.Silver, Color.Tan, Color.Tomato, 584 Color.Violet, Color.Turquoise, Color.Transparent 585 }; 586 587 /// <summary> 588 /// 邊距10px 589 /// </summary> 590 private float Margin = 10; 591 592 /// <summary> 593 /// 起點 X 坐標 594 /// </summary> 595 private float Start_X = 0; 596 597 /// <summary> 598 /// 起點 Y 坐標 599 /// </summary> 600 private float Start_Y = 0; 601 602 /// <summary> 603 /// 終點 X 坐標 604 /// </summary> 605 private float End_X = 0; 606 607 /// <summary> 608 /// 終點 Y 坐標 609 /// </summary> 610 private float End_Y = 0; 611 612 /// <summary> 613 /// X軸刻度寬度 614 /// </summary> 615 private float XScaleWidth = 0; 616 617 /// <summary> 618 /// Y軸刻度寬度 619 /// </summary> 620 private float YScaleWidth = 0; 621 622 /// <summary> 623 /// Y軸刻度間隔值 624 /// 說明:Y軸坐標全部采用整數,表示每個間隔的計算單位值 625 /// 包含正負數 626 /// </summary> 627 private double YScale_SplitValue = 0; 628 629 /// <summary> 630 /// Y軸刻度開始值 631 /// </summary> 632 private double YScale_StartValue = 0; 633 634 /// <summary> 635 /// 坐標軸原點坐標 636 /// </summary> 637 private PointF AxisZeroPt = new PointF(0f, 0f); 638 639 /// <summary> 640 /// 圖表數據 641 /// </summary> 642 private string _chartData = ""; 643 644 /// <summary> 645 /// 獲取--設置--圖表數據 646 /// </summary> 647 public string ChartData 648 { 649 get { return _chartData; } 650 set { _chartData = value; } 651 } 652 653 /// <summary> 654 /// 繪圖筆刷 655 /// </summary> 656 private Brush brush; 657 658 /// <summary> 659 /// 繪制畫筆 660 /// </summary> 661 private Pen pen; 662 663 /// <summary> 664 /// 繪圖矩形 665 /// </summary> 666 private RectangleF rectF = new RectangleF(0, 0, 0, 0); 667 668 /// <summary> 669 /// 字符格式化 670 /// </summary> 671 private StringFormat stringFormat; 672 673 /// <summary> 674 /// 臨時變量 最大值 675 /// </summary> 676 private double myMaxValue = 0; 677 678 /// <summary> 679 /// 臨時變量 最小值 680 /// </summary> 681 private double myMinValue = 0; 682 683 /// <summary> 684 /// 臨時變量 X軸刻度最大高度 685 /// 用於繪制坐標軸的時候進行偏移 686 /// </summary> 687 private float myXScaleMaxHeight = 0; 688 689 /// <summary> 690 /// 臨時變量 Y軸刻度值字符串的最大寬度 691 /// 用於繪制坐標軸的時候進行偏移 692 /// </summary> 693 private float myYScaleMaxWidth = 0; 694 695 #endregion 696 697 #region 圖表數據 698 699 /// <summary> 700 /// X軸刻度值數組 701 /// </summary> 702 private List<string> _xScaleValues = new List<string>(); 703 704 /// <summary> 705 /// 獲取--設置--X軸刻度值數組 706 /// </summary> 707 public List<string> XScaleValues 708 { 709 get { return _xScaleValues; } 710 set { _xScaleValues = value; } 711 } 712 713 /// <summary> 714 /// 圖表數據 715 /// </summary> 716 private List<EChartData> _chartDataArray = new List<EChartData>(); 717 718 /// <summary> 719 /// 獲取--設置--圖表數據 720 /// </summary> 721 public List<EChartData> ChartDataArray 722 { 723 get { return _chartDataArray; } 724 set { _chartDataArray = value; } 725 } 726 727 #endregion 728 729 #endregion 730 731 #region 構造方法 732 733 /// <summary> 734 /// 構造函數 735 /// </summary> 736 public EChart() 737 { 738 739 } 740 741 /// <summary> 742 /// 構造函數 743 /// </summary> 744 /// <param name="eChart"></param> 745 public EChart(EChart eChart) 746 { 747 748 } 749 750 #endregion 751 752 #region 生成圖表 753 754 /// <summary> 755 /// 生成圖表 756 /// </summary> 757 /// <returns>返回:圖表圖像</returns> 758 public Bitmap CreateImage() 759 { 760 Bitmap ChartImage = new Bitmap(ChartWidth, ChartHeight); 761 g = Graphics.FromImage(ChartImage); 762 g.SmoothingMode = SmoothingMode.Default; 763 g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; 764 g.Clear(Color.White); 765 766 Start_X = Margin; 767 Start_Y = Margin; 768 End_X = ChartWidth - Margin; 769 End_Y = ChartHeight - Margin; 770 771 DrawChart(); 772 773 g.Dispose(); 774 775 return ChartImage; 776 } 777 778 #endregion 779 780 #region 繪制方法 781 782 /// <summary> 783 /// 繪制圖表 784 /// </summary> 785 private void DrawChart() 786 { 787 DrawChart_InitGraph(); 788 DrawChart_MainTitle(); 789 DrawChart_SubTitle(); 790 DrawChart_Legend(); 791 DrawChart_YAxisText(); 792 if (ChartType != EChartType.Pie) 793 { 794 DrawChart_Axis(); 795 if (ChartType == EChartType.Curve) 796 DrawChart_Curve(); 797 else 798 DrawChart_Bar(); 799 } 800 else 801 { 802 DrawChart_Pie(); 803 } 804 } 805 806 /// <summary> 807 /// 繪制圖表--繪制背景圖 808 /// </summary> 809 private void DrawChart_InitGraph() 810 { 811 // 繪制圖表外圍邊框 812 if (_showBorder) 813 g.DrawRectangle(new Pen(BorderColor, 1), 0, 0, (ChartWidth - 1), (ChartHeight - 1)); 814 815 // 填充圖表背景顏色 816 g.FillRectangle(new SolidBrush(BackColor), 1, 1, ChartWidth - 2, ChartHeight - 2); 817 818 } 819 820 /// <summary> 821 /// 繪制圖表--繪制主標題 822 /// </summary> 823 private void DrawChart_MainTitle() 824 { 825 if (ShowTitle) 826 { 827 if (Title != null && Title.Trim() != "") 828 { 829 brush = new SolidBrush(TitleColor); // 矩形填充筆刷 830 SizeF sizeF = g.MeasureString(Title, TitleFont); // 測試字體大小 831 stringFormat = new StringFormat(); // 格式化字符串 832 stringFormat.LineAlignment = StringAlignment.Center; // 垂直對齊方式 833 switch (TitleAlign) // 水平對齊方式 834 { 835 case EAlign.center: 836 stringFormat.Alignment = StringAlignment.Center; 837 break; 838 case EAlign.right: 839 stringFormat.Alignment = StringAlignment.Far; 840 break; 841 default: 842 stringFormat.Alignment = StringAlignment.Near; 843 break; 844 } 845 846 rectF = new RectangleF(Start_X, Start_Y, (float)(ChartWidth - 4), sizeF.Height); // 文字的矩形 847 g.DrawString(Title, TitleFont, brush, rectF, stringFormat); // 繪制主標題 848 Start_Y += sizeF.Height + 3f; // 設置Y起點值 + 3px 849 } 850 } 851 } 852 853 /// <summary> 854 /// 繪制圖表--繪制副標題 855 /// </summary> 856 private void DrawChart_SubTitle() 857 { 858 if (ShowSubTitle) 859 { 860 if (SubTitle != null && SubTitle.Trim() != "") 861 { 862 brush = new SolidBrush(SubTitleColor); // 矩形填充筆刷 863 SizeF sizeF = g.MeasureString(SubTitle, SubTitleFont); // 測試字體大小 864 stringFormat = new StringFormat(); // 格式化字符串 865 stringFormat.LineAlignment = StringAlignment.Center; // 垂直對齊方式 866 switch (SubTitleAlign) // 水平對齊方式 867 { 868 case EAlign.center: 869 stringFormat.Alignment = StringAlignment.Center; 870 break; 871 case EAlign.right: 872 stringFormat.Alignment = StringAlignment.Far; 873 break; 874 default: 875 stringFormat.Alignment = StringAlignment.Near; 876 break; 877 } 878 879 rectF = new RectangleF(Start_X + (float)SubTitleOffset, Start_Y, (float)(ChartWidth - 4), sizeF.Height); // 文字的矩形 880 g.DrawString(SubTitle, SubTitleFont, brush, rectF, stringFormat); // 繪制副標題 881 Start_Y += sizeF.Height + 3f; // 設置Y起點值 + 3px 882 } 883 } 884 885 } 886 887 /// <summary> 888 /// 繪制圖表--繪制圖例 889 /// </summary> 890 private void DrawChart_Legend() 891 { 892 // 計算項目顏色 893 int tmIndex = 0; 894 for (int m = 0; m < ChartDataArray.Count; m++) 895 { 896 tmIndex = m % ChartColor.Length; 897 ChartDataArray[m].ItemColor = ChartColor[tmIndex]; 898 } 899 900 // 圖例的高度最大40px 3排 901 if (ShowLegend) 902 { 903 // 計算文字大小 904 int LegendCount = ChartDataArray.Count; 905 Font tFont = new Font("宋體", 9); 906 for (int t = 0; t < LegendCount; t++) 907 { 908 SizeF tmSize = new SizeF(); 909 tmSize = g.MeasureString(ChartDataArray[t].Name, tFont); 910 ChartDataArray[t].NameSize = tmSize; 911 } 912 913 #region 繪制一排圖例 914 915 // 首先判定一行夠不夠 916 float largMax = 0; 917 for (int t = 0; t < LegendCount; t++) 918 { 919 if (t == 0) 920 largMax += ChartDataArray[t].NameSize.Width; 921 else 922 largMax += (35f + ChartDataArray[t].NameSize.Width); 923 } 924 925 if (largMax <= End_X - Start_X) // 圖例只需一排 926 { 927 End_Y -= 12.0f; 928 float tmX = (End_X - Start_X - largMax) / 2 + Start_X; 929 float tmY = End_Y; 930 for (int n = 0; n < LegendCount; n++) 931 { 932 g.FillRectangle(new SolidBrush(ChartDataArray[n].ItemColor), tmX, tmY + 1, 15, 10); 933 tmX += 20; 934 g.DrawString(ChartDataArray[n].Name, new Font("宋體", 9), new SolidBrush(Color.Black), tmX, tmY); 935 tmX += 15 + ChartDataArray[n].NameSize.Width; 936 } 937 } 938 939 #endregion 940 941 #region 繪制多排圖例 942 943 // 圖例最多繪制三排 944 else 945 { 946 947 bool TwoLine = true; // 是否兩行:true 是; false: 否,為三行 948 949 // 判定兩排還是三排 950 float tmBX = Start_X - 5; 951 int tmBC = (int)Math.Ceiling((double)LegendCount / 2); 952 for (int T = 0; T < tmBC; T++) 953 { 954 float tmBW1 = -1F, tmBW2 = -1F, tmBM = 0F; 955 tmBW1 = ChartDataArray[T * 2].NameSize.Width; 956 if (ChartDataArray.Count > (T * 2 + 1)) 957 tmBW2 = ChartDataArray[T * 2 + 1].NameSize.Width; 958 tmBM = tmBW1 > tmBW2 ? tmBW1 : tmBW2; 959 tmBX += 35 + tmBM; 960 if (tmBX > (End_X + 5)) 961 { 962 TwoLine = false; 963 break; 964 } 965 } 966 967 // 繪制兩排圖例 968 if (TwoLine) 969 { 970 End_Y -= 24.0f; 971 float tmTX = (End_X + 10 - tmBX + Start_X + 5) / 2; // 開始位置保持兩排水平居中 972 float tmTY = End_Y; 973 int tmTM = (int)Math.Ceiling((double)LegendCount / 2); 974 975 // 繪制兩排圖例 976 for (int T = 0; T < tmTM; T++) 977 { 978 float tmTW1 = -1F, tmTW2 = -1F, tmTW3 = 0F; 979 tmTW1 = ChartDataArray[T * 2].NameSize.Width; 980 if (ChartDataArray.Count > (T * 2 + 1)) 981 tmTW2 = ChartDataArray[T * 2 + 1].NameSize.Width; 982 tmTW3 = tmTW1 > tmTW2 ? tmTW1 : tmTW2; 983 984 // 繪制第一排圖例 985 g.FillRectangle(new SolidBrush(ChartDataArray[T * 2].ItemColor), tmTX, tmTY + 1, 15, 10); 986 g.DrawString(ChartDataArray[T * 2].Name, new Font("宋體", 9), new SolidBrush(Color.Black), (tmTX + 20), tmTY); 987 988 // 繪制第二排圖例 989 if (tmTW2 > 0) 990 { 991 g.FillRectangle(new SolidBrush(ChartDataArray[T * 2 + 1].ItemColor), tmTX, (tmTY + 16 + 1), 15, 10); 992 g.DrawString(ChartDataArray[T * 2 + 1].Name, new Font("宋體", 9), new SolidBrush(Color.Black), (tmTX + 20), (tmTY + 16)); 993 } 994 tmTX += 35 + tmTW3; 995 } 996 } 997 998 // 繪制三排圖例 999 else 1000 { 1001 End_Y -= 40.0f; 1002 // 如果三排還不夠,那麼就不管了,繪制超出范圍就超出范圍 1003 float tmSX = Start_X - 5; 1004 float tmSY = End_Y; 1005 int tmSC = (int)Math.Ceiling((double)LegendCount / 3); 1006 bool CanFlag = true; // 三排是否足夠 1007 1008 // 首先計算三排的能排下的居中位置 1009 for (int n = 0; n < tmSC; n++) 1010 { 1011 float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F; 1012 tmSW1 = ChartDataArray[n * 3].NameSize.Width; 1013 if (ChartDataArray.Count > (n * 3 + 1)) 1014 tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width; 1015 if (ChartDataArray.Count > (n * 3 + 2)) 1016 tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width; 1017 tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2; 1018 tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3; 1019 tmSX += 35 + tmSW4; 1020 if (tmSX > (End_X + 5)) 1021 { 1022 CanFlag = false; 1023 break; 1024 } 1025 } 1026 1027 // 再次執行三排繪制 1028 if (CanFlag) // 三排足夠,則設置居中開始位置 1029 tmSX = (End_X + 10 - tmSX + Start_X + 5) / 2; 1030 else 1031 tmSX = Start_X - 5; // 三排排不下的情況就從5px 開始 1032 1033 for (int n = 0; n < tmSC; n++) 1034 { 1035 float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F; 1036 tmSW1 = ChartDataArray[n * 3].NameSize.Width; 1037 if (ChartDataArray.Count > (n * 3 + 1)) 1038 tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width; 1039 if (ChartDataArray.Count > (n * 3 + 2)) 1040 tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width; 1041 tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2; 1042 tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3; 1043 1044 // 繪制第一排圖例 1045 g.FillRectangle(new SolidBrush(ChartDataArray[n * 3].ItemColor), tmSX, (tmSY + 1), 15, 10); 1046 g.DrawString(ChartDataArray[n * 3].Name, new Font("宋體", 9), new SolidBrush(Color.Black), (tmSX + 20), tmSY); 1047 1048 // 繪制第二排圖例 1049 if (tmSW2 > 0) 1050 { 1051 g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 1].ItemColor), tmSX, (tmSY + 16 + 1), 15, 10); 1052 g.DrawString(ChartDataArray[n * 3 + 1].Name, new Font("宋體", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 16)); 1053 } 1054 1055 // 繪制第三排圖例 1056 if (tmSW3 > 0) 1057 { 1058 g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 2].ItemColor), tmSX, (tmSY + 32 + 1), 15, 10); 1059 g.DrawString(ChartDataArray[n * 3 + 2].Name, new Font("宋體", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 32)); 1060 } 1061 1062 tmSX += 35 + tmSW4; 1063 } 1064 } 1065 } 1066 1067 #endregion 1068 } 1069 } 1070 1071 /// <summary> 1072 /// 繪制圖表--繪制X軸標 1073 /// </summary> 1074 /// <param name="g"></param> 1075 private void DrawChart_XAxisText() 1076 { 1077 // X軸標就不繪制了,因為空間不夠,所以不執行X軸標的繪制 1078 } 1079 1080 /// <summary> 1081 /// 繪制圖表--繪制Y軸標 1082 /// </summary> 1083 private void DrawChart_YAxisText() 1084 { 1085 if (ChartType != EChartType.Pie) 1086 { 1087 if (YAxisText != null && YAxisText.Trim() != "") 1088 { 1089 brush = new SolidBrush(Color.Gray); 1090 stringFormat = new StringFormat(); // 格式化字符串 1091 stringFormat.LineAlignment = StringAlignment.Near; // 垂直對齊方式 1092 stringFormat.Alignment = StringAlignment.Near; // 水平對齊方式 1093 SizeF sizeF = g.MeasureString(YAxisText, new Font("宋體", 9)); // 測量文字大小 1094 rectF = new RectangleF(Start_X, Start_Y, sizeF.Width, sizeF.Height); // 文字外圍矩形 1095 g.TranslateTransform((Start_X - Start_Y), (Start_X + Start_Y + sizeF.Width)); // 設置位置移動 X,Y 1096 g.RotateTransform(270); // 旋轉270度 以左上角作為旋轉原點 1097 g.DrawString(YAxisText, new Font("宋體", 9), brush, rectF, stringFormat); 1098 g.ResetTransform(); 1099 1100 Start_X += sizeF.Height + 2; // 加2個像素 1101 } 1102 } 1103 } 1104 1105 /// <summary> 1106 /// 繪制圖表--繪制坐標軸 1107 /// </summary> 1108 private void DrawChart_Axis() 1109 { 1110 // 1、圖表區下移10PX 1111 Start_Y += 10; 1112 1113 // 2、計算坐標軸參數 1114 Calc_XScaleHeight(); 1115 Calc_YScaleValue(); 1116 1117 // 3、計算原點坐標值 1118 AxisZeroPt = new PointF(0f, 0f); // 坐標軸原點坐標 1119 AxisZeroPt.X = Start_X + myYScaleMaxWidth; 1120 AxisZeroPt.Y = End_Y - myXScaleMaxHeight; 1121 1122 // 3.1、繪制坐標軸 1123 Pen pen2 = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 2f); 1124 g.DrawLine(pen2, (Start_X + myYScaleMaxWidth - 4f), (End_Y - myXScaleMaxHeight), End_X + 2, (End_Y - myXScaleMaxHeight)); // 繪制 X坐標軸 1125 g.DrawLine(pen2, (Start_X + myYScaleMaxWidth), (End_Y - myXScaleMaxHeight + 4f), (Start_X + myYScaleMaxWidth), Start_Y - 2); // 繪制 Y坐標軸 1126 1127 // 3.2、計算分段寬 1128 XScaleWidth = (End_X - Start_X - myYScaleMaxWidth) / XSplitNum; // 計算X軸分段寬 1129 YScaleWidth = (End_Y - Start_Y - myXScaleMaxHeight) / YSplitNum; // 計算Y軸分段寬 1130 1131 // 3.3、繪制刻度值 1132 pen = new Pen(Color.LightGray, 1f); 1133 pen.DashStyle = DashStyle.Dash; 1134 for (int k = 0; k < XSplitNum; k++) // 繪制X軸刻度線 刻度值 1135 { 1136 // 繪制X軸刻度線 1137 g.DrawLine(pen2, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y + 4f); 1138 1139 // 繪制X軸刻度值 1140 g.TranslateTransform(AxisZeroPt.X + XScaleWidth * k + 15f * XRotateAngle / 90 + 4f, AxisZeroPt.Y + 4f); // 平移原點 1141 g.RotateTransform(XRotateAngle, MatrixOrder.Prepend); // 旋轉圖像 1142 g.DrawString(XScaleValues[k], new Font("宋體", 9f), new SolidBrush(Color.Black), 0, 0); // 繪制字符 1143 g.ResetTransform(); 1144 } 1145 1146 for (int k = 0; k < YSplitNum; k++) 1147 { 1148 // 繪制Y軸刻度線 1149 g.DrawLine(pen2, AxisZeroPt.X - 4, (AxisZeroPt.Y - YScaleWidth * (k + 1)), AxisZeroPt.X, (AxisZeroPt.Y - YScaleWidth * (k + 1))); 1150 1151 // 繪制Y軸刻度值 1152 string tmYvalue = (YScale_StartValue + k * YScale_SplitValue).ToString(); 1153 SizeF tmF = g.MeasureString(tmYvalue, new Font("宋體", 9)); 1154 g.DrawString(tmYvalue, new Font("宋體", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * k - tmF.Height / 2 + 1)); 1155 1156 if (k == YSplitNum - 1) 1157 { 1158 tmYvalue = (YScale_StartValue + (k + 1) * YScale_SplitValue).ToString(); 1159 tmF = g.MeasureString(tmYvalue, new Font("宋體", 9)); 1160 g.DrawString(tmYvalue, new Font("宋體", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * (k + 1) - tmF.Height / 2 + 1)); 1161 } 1162 } 1163 1164 1165 // 3.4、繪制網格線 1166 if (ShowGrid) 1167 { 1168 for (int k = 1; k <= YSplitNum; k++) // 繪制X軸平行橫向輔助線 1169 g.DrawLine(pen, AxisZeroPt.X + 1, (AxisZeroPt.Y - YScaleWidth * k), End_X, (AxisZeroPt.Y - YScaleWidth * k)); 1170 1171 for (int k = 1; k <= XSplitNum; k++) // 繪制Y軸平行縱向輔助線 1172 g.DrawLine(pen, (AxisZeroPt.X + XScaleWidth * k), Start_Y, (AxisZeroPt.X + XScaleWidth * k), AxisZeroPt.Y - 1); 1173 } 1174 1175 pen2.Dispose(); 1176 } 1177 1178 /// <summary> 1179 /// 繪制曲線圖 1180 /// </summary> 1181 private void DrawChart_Curve() 1182 { 1183 g.SmoothingMode = SmoothingMode.HighQuality; 1184 g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; 1185 g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; 1186 1187 int tmLength = 0; 1188 PointF[] CurvePointF = new PointF[tmLength]; 1189 foreach (EChartData iItem in this.ChartDataArray) 1190 { 1191 tmLength = iItem.Values.Count; 1192 CurvePointF = new PointF[tmLength]; 1193 pen = new Pen(iItem.ItemColor, 2.0f); 1194 for (int rr = 0; rr < iItem.Values.Count; rr++) 1195 { 1196 double dbValue = iItem.Values[rr]; 1197 CurvePointF[rr].X = AxisZeroPt.X + XScaleWidth * rr + XScaleWidth / 2; 1198 CurvePointF[rr].Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth; 1199 } 1200 1201 // 繪制曲線 1202 g.DrawCurve(pen, CurvePointF, LineTension); 1203 1204 // 繪制輔點 1205 for (int tt = 0; tt < CurvePointF.Length; tt++) 1206 { 1207 // 點標數據值 1208 string tmValStr = iItem.Values[tt].ToString(); 1209 1210 // 繪制數據點 1211 g.FillEllipse(new SolidBrush(iItem.ItemColor), CurvePointF[tt].X - 3, CurvePointF[tt].Y - 3, 6, 6); 1212 1213 // 繪制數據值 1214 SizeF tmValueSize = g.MeasureString(tmValStr, new Font("Arial", 9)); 1215 g.DrawString(tmValStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (CurvePointF[tt].X - tmValueSize.Width / 2), (CurvePointF[tt].Y - tmValueSize.Height - 2f)); 1216 } 1217 } 1218 } 1219 1220 /// <summary> 1221 /// 繪制柱狀圖 1222 /// </summary> 1223 private void DrawChart_Bar() 1224 { 1225 g.SmoothingMode = SmoothingMode.HighQuality; 1226 int tmLen = ChartDataArray.Count; // 柱形條目總數 1227 float tmBarWidth = XScaleWidth / (tmLen * 2 + 1); // 每條柱形寬度 平均分配 1228 if (tmBarWidth < 2) 1229 { 1230 tmBarWidth = 2f; 1231 } 1232 1233 for (int kk = 0; kk < this.ChartDataArray.Count; kk++) 1234 { 1235 EChartData iItem = this.ChartDataArray[kk]; 1236 pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.0f); 1237 for (int rr = 0; rr < iItem.Values.Count; rr++) 1238 { 1239 RectangleF barRect = new RectangleF(0, 0, 0, 0); 1240 double dbValue = iItem.Values[rr]; 1241 barRect.X = AxisZeroPt.X + XScaleWidth * rr + (tmBarWidth * ((kk + 1) * 2 - 1)); 1242 barRect.Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth; 1243 barRect.Width = tmBarWidth; 1244 barRect.Height = AxisZeroPt.Y - barRect.Y; 1245 1246 // 繪制柱形 1247 g.DrawRectangle(pen, barRect.X, barRect.Y, barRect.Width, barRect.Height); 1248 1249 brush = new SolidBrush(iItem.ItemColor); 1250 g.FillRectangle(brush, barRect.X + 1, barRect.Y + 1, barRect.Width - 2, barRect.Height - 2); 1251 1252 // 繪制數據 1253 SizeF tmValueSize = g.MeasureString(dbValue.ToString(), new Font("Arial", 9)); 1254 g.DrawString(dbValue.ToString(), new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (barRect.X + tmBarWidth / 2 - tmValueSize.Width / 2), (barRect.Y - tmValueSize.Height - 2f)); 1255 } 1256 } 1257 } 1258 1259 /// <summary> 1260 /// 繪制圖表--繪制餅狀圖 1261 /// </summary> 1262 private void DrawChart_Pie() 1263 { 1264 // 上下預留20 PX 為了標記餅圖的數據值 1265 Start_Y += 20; 1266 End_Y -= 20; 1267 1268 g.SmoothingMode = SmoothingMode.HighQuality; 1269 g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; 1270 g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; 1271 1272 // 矩形坐標點 1273 PointF piePoint = new PointF(0, 0); 1274 float tmPieW = End_X - Start_X; 1275 float tmPieH = End_Y - Start_Y; 1276 float tmPieR = tmPieW < tmPieH ? tmPieW / 2 : tmPieH / 2; // 半徑 1277 1278 piePoint.X = Start_X + tmPieW / 2 - tmPieR; 1279 piePoint.Y = Start_Y + tmPieH / 2 - tmPieR; 1280 1281 // 圓心坐標點 1282 PointF pieZero = new PointF(piePoint.X + tmPieR, piePoint.Y + tmPieR); 1283 1284 // 繪制外圍圓 1285 pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.5f); 1286 g.DrawEllipse(pen, piePoint.X - 5, piePoint.Y - 5, (tmPieR + 5) * 2, (tmPieR + 5) * 2); 1287 1288 // 計算總數 1289 double pieCountValue = 0; 1290 foreach (EChartData iItem in this.ChartDataArray) 1291 { 1292 if (iItem.Values.Count >= 1) 1293 pieCountValue += iItem.Values[0]; 1294 } 1295 1296 // 繪制扇形 1297 if (pieCountValue > 0) 1298 { 1299 float curAngle = 0; // 占比角度 1300 float sumAngle = 0; // 總角度和 1301 1302 foreach (EChartData iItem in this.ChartDataArray) 1303 { 1304 if (iItem.Values.Count >= 1) 1305 curAngle = (float)(iItem.Values[0] / pieCountValue * 360); 1306 else 1307 curAngle = 0; 1308 1309 // 填充筆刷 1310 brush = new SolidBrush(iItem.ItemColor); 1311 1312 // 繪制弧形 1313 g.FillPie(brush, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle); 1314 1315 // 繪制弧線 1316 g.DrawPie(pen, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle); 1317 1318 // 繪制數據 1319 float tmPre = (float)Math.Round((iItem.Values[0] / pieCountValue) * 100, 2); 1320 string tmStr = tmPre.ToString() + "%" + " [" + iItem.Values[0].ToString() + "]"; 1321 1322 // 內圓信息 1323 double relCur_X = tmPieR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180); 1324 double relCur_Y = tmPieR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180); 1325 double cur_X = relCur_X + pieZero.X; 1326 double cur_Y = pieZero.Y - relCur_Y; 1327 PointF cur_Point = new PointF((float)cur_X, (float)cur_Y); // 內圓上弧線中間點的坐標 1328 1329 // 外圓信息 1330 float largerR = tmPieR + 10; 1331 double relLarg_X = largerR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180); 1332 double relLarg_Y = largerR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180); 1333 double largerX = relLarg_X + pieZero.X; 1334 double largerY = pieZero.Y - relLarg_Y; 1335 PointF larger_Point = new PointF((float)largerX, (float)largerY); 1336 1337 SizeF calcSize = new SizeF(0, 0); 1338 1339 // 繪制鏈接斜線(內圓到外圓弧度中間點的連接線) 1340 g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), cur_Point, larger_Point); // 斜線 1341 1342 // 繪制橫向線條 1343 //*以下是對四個象限、以及對90度、180度、270度和360度的判斷*// 1344 float tmCurIf = sumAngle + curAngle / 2; 1345 if (tmCurIf <= 90) 1346 { 1347 g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y); // 橫線 1348 g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f); // 文字 1349 } 1350 else if (tmCurIf > 90 && tmCurIf <= 180) 1351 { 1352 calcSize = g.MeasureString(tmStr, new Font("Arial", 9)); 1353 g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y); // 橫線 1354 g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字 1355 } 1356 else if (tmCurIf > 180 && tmCurIf <= 270) 1357 { 1358 calcSize = g.MeasureString(tmStr, new Font("Arial", 9)); 1359 g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y); // 橫線 1360 g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字 1361 } 1362 else 1363 { 1364 g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y); // 橫線 1365 g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f); // 文字 1366 } 1367 1368 ////*以下是對四個象限、以及對90度、180度、270度和360度的判斷*// 1369 //if ((sumAngle + curAngle / 2) < 90) 1370 //{ 1371 // Half = sumAngle + curAngle / 2; 1372 // double tem_sin = Math.Sin(Pi / 180 * Half); 1373 // double tem_cos = Math.Cos(Pi / 180 * Half); 1374 1375 // //Math.PI 1376 1377 // float Px = (float)(tmPieR * tem_cos); 1378 // float Py = (float)(tmPieR * tem_sin); 1379 1380 // g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(Color.Black), piePoint.X + tmPieR + Px, piePoint.Y + Py); 1381 // //g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + x, 225 + y)); 1382 // //g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + x, 225 + y + 12)); 1383 //} 1384 1385 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 90) 1386 //{ 1387 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225, 225 + 125)); 1388 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225, 225 + 125 + 12)); 1389 //} 1390 1391 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 90 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 180) 1392 //{ 1393 // halfangle = (180 - tem_angle - Convert.ToSingle(arraylist_angle[i]) / 2); 1394 // double tem_sin = Math.Sin(T / 180 * halfangle); 1395 // double tem_cos = Math.Cos(T / 180 * halfangle); 1396 1397 // int y = Convert.ToInt32(125 * tem_sin); 1398 // int x = Convert.ToInt32(125 * tem_cos); 1399 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - x, 225 + y)); 1400 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - x, 225 + y + 12)); 1401 //} 1402 1403 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 180) 1404 //{ 1405 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - 125, 225)); 1406 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - 125, 225 + 12)); 1407 //} 1408 1409 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 180 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 270) 1410 //{ 1411 // halfangle = (tem_angle - 180 + Convert.ToSingle(arraylist_angle[i]) / 2); 1412 // double tem_sin = Math.Sin(T / 180 * halfangle); 1413 // double tem_cos = Math.Cos(T / 180 * halfangle); 1414 1415 // int y = Convert.ToInt32(125 * tem_sin); 1416 // int x = Convert.ToInt32(125 * tem_cos); 1417 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - x, 225 - y)); 1418 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - x, 225 - y + 12)); 1419 //} 1420 1421 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 270) 1422 //{ 1423 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225, 225 - 125)); 1424 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225, 225 - 125 + 12)); 1425 //} 1426 1427 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 270 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 360) 1428 //{ 1429 // halfangle = (360 - tem_angle - Convert.ToSingle(arraylist_angle[i]) / 2); 1430 // double tem_sin = Math.Sin(T / 180 * halfangle); 1431 // double tem_cos = Math.Cos(T / 180 * halfangle); 1432 1433 // int y = Convert.ToInt32(125 * tem_sin); 1434 // int x = Convert.ToInt32(125 * tem_cos); 1435 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + x, 225 - y)); 1436 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + x, 225 - y + 12)); 1437 //} 1438 1439 //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 360) 1440 //{ 1441 // g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + 125, 225)); 1442 // g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + 125, 225 + 12)); 1443 //} 1444 1445 1446 // 累加角度 1447 sumAngle += curAngle; 1448 1449 } 1450 1451 } 1452 } 1453 1454 #endregion 1455 1456 #region 輔助方法 1457 1458 /// <summary> 1459 /// 計算X軸刻度值最大高度 1460 /// </summary> 1461 /// <returns></returns> 1462 private void Calc_XScaleHeight() 1463 { 1464 SizeF tmMaxSizeF = new SizeF(0, 0); 1465 for (int t = 0; t < XScaleValues.Count; t++) 1466 { 1467 SizeF tmSizeF = g.MeasureString(XScaleValues[t], new Font("宋體", 9)); 1468 if (tmSizeF.Width > tmMaxSizeF.Width) 1469 { 1470 tmMaxSizeF.Width = tmSizeF.Width; 1471 tmMaxSizeF.Height = tmSizeF.Height; 1472 } 1473 } 1474 myXScaleMaxHeight = (((float)Math.Sqrt(tmMaxSizeF.Height * tmMaxSizeF.Height + tmMaxSizeF.Width * tmMaxSizeF.Width) - tmMaxSizeF.Height) * XRotateAngle / 90 + tmMaxSizeF.Height + 13f); 1475 } 1476 1477 /// <summary> 1478 /// 計算坐標Y軸的刻度值 1479 /// 適用於:曲線圖、柱狀圖 1480 /// 不適用:餅狀圖無需計算 1481 /// </summary> 1482 private void Calc_YScaleValue() 1483 { 1484 myMaxValue = 0; // 原始最大值 1485 myMinValue = 0; // 原始最小值 1486 1487 // 計算所有數據的最大值和最小值 1488 for (int mm = 0; mm < this.ChartDataArray.Count; mm++) 1489 { 1490 for (int nn = 0; nn < this.ChartDataArray[mm].Values.Count; nn++) 1491 { 1492 double iData = this.ChartDataArray[mm].Values[nn]; 1493 if (mm == 0 && nn == 0) 1494 { 1495 myMaxValue = iData; 1496 myMinValue = iData; 1497 } 1498 else 1499 { 1500 myMaxValue = iData > myMaxValue ? iData : myMaxValue; 1501 myMinValue = iData > myMinValue ? myMinValue : iData; 1502 } 1503 } 1504 } 1505 1506 // 計算Y軸刻度 1507 double tmMax_New = Math.Ceiling(myMaxValue); // 目標最大值 向上取整 1508 double tmMin_New = Math.Floor(myMinValue); // 目標最小值 向下取整 1509 if (myMinValue == 0) 1510 { 1511 YScale_SplitValue = Math.Ceiling(tmMax_New / (double)YSplitNum); // 計算Y軸刻度間隔值 1512 YScale_StartValue = 0; // 計算Y軸刻度開始值 1513 } 1514 else 1515 { 1516 // 計算間隔值 1517 double tmJD1 = Math.Ceiling((tmMax_New - tmMin_New) / (double)(YSplitNum)); 1518 double tmJD2 = tmJD1 - Math.Ceiling((tmMax_New - tmMin_New) / (double)(YSplitNum + 1)); 1519 if (tmJD1 == 0) tmJD1 = 1; 1520 YScale_StartValue = tmJD1 * Math.Floor(tmMin_New / tmJD1); // 計算Y軸刻度開始值 1521 bool tmJDFlag = true; 1522 while (tmJDFlag) 1523 { 1524 if (YScale_StartValue <= tmMin_New && (YScale_StartValue + tmJD1 * YSplitNum) >= tmMax_New) 1525 { 1526 tmJDFlag = false; 1527 YScale_SplitValue = tmJD1; // 計算Y軸刻度間隔值 1528 break; 1529 } 1530 else 1531 { 1532 tmJD1 += tmJD2; 1533 } 1534 } 1535 } 1536 1537 // 計算Y軸刻度字符串的最大寬度 1538 SizeF tmYSizeF = g.MeasureString((YScale_StartValue + YScale_SplitValue * YSplitNum).ToString(), new Font("宋體", 9)); 1539 myYScaleMaxWidth = tmYSizeF.Width + 9f;// 預留4個像素 1540 } 1541 1542 #endregion 1543 1544 #region 枚舉方法 1545 1546 /// <summary> 1547 /// 枚舉圖表類型 1548 /// </summary> 1549 public enum EChartType 1550 { 1551 /// <summary> 1552 /// 曲線圖 1553 /// </summary> 1554 Curve, 1555 1556 /// <summary> 1557 /// 柱狀圖 1558 /// </summary> 1559 Bar, 1560 1561 /// <summary> 1562 /// 餅狀圖 1563 /// </summary> 1564 Pie 1565 1566 } 1567 1568 /// <summary> 1569 /// 枚舉對齊方式 1570 /// </summary> 1571 public enum EAlign 1572 { 1573 1574 /// <summary> 1575 /// 居左 1576 /// </summary> 1577 left, 1578 1579 /// <summary> 1580 /// 居中 1581 /// </summary> 1582 center, 1583 1584 /// <summary> 1585 /// 居右 1586 /// </summary> 1587 right 1588 } 1589 1590 #endregion 1591 1592 } 1593 1594 /// <summary> 1595 /// 圖表數據單個項目 1596 /// </summary> 1597 public class EChartData 1598 { 1599 private string _name; 1600 private List<double> _values; 1601 private Color _itemColor; 1602 private SizeF _nameSize; 1603 1604 public EChartData() 1605 { 1606 _name = ""; 1607 _values = new List<double>(); 1608 _itemColor = Color.White; 1609 _nameSize = new SizeF(0, 0); 1610 } 1611 1612 /// <summary> 1613 /// 項目名稱 1614 /// </summary> 1615 public string Name 1616 { 1617 get { return _name; } 1618 set { _name = value; } 1619 } 1620 1621 /// <summary> 1622 /// 項目值數組 1623 /// </summary> 1624 public List<double> Values 1625 { 1626 get { return _values; } 1627 set { _values = value; } 1628 } 1629 1630 /// <summary> 1631 /// 文字大小 1632 /// 用戶繪制圖例時候使用 1633 /// </summary> 1634 public SizeF NameSize 1635 { 1636 get { return _nameSize; } 1637 set { _nameSize = value; } 1638 } 1639 1640 /// <summary> 1641 /// 項目顏色 1642 /// </summary> 1643 public Color ItemColor 1644 { 1645 get { return _itemColor; } 1646 set { _itemColor = value; } 1647 } 1648 1649 } 1650 } View Code

   表報設計DLL控件的源碼實在太多,這裡就不再一一貼出來了,下載完整的源碼自己調試運行查看。
   此報表設計器結合上次的WEB打印控件,就組成了完整的報表設計。

   報表設計器實例完整源碼下載地址:www.sdpsoft.com/==》下載中心==》報表設計器簡易源碼----自定義報表控件(源碼)以及在Winform中的使用源碼  

   或直接下載地址:winform報表設計工具源碼

   歡迎廣大朋友一起交流。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved