标签:
记得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 } }
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(); else DrawChart_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; else largMax += (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; else tmSX = 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、图表区下移10PX Start_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); else curAngle = 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报表 开放源码及调试
标签:
原文地址:http://blog.csdn.net/szzzzn/article/details/51603190