记得2010年之前,公司的项目基本上都要用到报表,以前我们常用的方法就是针对客户的需求来定制化开发(基本上是死写代码)来实现,经常导致项目经常性的延期,因为客户的需求经常会变化,随着用户的使用认知度的提高,对报表的要求越来越高,导致程序员不停的修改代码来实现,效率不高、结束遥遥无期。。。非常的痛苦;当然市面上有很多报表开发工具可以实现,但是针对小公司来说采购一套这样的系统的成本也非常的高,所以我们决定自己来开发一套像目前的润乾、FineReport 这样的报表设计器,来实现快速的报表设计制作。

当初为了开发这样的系统,花费的了很长的时间学习查阅各种资料,其痛苦只有程序员才能体会,因为没有任何现成的实例代码可供参考,只有看别人的思路来一步步的摸索,本文将我们当初设计制作的报表设计器的功能分享出来,让有需要的或想开发报表设计的朋友们提供一个参考,尽量少走很动弯路,设计端可以直接使用,但是计算引擎和网页的计算的源码就不能分享出来了(请不要介意,因为涉及到公司的保密原因)

记得当初为了制作报表设计器,在网上查找有没有相关的实例资料,找了很久,也是没有找到合适的,后来发现 SourceGrid 可以实现单元格的合并拆分功能,所以决定修改实现winform端的报表设计。下面我将制作的E_Report 报表控件抽取出来建立一个简易的Winform的可运行的实例提供给大伙下载,希望能给你的开发提供一点帮助和借鉴;当然你可以直接使用也可以,里面的设计功能基本全部能。

抽取出来的源码包含:E_Report 报表设计自定义控件DLL源码; EReportDemo 建立的简易Winform 端设计器使用DLL的实例源码;

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

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

一、运行效果

实例中,只做了一个简单的效果,工具栏的按钮在单元格右击属性中都有,只是放了几个常用的在工具导航栏中(右击单元格属性可以看到设计导航)

可以进行单元格的合并、拆分、字体、颜色、背景、边框等的设置,朋友们可以自己编写保存发布等功能,实现报表的真实功能;

例如单元格属性(其他还有很多的属性,自己下载源码后运行起来就能看到了)

对表格的斜线、斜线文字有很好的支持;可以设置表头、表位、标题等 实际效果图如下

二、使用介绍

1、页面初始化的时候,通过 ReportDoc 类 初始报表的行列及单元格属性

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Xml;
using System.Collections;
using E_Report;namespace EReportDemo
{/// <summary>/// 报表表格对象/// </summary>public class ReportDoc{#region 变量参数定义/// <summary>/// 表格对象/// </summary>private EReport _nowReport;/// <summary>/// 报表配置编码/// </summary>private string _reportCode = "";/// <summary>/// 表报设计状态/// </summary>private string _reportState = "";#endregion#region 函数构造方法/// <summary>/// 构造函数/// </summary>public ReportDoc(){this._nowReport = null;this._reportCode = "";this._reportState = "";}/// <summary>/// 获取--设置--表格对象/// </summary>public EReport NowReport{get { return this._nowReport; }set { this._nowReport = value; }}/// <summary>/// 报表配置编码/// </summary>public string ReportCode{get { return this._reportCode; }set { this._reportCode = value; }}/// <summary>/// 报表设计状态/// 新增、修改 两种状态/// </summary>public string ReportState{get { return this._reportState; }set { this._reportState = value; }}/// <summary>/// 资源释放/// </summary>~ReportDoc(){this._nowReport = null;this._reportState = "";}#endregion#region 加载报表表格/// <summary>/// 初始化--报表表格/// </summary>public void InitReport(){int rCount = 41;  // 41行int cCount = 20;  // 20列_nowReport.Redim(rCount, cCount);_nowReport.FixedRows = 1;_nowReport.FixedColumns = 1;InitCells();}/// <summary>/// 初始化--单元格/// </summary>public void InitCells(){// 第一行 第一列_nowReport.Rows[0].Height = 23;_nowReport.Columns[0].Width = 50;// 设置00格_nowReport[0, 0] = new E_Report.Cells.HeaderColumn("");//  设置行for (int rr = 1; rr < _nowReport.RowsCount; rr++){string tmRowT = rr.ToString();_nowReport[rr, 0] = new E_Report.Cells.HeaderRow(tmRowT);}//  设置列for (int cc = 1; cc < _nowReport.ColumnsCount; cc++){_nowReport[0, cc] = new E_Report.Cells.HeaderColumn(_nowReport.GetColumnHeadTileChar(cc));}// 设置单元格for (int iRow = 1; iRow < _nowReport.RowsCount; iRow++){for (int iCol = 1; iCol < _nowReport.ColumnsCount; iCol++){_nowReport[iRow, iCol] = new E_Report.Cells.Cell("", typeof(string));}}}#endregion}
}

