记得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>