你的位置:首页 > ASP.net教程

[ASP.net教程]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. 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     #endregion148 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           else1000           {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             else1031               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         #endregion1068       }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、图表区下移10PX1111       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           else1307             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           else1363           {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.PI1376 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     #endregion1455 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           else1499           {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       else1515       {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           else1531           {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     #endregion1543 1544     #region 枚举方法1545 1546     /// <summary>1547     /// 枚举图表类型1548     /// </summary>1549     public enum EChartType1550     {1551       /// <summary>1552       /// 曲线图1553       /// </summary>1554       Curve,1555 1556       /// <summary>1557       /// 柱状图1558       /// </summary>1559       Bar,1560 1561       /// <summary>1562       /// 饼状图1563       /// </summary>1564       Pie1565 1566     }1567 1568     /// <summary>1569     /// 枚举对齐方式1570     /// </summary>1571     public enum EAlign1572     {1573 1574       /// <summary>1575       /// 居左1576       /// </summary>1577       left,1578 1579       /// <summary>1580       /// 居中1581       /// </summary>1582       center,1583 1584       /// <summary>1585       /// 居右1586       /// </summary>1587       right1588     }1589 1590     #endregion1591 1592   }1593 1594   /// <summary>1595   /// 图表数据单个项目1596   /// </summary>1597   public class EChartData1598   {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 Name1616     {1617       get { return _name; }1618       set { _name = value; }1619     }1620 1621     /// <summary>1622     /// 项目值数组1623     /// </summary>1624     public List<double> Values1625     {1626       get { return _values; }1627       set { _values = value; }1628     }1629 1630     /// <summary>1631     /// 文字大小1632     /// 用户绘制图例时候使用1633     /// </summary>1634     public SizeF NameSize1635     {1636       get { return _nameSize; }1637       set { _nameSize = value; }1638     }1639 1640     /// <summary>1641     /// 项目颜色1642     /// </summary>1643     public Color ItemColor1644     {1645       get { return _itemColor; }1646       set { _itemColor = value; }1647     }1648 1649   }1650 }

View Code

   表报设计DLL控件的源码实在太多,这里就不再一一贴出来了,下载完整的源码自己调试运行查看。
   此报表设计器结合上次的WEB打印控件,就组成了完整的报表设计。

   报表设计器实例完整源码下载地址:www.sdpsoft.com/==》下载中心==》报表设计器简易源码----自定义报表控件(源码)以及在Winform中的使用源码  

   或直接下载地址:winform报表设计工具源码

   欢迎广大朋友一起交流。