2、工具导航栏 设置单元格相关属性

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using E_Report;namespace EReportDemo
{/// <summary>/// 本程序只是Winform端的报表设计功能/// 至于其他的功能,本实例没有提供/// 报表设计的设计效果:可以查看  www.sdpsoft.com  SDP软件快速开发平台 报表设计篇/// </summary>public partial class EReportMain : Form{private ReportDoc report;private E_Report.Cells.Controllers.PopupMenu myPopupMenu;public EReportMain(){InitializeComponent();}private void EReportMain_Load(object sender, EventArgs e){Cursor.Current = Cursors.WaitCursor;gridMain.Rows.Clear();myPopupMenu = new E_Report.Cells.Controllers.PopupMenu(gridMain);report = new ReportDoc();report.NowReport = gridMain;report.InitReport();Cursor.Current = Cursors.Default;}private void gridMain_MouseMove(object sender, MouseEventArgs e){this.lbl_X.Text = e.X.ToString();this.lbl_Y.Text = e.Y.ToString();}/// <summary>/// 工具栏报表单元格事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_GridTools_Click(object sender, EventArgs e){string sType = ((Button)sender).Tag.ToString().Trim().ToLower();switch (sType){case "cellproperty":  // 单元格属性设置myPopupMenu.CellProperty_Click(sender, e);break;case "fontset":       // 单元格字体设置myPopupMenu.CellFont_Click(sender, e);break;case "fontcolor":     // 文本字体颜色myPopupMenu.CellForColor_Click(sender, e);break;case "backcolor":     // 单元格背景色myPopupMenu.CellBackColor_Click(sender, e);break;case "cellborder":   // 单元格边框设置myPopupMenu.CellBorder_Click(sender, e);break;case "lock":         // 设置表格只读myPopupMenu.LockReport_Click(sender, e);break;case "unlock":       // 设置表格编辑myPopupMenu.UnLockReport_Click(sender, e);break;case "alignleft":    // 水平居左对齐myPopupMenu.AlignLeft_Click(sender, e);break;case "aligncenter":  // 水平居中对齐myPopupMenu.AlignCenter_Click(sender, e);break;case "alignright":   // 水平居右对齐myPopupMenu.AlignRight_Click(sender, e);break;case "aligntop":     // 垂直居上对齐myPopupMenu.AlignTop_Click(sender, e);break;case "alignmiddle":  // 垂直居中对齐myPopupMenu.AlignMiddle_Click(sender, e);break;case "alignbottom":  // 垂直居下对齐myPopupMenu.AlignBottom_Click(sender, e);break;case "addindent":    // 增加文本缩进myPopupMenu.AddIndent_Click(sender, e);break;case "delindent":    // 清除文本缩进myPopupMenu.RemoveIndent_Click(sender, e);break;case "insertrow":    // 插入后一行myPopupMenu.InsertRow_Click(sender, e);break;case "appendrow":    // 表格追加行myPopupMenu.AddRow_Click(sender, e);break;case "delrow":       // 删除选中行myPopupMenu.DeleteRows_Click(sender, e);break;case "hiderow":      // 隐藏选中行myPopupMenu.HideSelectRows_Click(sender, e);break;case "showrow":      // 显示选中行myPopupMenu.ShowSelectRows_Click(sender, e);break;case "showallrow":   // 显示所有行myPopupMenu.ShowAllRows_Click(sender, e);break;case "insertcol":    // 插入左侧列myPopupMenu.InsertColumn_Click(sender, e);break;case "addcol":       // 插入右侧列myPopupMenu.AddColumn_Click(sender, e);break;case "delcol":       // 删除选中列myPopupMenu.DeleteColumns_Click(sender, e);break;case "hidecol":      // 隐藏选中列myPopupMenu.HideSelectColumns_Click(sender, e);break;case "showcol":      // 显示选中列myPopupMenu.ShowSelectColumns_Click(sender, e);break;case "showallcol":   // 显示所有列myPopupMenu.ShowAllColumns_Click(sender, e);break;case "mergecell":    // 合并单元格myPopupMenu.MergeCell_Click(sender, e);break;case "splitcell":    // 拆分单元格myPopupMenu.SplitCell_Click(sender, e);break;}}}
}

3、报表控件DLL类库部分

里面有我们自定义的 条码控件、图片控件、图表控件

表格内自定义图表控件(曲线、柱状、饼状)源码

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;namespace E_Report
{/// <summary>/// 图表属性/// </summary>/// <summary>/// 报表图表类库/// </summary>public class EChart{#region 属性方法#region 临时变量/// <summary>/// 临时变量--关联单元格行号/// </summary>private int _row = 0;/// <summary>/// 获取--设置--关联单元格行号/// </summary>public int Row{get { return _row; }set { _row = value; }}/// <summary>/// 临时变量--关联单元格列号/// </summary>private int _col = 0;/// <summary>/// 获取--设置--关联单元格列号/// </summary>public int Col{get { return _col; }set { _col = value; }}/// <summary>/// 数据来源/// </summary>private string _t_DataFrom = "数据源";/// <summary>/// 获取--设置--数据来源/// </summary>public string T_DataFrom{get { return _t_DataFrom; }set { _t_DataFrom = value; }}/// <summary>/// 数据源名称/// </summary>private string _t_DsName = "";/// <summary>/// 获取--设置--数据源名称/// </summary>public string T_DsName{get { return _t_DsName; }set { _t_DsName = value; }}/// <summary>/// 项目名称/// </summary>private string _t_ItemName = "";/// <summary>/// 获取--设置--项目名称/// </summary>public string T_ItemName{get { return _t_ItemName; }set { _t_ItemName = value; }}/// <summary>/// 项目数值/// </summary>private string _t_ItemValue = "";/// <summary>/// 获取--设置--项目数值/// </summary>public string T_ItemValue{get { return _t_ItemValue; }set { _t_ItemValue = value; }}/// <summary>/// X轴刻度/// </summary>private string _t_XScale = "";/// <summary>/// 获取--设置--X轴刻度/// </summary>public string T_XScale{get { return _t_XScale; }set { _t_XScale = value; }}#endregion#region 图表属性/// <summary>/// 图表名称ID/// </summary>private string _name = "";/// <summary>/// 获取--设置--图表名称ID/// </summary>public string Name{get { return _name; }set { _name = value; }}/// <summary>/// 图表类型/// </summary>private EChartType _chartType = EChartType.Curve;/// <summary>/// 获取--设置--图表类型/// 默认:Line 折曲线/// </summary>public EChartType ChartType{get { return _chartType; }set { _chartType = value; }}/// <summary>/// 图表宽度/// </summary>private int _chartWidth = 0;/// <summary>/// 获取--设置--图表宽度/// </summary>public int ChartWidth{get { return _chartWidth; }set { _chartWidth = value; }}/// <summary>/// 图表高度/// </summary>private int _chartHeight = 0;/// <summary>/// 获取--设置--图表高度/// </summary>public int ChartHeight{get { return _chartHeight; }set { _chartHeight = value; }}/// <summary>/// 图表背景颜色/// </summary>private Color _backColor = Color.White;/// <summary>/// 获取--设置--图表背景颜色/// </summary>public Color BackColor{get { return _backColor; }set { _backColor = value; }}/// <summary>/// 是否显示图表边框/// </summary>private bool _showBorder = true;/// <summary>/// 获取--设置--是否显示图表边框/// 默认:true 显示/// </summary>public bool ShowBorder{get { return _showBorder; }set { _showBorder = value; }}/// <summary>/// 图表边框颜色/// </summary>private Color _borderColor = Color.LightGray;/// <summary>/// 获取--设置--图表边框颜色/// </summary>public Color BorderColor{get { return _borderColor; }set { _borderColor = value; }}/// <summary>/// 是否显示网格线/// </summary>private bool _showGrid = true;/// <summary>/// 获取--设置--是否显示网格线/// 默认:true 显示/// </summary>public bool ShowGrid{get { return _showGrid; }set { _showGrid = value; }}/// <summary>/// 线条张力系数/// </summary>private float _lineTension = 0.3f;/// <summary>/// 获取--设置--线条张力系数/// 默认:0.3/// </summary>public float LineTension{get { return _lineTension; }set{if (value < 0.0f && value > 1.0f)_lineTension = 0.5f;else_lineTension = value;}}#endregion#region 标题属性/// <summary>/// 是否显示主标题/// </summary>private bool _showTitle = true;/// <summary>/// 获取--设置--是否显示主标题/// 默认:true 显示/// </summary>public bool ShowTitle{get { return _showTitle; }set { _showTitle = value; }}/// <summary>/// 主标题文本/// </summary>private string _title = "";/// <summary>/// 获取--设置--主标题文本/// </summary>public string Title{get { return _title; }set { _title = value; }}/// <summary>/// 主标题字体/// </summary>private Font _titleFont = new Font("黑体", 12);/// <summary>/// 获取--设置--主标题字体/// </summary>public Font TitleFont{get { return _titleFont; }set { _titleFont = value; }}/// <summary>/// 主标题颜色/// </summary>private Color _titleColor = Color.Black;/// <summary>/// 获取--设置--主标题颜色/// </summary>public Color TitleColor{get { return _titleColor; }set { _titleColor = value; }}/// <summary>/// 主标题对齐方式/// </summary>private EAlign _titleAlign = EAlign.center;/// <summary>/// 获取--设置--主标题对齐方式/// </summary>public EAlign TitleAlign{get { return _titleAlign; }set { _titleAlign = value; }}/// <summary>/// 是否显示副标题/// </summary>private bool _showSubTilte = true;/// <summary>/// 获取--设置--是否显示副标题/// 默认:true 显示/// </summary>public bool ShowSubTitle{get { return _showSubTilte; }set { _showSubTilte = value; }}/// <summary>/// 副标题文本/// </summary>private string _subTitle = "";/// <summary>/// 获取--设置--副标题文本/// </summary>public string SubTitle{get { return _subTitle; }set { _subTitle = value; }}/// <summary>/// 副标题字体/// </summary>private Font _subTitleFont = new Font("黑体", 10);/// <summary>/// 获取--设置--副标题字体/// </summary>public Font SubTitleFont{get { return _subTitleFont; }set { _subTitleFont = value; }}/// <summary>/// 副标题颜色/// </summary>private Color _subTitleColor = Color.Blue;/// <summary>/// 获取--设置--副标题颜色/// </summary>public Color SubTitleColor{get { return _subTitleColor; }set { _subTitleColor = value; }}/// <summary>/// 副标题对齐方式/// </summary>private EAlign _subTitleAlign = EAlign.center;/// <summary>/// 获取--设置--副标题对齐方式/// </summary>public EAlign SubTitleAlign{get { return _subTitleAlign; }set { _subTitleAlign = value; }}/// <summary>/// 副标题水平方向偏移量/// + - 整数/// </summary>private int _subTitleOffset = 0;/// <summary>/// 获取--设置--副标题水平方向偏移量/// </summary>public int SubTitleOffset{get { return _subTitleOffset; }set { _subTitleOffset = value; }}#endregion#region 图例属性/// <summary>/// 是否显示图例/// </summary>private bool _showLegend = true;/// <summary>/// 是否显示图例/// </summary>public bool ShowLegend{get { return _showLegend; }set { _showLegend = value; }}/// <summary>/// 图例字体/// </summary>private Font _legendFont = new Font("宋体", 9);/// <summary>/// 获取--设置--图例字体/// </summary>public Font LegendFont{get { return _legendFont; }set { _legendFont = value; }}/// <summary>/// 图例字体颜色/// </summary>private Color _legendColor = Color.Black;/// <summary>/// 获取--设置--图例字体颜色/// </summary>public Color LegendColor{get { return _legendColor; }set { _legendColor = value; }}/// <summary>/// 图例对齐方式/// </summary>private EAlign _legendAlign = EAlign.center;/// <summary>/// 获取--设置--图例对齐方式/// </summary>public EAlign LegendAlign{get { return _legendAlign; }set { _legendAlign = value; }}#endregion#region 坐标属性/// <summary>/// 获取--X轴分割段数/// </summary>public int XSplitNum{get { return _xScaleValues.Count; }}/// <summary>/// Y轴分割段数/// </summary>private int _ySplitNum = 5;/// <summary>/// 获取--设置--分割段数/// 默认:5/// 范围:最小5/// </summary>public int YSplitNum{get { return _ySplitNum; }set{if (value < 5)_ySplitNum = 5;else_ySplitNum = value;}}/// <summary>/// X 轴标/// </summary>private string _xAxisText = "";/// <summary>/// 获取--设置--X 轴标/// </summary>public string XAxisText{get { return _xAxisText; }set { _xAxisText = value; }}/// <summary>/// Y 轴标/// </summary>private string _yAxisText = "";/// <summary>/// 获取--设置--Y 轴标/// </summary>public string YAxisText{get { return _yAxisText; }set { _yAxisText = value; }}/// <summary>/// X轴文本旋转角度/// 默认:0/// 范围:0~90/// </summary>private float _xRotateAngle = 0.0f;/// <summary>/// 获取--设置--X轴文本旋转角度/// </summary>public float XRotateAngle{get { return _xRotateAngle; }set{if (value >= 0.0f && value <= 90.0f)_xRotateAngle = value;else_xRotateAngle = 0.0f;}}#endregion#region 绘图变量/// <summary>/// 绘图对象/// </summary>private Graphics g = null;/// <summary>/// 图表颜色数组/// </summary>private static Color[] ChartColor = { Color.Red, Color.Blue, Color.Orange, Color.Green, Color.Cyan, Color.Purple,Color.Coral, Color.Chocolate, Color.Gray, Color.Gold, Color.Lavender, Color.Linen,Color.Magenta, Color.Moccasin, Color.Navy, Color.Olive, Color.Peru, Color.Plum,Color.Purple, Color.Salmon, Color.Sienna, Color.Silver, Color.Tan, Color.Tomato, Color.Violet, Color.Turquoise, Color.Transparent};/// <summary>/// 边距10px/// </summary>private float Margin = 10;/// <summary>/// 起点 X 坐标/// </summary>private float Start_X = 0;/// <summary>/// 起点 Y 坐标/// </summary>private float Start_Y = 0;/// <summary>/// 终点 X 坐标/// </summary>private float End_X = 0;/// <summary>/// 终点 Y 坐标/// </summary>private float End_Y = 0;/// <summary>/// X轴刻度宽度/// </summary>private float XScaleWidth = 0;/// <summary>/// Y轴刻度宽度/// </summary>private float YScaleWidth = 0;/// <summary>/// Y轴刻度间隔值/// 说明:Y轴坐标全部采用整数,表示每个间隔的计算单位值/// 包含正负数/// </summary>private double YScale_SplitValue = 0;/// <summary>/// Y轴刻度开始值/// </summary>private double YScale_StartValue = 0;/// <summary>/// 坐标轴原点坐标/// </summary>private PointF AxisZeroPt = new PointF(0f, 0f);/// <summary>/// 图表数据/// </summary>private string _chartData = "";/// <summary>/// 获取--设置--图表数据/// </summary>public string ChartData{get { return _chartData; }set { _chartData = value; }}/// <summary>/// 绘图笔刷/// </summary>private Brush brush;/// <summary>/// 绘制画笔/// </summary>private Pen pen;/// <summary>/// 绘图矩形/// </summary>private RectangleF rectF = new RectangleF(0, 0, 0, 0);/// <summary>/// 字符格式化/// </summary>private StringFormat stringFormat;/// <summary>/// 临时变量 最大值/// </summary>private double myMaxValue = 0;/// <summary>/// 临时变量 最小值/// </summary>private double myMinValue = 0;/// <summary>/// 临时变量 X轴刻度最大高度/// 用于绘制坐标轴的时候进行偏移/// </summary>private float myXScaleMaxHeight = 0;/// <summary>/// 临时变量 Y轴刻度值字符串的最大宽度/// 用于绘制坐标轴的时候进行偏移/// </summary>private float myYScaleMaxWidth = 0;#endregion#region 图表数据/// <summary>/// X轴刻度值数组/// </summary>private List<string> _xScaleValues = new List<string>();/// <summary>/// 获取--设置--X轴刻度值数组/// </summary>public List<string> XScaleValues{get { return _xScaleValues; }set { _xScaleValues = value; }}/// <summary>/// 图表数据/// </summary>private List<EChartData> _chartDataArray = new List<EChartData>();/// <summary>/// 获取--设置--图表数据/// </summary>public List<EChartData> ChartDataArray{get { return _chartDataArray; }set { _chartDataArray = value; }}#endregion#endregion#region 构造方法/// <summary>/// 构造函数/// </summary>public EChart(){}/// <summary>/// 构造函数/// </summary>/// <param name="eChart"></param>public EChart(EChart eChart){}#endregion#region 生成图表/// <summary>/// 生成图表/// </summary>/// <returns>返回:图表图像</returns>public Bitmap CreateImage(){Bitmap ChartImage = new Bitmap(ChartWidth, ChartHeight);g = Graphics.FromImage(ChartImage);g.SmoothingMode = SmoothingMode.Default;g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;g.Clear(Color.White);Start_X = Margin;Start_Y = Margin;End_X = ChartWidth - Margin;End_Y = ChartHeight - Margin;DrawChart();g.Dispose();return ChartImage;}#endregion#region 绘制方法/// <summary>/// 绘制图表/// </summary>private void DrawChart(){DrawChart_InitGraph();DrawChart_MainTitle();DrawChart_SubTitle();DrawChart_Legend();DrawChart_YAxisText();if (ChartType != EChartType.Pie){DrawChart_Axis();if (ChartType == EChartType.Curve)DrawChart_Curve();elseDrawChart_Bar();}else{DrawChart_Pie();}}/// <summary>/// 绘制图表--绘制背景图/// </summary>private void DrawChart_InitGraph(){// 绘制图表外围边框if (_showBorder)g.DrawRectangle(new Pen(BorderColor, 1), 0, 0, (ChartWidth - 1), (ChartHeight - 1));// 填充图表背景颜色g.FillRectangle(new SolidBrush(BackColor), 1, 1, ChartWidth - 2, ChartHeight - 2);}/// <summary>/// 绘制图表--绘制主标题/// </summary>private void DrawChart_MainTitle(){if (ShowTitle){if (Title != null && Title.Trim() != ""){brush = new SolidBrush(TitleColor);                     // 矩形填充笔刷SizeF sizeF = g.MeasureString(Title, TitleFont);        // 测试字体大小stringFormat = new StringFormat();                      // 格式化字符串stringFormat.LineAlignment = StringAlignment.Center;    // 垂直对齐方式switch (TitleAlign)                                     // 水平对齐方式{case EAlign.center:stringFormat.Alignment = StringAlignment.Center;break;case EAlign.right:stringFormat.Alignment = StringAlignment.Far;break;default:stringFormat.Alignment = StringAlignment.Near;break;}rectF = new RectangleF(Start_X, Start_Y, (float)(ChartWidth - 4), sizeF.Height);  // 文字的矩形g.DrawString(Title, TitleFont, brush, rectF, stringFormat);                       // 绘制主标题Start_Y += sizeF.Height + 3f;                                                     // 设置Y起点值 + 3px}}}/// <summary>/// 绘制图表--绘制副标题/// </summary>private void DrawChart_SubTitle(){if (ShowSubTitle){if (SubTitle != null && SubTitle.Trim() != ""){brush = new SolidBrush(SubTitleColor);                  // 矩形填充笔刷SizeF sizeF = g.MeasureString(SubTitle, SubTitleFont);  // 测试字体大小stringFormat = new StringFormat();                      // 格式化字符串stringFormat.LineAlignment = StringAlignment.Center;    // 垂直对齐方式switch (SubTitleAlign)                                  // 水平对齐方式{case EAlign.center:stringFormat.Alignment = StringAlignment.Center;break;case EAlign.right:stringFormat.Alignment = StringAlignment.Far;break;default:stringFormat.Alignment = StringAlignment.Near;break;}rectF = new RectangleF(Start_X + (float)SubTitleOffset, Start_Y, (float)(ChartWidth - 4), sizeF.Height);  // 文字的矩形g.DrawString(SubTitle, SubTitleFont, brush, rectF, stringFormat);                                               // 绘制副标题Start_Y += sizeF.Height + 3f;                                                                             // 设置Y起点值 + 3px}}}/// <summary>/// 绘制图表--绘制图例/// </summary>private void DrawChart_Legend(){// 计算项目颜色int tmIndex = 0;for (int m = 0; m < ChartDataArray.Count; m++){tmIndex = m % ChartColor.Length;ChartDataArray[m].ItemColor = ChartColor[tmIndex];}// 图例的高度最大40px 3排if (ShowLegend){// 计算文字大小 int LegendCount = ChartDataArray.Count;Font tFont = new Font("宋体", 9);for (int t = 0; t < LegendCount; t++){SizeF tmSize = new SizeF();tmSize = g.MeasureString(ChartDataArray[t].Name, tFont);ChartDataArray[t].NameSize = tmSize;}#region 绘制一排图例// 首先判定一行够不够float largMax = 0;for (int t = 0; t < LegendCount; t++){if (t == 0)largMax += ChartDataArray[t].NameSize.Width;elselargMax += (35f + ChartDataArray[t].NameSize.Width);}if (largMax <= End_X - Start_X) // 图例只需一排{End_Y -= 12.0f;float tmX = (End_X - Start_X - largMax) / 2 + Start_X;float tmY = End_Y;for (int n = 0; n < LegendCount; n++){g.FillRectangle(new SolidBrush(ChartDataArray[n].ItemColor), tmX, tmY + 1, 15, 10);tmX += 20;g.DrawString(ChartDataArray[n].Name, new Font("宋体", 9), new SolidBrush(Color.Black), tmX, tmY);tmX += 15 + ChartDataArray[n].NameSize.Width;}}#endregion#region 绘制多排图例// 图例最多绘制三排else{bool TwoLine = true;                     // 是否两行:true 是; false: 否,为三行// 判定两排还是三排float tmBX = Start_X - 5;int tmBC = (int)Math.Ceiling((double)LegendCount / 2);for (int T = 0; T < tmBC; T++){float tmBW1 = -1F, tmBW2 = -1F, tmBM = 0F;tmBW1 = ChartDataArray[T * 2].NameSize.Width;if (ChartDataArray.Count > (T * 2 + 1))tmBW2 = ChartDataArray[T * 2 + 1].NameSize.Width;tmBM = tmBW1 > tmBW2 ? tmBW1 : tmBW2;tmBX += 35 + tmBM;if (tmBX > (End_X + 5)){TwoLine = false;break;}}// 绘制两排图例if (TwoLine){End_Y -= 24.0f;float tmTX = (End_X + 10 - tmBX + Start_X + 5) / 2;       // 开始位置保持两排水平居中float tmTY = End_Y;int tmTM = (int)Math.Ceiling((double)LegendCount / 2);// 绘制两排图例for (int T = 0; T < tmTM; T++){float tmTW1 = -1F, tmTW2 = -1F, tmTW3 = 0F;tmTW1 = ChartDataArray[T * 2].NameSize.Width;if (ChartDataArray.Count > (T * 2 + 1))tmTW2 = ChartDataArray[T * 2 + 1].NameSize.Width;tmTW3 = tmTW1 > tmTW2 ? tmTW1 : tmTW2;// 绘制第一排图例g.FillRectangle(new SolidBrush(ChartDataArray[T * 2].ItemColor), tmTX, tmTY + 1, 15, 10);g.DrawString(ChartDataArray[T * 2].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmTX + 20), tmTY);// 绘制第二排图例if (tmTW2 > 0){g.FillRectangle(new SolidBrush(ChartDataArray[T * 2 + 1].ItemColor), tmTX, (tmTY + 16 + 1), 15, 10);g.DrawString(ChartDataArray[T * 2 + 1].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmTX + 20), (tmTY + 16));}tmTX += 35 + tmTW3;}}// 绘制三排图例else{End_Y -= 40.0f;// 如果三排还不够,那么就不管了,绘制超出范围就超出范围float tmSX = Start_X - 5;float tmSY = End_Y;int tmSC = (int)Math.Ceiling((double)LegendCount / 3);bool CanFlag = true;  // 三排是否足够// 首先计算三排的能排下的居中位置for (int n = 0; n < tmSC; n++){float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F;tmSW1 = ChartDataArray[n * 3].NameSize.Width;if (ChartDataArray.Count > (n * 3 + 1))tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width;if (ChartDataArray.Count > (n * 3 + 2))tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width;tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2;tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3;tmSX += 35 + tmSW4;if (tmSX > (End_X + 5)){CanFlag = false;break;}}// 再次执行三排绘制if (CanFlag)             // 三排足够,则设置居中开始位置tmSX = (End_X + 10 - tmSX + Start_X + 5) / 2;elsetmSX = Start_X - 5;  // 三排排不下的情况就从5px 开始for (int n = 0; n < tmSC; n++){float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F;tmSW1 = ChartDataArray[n * 3].NameSize.Width;if (ChartDataArray.Count > (n * 3 + 1))tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width;if (ChartDataArray.Count > (n * 3 + 2))tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width;tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2;tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3;// 绘制第一排图例g.FillRectangle(new SolidBrush(ChartDataArray[n * 3].ItemColor), tmSX, (tmSY + 1), 15, 10);g.DrawString(ChartDataArray[n * 3].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), tmSY);// 绘制第二排图例if (tmSW2 > 0){g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 1].ItemColor), tmSX, (tmSY + 16 + 1), 15, 10);g.DrawString(ChartDataArray[n * 3 + 1].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 16));}// 绘制第三排图例if (tmSW3 > 0){g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 2].ItemColor), tmSX, (tmSY + 32 + 1), 15, 10);g.DrawString(ChartDataArray[n * 3 + 2].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 32));}tmSX += 35 + tmSW4;}}}#endregion}}/// <summary>/// 绘制图表--绘制X轴标/// </summary>/// <param name="g"></param>private void DrawChart_XAxisText(){// X轴标就不绘制了,因为空间不够,所以不执行X轴标的绘制}/// <summary>/// 绘制图表--绘制Y轴标/// </summary>private void DrawChart_YAxisText(){if (ChartType != EChartType.Pie){if (YAxisText != null && YAxisText.Trim() != ""){brush = new SolidBrush(Color.Gray);stringFormat = new StringFormat();                                    // 格式化字符串stringFormat.LineAlignment = StringAlignment.Near;                    // 垂直对齐方式stringFormat.Alignment = StringAlignment.Near;                        // 水平对齐方式SizeF sizeF = g.MeasureString(YAxisText, new Font("宋体", 9));        // 测量文字大小rectF = new RectangleF(Start_X, Start_Y, sizeF.Width, sizeF.Height);  // 文字外围矩形g.TranslateTransform((Start_X - Start_Y), (Start_X + Start_Y + sizeF.Width));    // 设置位置移动 X,Y g.RotateTransform(270);                                                          // 旋转270度  以左上角作为旋转原点g.DrawString(YAxisText, new Font("宋体", 9), brush, rectF, stringFormat);g.ResetTransform();Start_X += sizeF.Height + 2;                                          // 加2个像素}}}/// <summary>/// 绘制图表--绘制坐标轴/// </summary>private void DrawChart_Axis(){// 1、图表区下移10PXStart_Y += 10;// 2、计算坐标轴参数Calc_XScaleHeight();Calc_YScaleValue();// 3、计算原点坐标值AxisZeroPt = new PointF(0f, 0f); // 坐标轴原点坐标AxisZeroPt.X = Start_X + myYScaleMaxWidth;AxisZeroPt.Y = End_Y - myXScaleMaxHeight;// 3.1、绘制坐标轴Pen pen2 = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 2f);g.DrawLine(pen2, (Start_X + myYScaleMaxWidth - 4f), (End_Y - myXScaleMaxHeight), End_X + 2, (End_Y - myXScaleMaxHeight));     // 绘制 X坐标轴g.DrawLine(pen2, (Start_X + myYScaleMaxWidth), (End_Y - myXScaleMaxHeight + 4f), (Start_X + myYScaleMaxWidth), Start_Y - 2);  // 绘制 Y坐标轴// 3.2、计算分段宽XScaleWidth = (End_X - Start_X - myYScaleMaxWidth) / XSplitNum;      // 计算X轴分段宽YScaleWidth = (End_Y - Start_Y - myXScaleMaxHeight) / YSplitNum;     // 计算Y轴分段宽// 3.3、绘制刻度值pen = new Pen(Color.LightGray, 1f);pen.DashStyle = DashStyle.Dash;for (int k = 0; k < XSplitNum; k++)    // 绘制X轴刻度线 刻度值{// 绘制X轴刻度线g.DrawLine(pen2, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y + 4f);// 绘制X轴刻度值g.TranslateTransform(AxisZeroPt.X + XScaleWidth * k + 15f * XRotateAngle / 90 + 4f, AxisZeroPt.Y + 4f);  // 平移原点g.RotateTransform(XRotateAngle, MatrixOrder.Prepend);                                                    // 旋转图像g.DrawString(XScaleValues[k], new Font("宋体", 9f), new SolidBrush(Color.Black), 0, 0);                  // 绘制字符g.ResetTransform();}for (int k = 0; k < YSplitNum; k++){// 绘制Y轴刻度线g.DrawLine(pen2, AxisZeroPt.X - 4, (AxisZeroPt.Y - YScaleWidth * (k + 1)), AxisZeroPt.X, (AxisZeroPt.Y - YScaleWidth * (k + 1)));// 绘制Y轴刻度值string tmYvalue = (YScale_StartValue + k * YScale_SplitValue).ToString();SizeF tmF = g.MeasureString(tmYvalue, new Font("宋体", 9));g.DrawString(tmYvalue, new Font("宋体", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * k - tmF.Height / 2 + 1));if (k == YSplitNum - 1){tmYvalue = (YScale_StartValue + (k + 1) * YScale_SplitValue).ToString();tmF = g.MeasureString(tmYvalue, new Font("宋体", 9));g.DrawString(tmYvalue, new Font("宋体", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * (k + 1) - tmF.Height / 2 + 1));}}// 3.4、绘制网格线if (ShowGrid){for (int k = 1; k <= YSplitNum; k++)  // 绘制X轴平行横向辅助线g.DrawLine(pen, AxisZeroPt.X + 1, (AxisZeroPt.Y - YScaleWidth * k), End_X, (AxisZeroPt.Y - YScaleWidth * k));for (int k = 1; k <= XSplitNum; k++)  // 绘制Y轴平行纵向辅助线g.DrawLine(pen, (AxisZeroPt.X + XScaleWidth * k), Start_Y, (AxisZeroPt.X + XScaleWidth * k), AxisZeroPt.Y - 1);}pen2.Dispose();}/// <summary>/// 绘制曲线图/// </summary>private void DrawChart_Curve(){g.SmoothingMode = SmoothingMode.HighQuality;g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;int tmLength = 0;PointF[] CurvePointF = new PointF[tmLength];foreach (EChartData iItem in this.ChartDataArray){tmLength = iItem.Values.Count;CurvePointF = new PointF[tmLength];pen = new Pen(iItem.ItemColor, 2.0f);for (int rr = 0; rr < iItem.Values.Count; rr++){double dbValue = iItem.Values[rr];CurvePointF[rr].X = AxisZeroPt.X + XScaleWidth * rr + XScaleWidth / 2;CurvePointF[rr].Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth;}// 绘制曲线g.DrawCurve(pen, CurvePointF, LineTension);// 绘制辅点for (int tt = 0; tt < CurvePointF.Length; tt++){// 点标数据值string tmValStr = iItem.Values[tt].ToString();// 绘制数据点g.FillEllipse(new SolidBrush(iItem.ItemColor), CurvePointF[tt].X - 3, CurvePointF[tt].Y - 3, 6, 6);// 绘制数据值SizeF tmValueSize = g.MeasureString(tmValStr, new Font("Arial", 9));g.DrawString(tmValStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (CurvePointF[tt].X - tmValueSize.Width / 2), (CurvePointF[tt].Y - tmValueSize.Height - 2f));}}}/// <summary>/// 绘制柱状图/// </summary>private void DrawChart_Bar(){g.SmoothingMode = SmoothingMode.HighQuality;int tmLen = ChartDataArray.Count;                       // 柱形条目总数float tmBarWidth = XScaleWidth / (tmLen * 2 + 1);    // 每条柱形宽度 平均分配if (tmBarWidth < 2){tmBarWidth = 2f;}for (int kk = 0; kk < this.ChartDataArray.Count; kk++){EChartData iItem = this.ChartDataArray[kk];pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.0f);for (int rr = 0; rr < iItem.Values.Count; rr++){RectangleF barRect = new RectangleF(0, 0, 0, 0);double dbValue = iItem.Values[rr];barRect.X = AxisZeroPt.X + XScaleWidth * rr + (tmBarWidth * ((kk + 1) * 2 - 1));barRect.Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth;barRect.Width = tmBarWidth;barRect.Height = AxisZeroPt.Y - barRect.Y;// 绘制柱形g.DrawRectangle(pen, barRect.X, barRect.Y, barRect.Width, barRect.Height);brush = new SolidBrush(iItem.ItemColor);g.FillRectangle(brush, barRect.X + 1, barRect.Y + 1, barRect.Width - 2, barRect.Height - 2);// 绘制数据SizeF tmValueSize = g.MeasureString(dbValue.ToString(), new Font("Arial", 9));g.DrawString(dbValue.ToString(), new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (barRect.X + tmBarWidth / 2 - tmValueSize.Width / 2), (barRect.Y - tmValueSize.Height - 2f));}}}/// <summary>/// 绘制图表--绘制饼状图/// </summary>private void DrawChart_Pie(){// 上下预留20 PX 为了标记饼图的数据值        Start_Y += 20;End_Y -= 20;g.SmoothingMode = SmoothingMode.HighQuality;g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;// 矩形坐标点PointF piePoint = new PointF(0, 0);float tmPieW = End_X - Start_X;float tmPieH = End_Y - Start_Y;float tmPieR = tmPieW < tmPieH ? tmPieW / 2 : tmPieH / 2;  // 半径piePoint.X = Start_X + tmPieW / 2 - tmPieR;piePoint.Y = Start_Y + tmPieH / 2 - tmPieR;// 圆心坐标点PointF pieZero = new PointF(piePoint.X + tmPieR, piePoint.Y + tmPieR);// 绘制外围圆pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.5f);g.DrawEllipse(pen, piePoint.X - 5, piePoint.Y - 5, (tmPieR + 5) * 2, (tmPieR + 5) * 2);// 计算总数double pieCountValue = 0;foreach (EChartData iItem in this.ChartDataArray){if (iItem.Values.Count >= 1)pieCountValue += iItem.Values[0];}// 绘制扇形if (pieCountValue > 0){float curAngle = 0; // 占比角度float sumAngle = 0; // 总角度和foreach (EChartData iItem in this.ChartDataArray){if (iItem.Values.Count >= 1)curAngle = (float)(iItem.Values[0] / pieCountValue * 360);elsecurAngle = 0;// 填充笔刷brush = new SolidBrush(iItem.ItemColor);// 绘制弧形g.FillPie(brush, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle);// 绘制弧线g.DrawPie(pen, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle);// 绘制数据float tmPre = (float)Math.Round((iItem.Values[0] / pieCountValue) * 100, 2);string tmStr = tmPre.ToString() + "%" + " [" + iItem.Values[0].ToString() + "]";// 内圆信息double relCur_X = tmPieR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180);double relCur_Y = tmPieR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180);double cur_X = relCur_X + pieZero.X;double cur_Y = pieZero.Y - relCur_Y;PointF cur_Point = new PointF((float)cur_X, (float)cur_Y);  // 内圆上弧线中间点的坐标// 外圆信息float largerR = tmPieR + 10;double relLarg_X = largerR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180);double relLarg_Y = largerR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180);double largerX = relLarg_X + pieZero.X;double largerY = pieZero.Y - relLarg_Y;PointF larger_Point = new PointF((float)largerX, (float)largerY);SizeF calcSize = new SizeF(0, 0);// 绘制链接斜线(内圆到外圆弧度中间点的连接线)g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), cur_Point, larger_Point);                                               // 斜线// 绘制横向线条//*以下是对四个象限、以及对90度、180度、270度和360度的判断*//float tmCurIf = sumAngle + curAngle / 2;if (tmCurIf <= 90){g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y);  // 横线g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f);             // 文字}else if (tmCurIf > 90 && tmCurIf <= 180){calcSize = g.MeasureString(tmStr, new Font("Arial", 9));g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y);       // 横线g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字}else if (tmCurIf > 180 && tmCurIf <= 270){calcSize = g.MeasureString(tmStr, new Font("Arial", 9));g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y);       // 横线g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字}else{g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y);  // 横线g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f);             // 文字}*以下是对四个象限、以及对90度、180度、270度和360度的判断*////if ((sumAngle + curAngle / 2) < 90)//{//    Half = sumAngle + curAngle / 2;//    double tem_sin = Math.Sin(Pi / 180 * Half);//    double tem_cos = Math.Cos(Pi / 180 * Half);//    //Math.PI//    float Px = (float)(tmPieR * tem_cos);//    float Py = (float)(tmPieR * tem_sin);//    g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(Color.Black), piePoint.X + tmPieR + Px, piePoint.Y + Py);//    //g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + x, 225 + y));//    //g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + x, 225 + y + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 90)//{//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225, 225 + 125));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225, 225 + 125 + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 90 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 180)//{//    halfangle = (180 - tem_angle - Convert.ToSingle(arraylist_angle[i]) / 2);//    double tem_sin = Math.Sin(T / 180 * halfangle);//    double tem_cos = Math.Cos(T / 180 * halfangle);//    int y = Convert.ToInt32(125 * tem_sin);//    int x = Convert.ToInt32(125 * tem_cos);//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - x, 225 + y));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - x, 225 + y + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 180)//{//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - 125, 225));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - 125, 225 + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 180 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 270)//{//    halfangle = (tem_angle - 180 + Convert.ToSingle(arraylist_angle[i]) / 2);//    double tem_sin = Math.Sin(T / 180 * halfangle);//    double tem_cos = Math.Cos(T / 180 * halfangle);//    int y = Convert.ToInt32(125 * tem_sin);//    int x = Convert.ToInt32(125 * tem_cos);//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - x, 225 - y));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - x, 225 - y + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 270)//{//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225, 225 - 125));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225, 225 - 125 + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 270 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 360)//{//    halfangle = (360 - tem_angle - Convert.ToSingle(arraylist_angle[i]) / 2);//    double tem_sin = Math.Sin(T / 180 * halfangle);//    double tem_cos = Math.Cos(T / 180 * halfangle);//    int y = Convert.ToInt32(125 * tem_sin);//    int x = Convert.ToInt32(125 * tem_cos);//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + x, 225 - y));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + x, 225 - y + 12));//}//else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 360)//{//    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + 125, 225));//    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + 125, 225 + 12));//}// 累加角度sumAngle += curAngle;}}}#endregion#region 辅助方法/// <summary>/// 计算X轴刻度值最大高度/// </summary>/// <returns></returns>private void Calc_XScaleHeight(){SizeF tmMaxSizeF = new SizeF(0, 0);for (int t = 0; t < XScaleValues.Count; t++){SizeF tmSizeF = g.MeasureString(XScaleValues[t], new Font("宋体", 9));if (tmSizeF.Width > tmMaxSizeF.Width){tmMaxSizeF.Width = tmSizeF.Width;tmMaxSizeF.Height = tmSizeF.Height;}}myXScaleMaxHeight = (((float)Math.Sqrt(tmMaxSizeF.Height * tmMaxSizeF.Height + tmMaxSizeF.Width * tmMaxSizeF.Width) - tmMaxSizeF.Height) * XRotateAngle / 90 + tmMaxSizeF.Height + 13f);}/// <summary>/// 计算坐标Y轴的刻度值/// 适用于:曲线图、柱状图/// 不适用:饼状图无需计算/// </summary>private void Calc_YScaleValue(){myMaxValue = 0; // 原始最大值myMinValue = 0; // 原始最小值// 计算所有数据的最大值和最小值for (int mm = 0; mm < this.ChartDataArray.Count; mm++){for (int nn = 0; nn < this.ChartDataArray[mm].Values.Count; nn++){double iData = this.ChartDataArray[mm].Values[nn];if (mm == 0 && nn == 0){myMaxValue = iData;myMinValue = iData;}else{myMaxValue = iData > myMaxValue ? iData : myMaxValue;myMinValue = iData > myMinValue ? myMinValue : iData;}}}// 计算Y轴刻度double tmMax_New = Math.Ceiling(myMaxValue);  // 目标最大值 向上取整double tmMin_New = Math.Floor(myMinValue);    // 目标最小值 向下取整if (myMinValue == 0){YScale_SplitValue = Math.Ceiling(tmMax_New / (double)YSplitNum);                       // 计算Y轴刻度间隔值YScale_StartValue = 0;                                                                 // 计算Y轴刻度开始值}else{// 计算间隔值double tmJD1 = Math.Ceiling((tmMax_New - tmMin_New) / (double)(YSplitNum));double tmJD2 = tmJD1 - Math.Ceiling((tmMax_New - tmMin_New) / (double)(YSplitNum + 1));if (tmJD1 == 0) tmJD1 = 1;YScale_StartValue = tmJD1 * Math.Floor(tmMin_New / tmJD1);  // 计算Y轴刻度开始值bool tmJDFlag = true;while (tmJDFlag){if (YScale_StartValue <= tmMin_New && (YScale_StartValue + tmJD1 * YSplitNum) >= tmMax_New){tmJDFlag = false;YScale_SplitValue = tmJD1;                          // 计算Y轴刻度间隔值break;}else{tmJD1 += tmJD2;}}}// 计算Y轴刻度字符串的最大宽度SizeF tmYSizeF = g.MeasureString((YScale_StartValue + YScale_SplitValue * YSplitNum).ToString(), new Font("宋体", 9));myYScaleMaxWidth = tmYSizeF.Width + 9f;// 预留4个像素}#endregion#region 枚举方法/// <summary>/// 枚举图表类型/// </summary>public enum EChartType{/// <summary>/// 曲线图/// </summary>Curve,/// <summary>/// 柱状图/// </summary>Bar,/// <summary>/// 饼状图/// </summary>Pie}/// <summary>/// 枚举对齐方式/// </summary>public enum EAlign{/// <summary>/// 居左/// </summary>left,/// <summary>/// 居中/// </summary>center,/// <summary>/// 居右/// </summary>right}#endregion}/// <summary>/// 图表数据单个项目/// </summary>public class EChartData{private string _name;private List<double> _values;private Color _itemColor;private SizeF _nameSize;public EChartData(){_name = "";_values = new List<double>();_itemColor = Color.White;_nameSize = new SizeF(0, 0);}/// <summary>/// 项目名称/// </summary>public string Name{get { return _name; }set { _name = value; }}/// <summary>/// 项目值数组/// </summary>public List<double> Values{get { return _values; }set { _values = value; }}/// <summary>/// 文字大小/// 用户绘制图例时候使用/// </summary>public SizeF NameSize{get { return _nameSize; }set { _nameSize = value; }}/// <summary>/// 项目颜色/// </summary>public Color ItemColor{get { return _itemColor; }set { _itemColor = value; }}}
}

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

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

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

欢迎广大朋友一起交流。

C# 报表设计器 (winform 设计端)开发与实现生成网页的HTML报表 开放源码及调试相关推荐

  1. 表格设计器的设计与开发(hong-crud)

    表格设计器的设计与开发(hong-crud) 首先安利一个特别厉害的前端框架Avue,此插件是基于avue进行的二次开发,一切为了业务和产品,当然Avue官方也提供了表格设计器avue-crud(功能 ...

  2. .net mvc 报表_Web在线报表设计器使用指南

    市面上的报表工具有很多,虽说功能大同小异,但每一个报表工具都有各自明确的定位,选择最合适的工具,才能达到事半功倍的效果. 本文将要介绍的ActiveReports报表工具,可全面满足 .NET 报表开 ...

  3. 水晶报表 jar包版本过低_工具类学习-UReport报表设计器整合

    dada-report报表整合UReport报表设计器工具 结合日常工作和学习实践,针对传统报表子站面临的问题,尝试借助UReport报表设计器解决 1.可在现有工程基础上引入Ureport2报表设计 ...

  4. 说说下一代的报表设计器——Jaspersoft Studio

    大家所熟知的报表设计器应该是 iReport,现在已经不再维护咯,Jaspersoft 公司已经把资源转向了 Jaspersoft Studio,所以我们就来看一看这个新一代的设计器吧. Jasper ...

  5. FastReport.Net教程:基本原理之报表、报表设计器和报表选项

    下载FastReport.Net最新版本 FastReport.Net在线订购火热进行中,立可享受特别优惠!点此链接,速来抢购!!! 基本原理 在本章中,我们将学习在FastReport中使用报表的原 ...

  6. .net webapi 接收参数_FastReport.Net报表设计器如何连接到SQLCe

    Microsoft SQL Server Compact Edition是一个简单的本地关系数据库,不需要安装,并且已与数据库文件建立连接.您不需要管理员权限即可使用基础功能.您也只能"密码 ...

  7. ActiveReports.NET Crack,集成报表设计器

    ActiveReports.NET Crack,集成报表设计器 ActiveReports.NET 通过直观的 Visual Studio 集成报表设计器和丰富的控件帮助您交付精美的报表.Active ...

  8. 报表设计应该注意什么?报表设计器推荐

    报表设计需要强调的几点: 1.明确分析目的,不要想着"用户想要看什么",而是要去想"用户想要解决什么问题". 不管是基于项目目标还是业务流程还是现有报表,最终都 ...

  9. 创建您的ActiveReports Web端在线报表设计器

    下载ActiveReport最新试用版 概述 ActiveReports Web端在线报表设计器已经正式上线!看到它这么帅气.实用,你是不是也想自己动手创建一个? 现在我们就来教您,如何创建一个简单的 ...

  10. html5拖拽表单设计器,require+jquery+backbone实现拖拽式报表设计器-拖拽式表单设计器...

    HTML我帮您-拖拽式报表设计器-拖拽式表单设计器是一个可视化设计器,基于require+jquery+backbone+underscore+bootstrap实现的表单设计器.思想来源于 Layo ...

最新文章

  1. (Incomplete) UVa 719 Glass Beads
  2. 线性代数导论5——SVD分解
  3. 表格布局页面_对于表格布局管理器的回顾以及接下来的目标
  4. Heap与Stack的区别- -
  5. Kotlin入门(22)适配器的简单优化
  6. 您的计算机已实施了USB存储设备管理策略,设置usb设备管理 【解决步骤】 的教程_...
  7. JAVA 字符串格式化-String.format()的使用(转)
  8. CSS3实现的立体button
  9. jdbc c3p0 mysql_JDBC+C3P0+DBCP 基本使用
  10. HiBit Startup Manager(电脑开机启动项管理软件)官方中文版V2.3.20 | 电脑启动项管理工具下载
  11. Java之JDBC连接池详解
  12. 微信小程序:网课查题微信小程序源码下载,题库资源丰富自动采集,支持语音拍照识别
  13. 王阳明的智慧:如何让职场从“举步维艰”到“平步青云”?
  14. u盘安装红旗linux操作系统,如何用u盘安装红旗linux?
  15. 技术经理、架构师、技术总监、VP、CTO,这些岗位都是如何挣出来
  16. <数据结构>链表实战之单链表与双链表的增删改查
  17. 【Vscode】 Vscode常用插件
  18. opencv函数cv2.warpAffine 和 cv2.warpPerspective 的理解和复现
  19. Quectel移远展锐平台5G模组RX500U/RG200U使用指南(四)-工作模式】
  20. ceres学习笔记(四)

热门文章

  1. bat 命令如何启动远程PC上的一个程序?
  2. Java一般要学多久?
  3. 纺织服装产业实现智能制造升级
  4. AR涂涂乐⭐六、 UGUI精灵格式、自动延迟截图、优化“4”、移出扫描框终止截图进程
  5. 阿里P9告诉你:P6-P10到底啥区别,别再傻傻分不清?怎样才能打怪晋级?
  6. Kubernetes Downward API的介绍及使用
  7. 郁金香java_郁金香搜索引擎的方案
  8. IBM山东开建全球首个完整云计算中心
  9. 面试通过了,也给了Offer,不去有什么后果?
  10. 北京理工计算机科学与应用,沈蒙_北京理工大学计算机学院