在Delphi编程中利用Excel实现动态报表

楼主
我是社区第8265位番薯,欢迎点我头像关注我哦~
0 引言
随着计算机技术的不断普及, 办公的数字化程度越来越高, 出现了大量的计算机系统, 如固定资产管理系统、人事工资管理系统等等。这其中存在大量的MIS系统。MIS系统的一个重要特点是需要处理大量数据并形成报表。由于行业或者其他一些原因, 这些报表的格式种类繁多, 而且还有一些复杂报表。这些报表的格式在开发期间可能都无法设定。为了解决这些问题, 本文采用了表格功能强大的Excel作为报表模板, 用户可以按照自己的要求设置报表格式, 程序运行时再根据用户的设置动态填入数据, 从而实现动态报表功能。

1 实现原理              
先由用户按照自己的格式生成Excel报表模板,系统读取模板文件, 并把模板文件存入数据库, 保存用户输入的报表信息, 如某一字段填入第几行第几列。报表打印时, 提取相应的Excel文件, 利用Delphi的Excel控件填入数据库的数据, 实现动态报表功能。

2实现过程
2. 1 定义数据表
系统使用MsSql Server2000数据库,定义两个表,一个是MB,用来存储报表基本信息和Excel文件,一个是MB_Detail存放报表的详细信息,如对应字段的行号和列号。表结构如下:
   
图1 MB 表结构               图2 MB _Detail表结构

MB表中,“模板内容”字段为image类型, 用来存储Excel模板文件,“记录类型”字段用来表示是单张表格(只打印一条记录)还是列表(打印多条记录); MB Detail表中的列号数据类型为char, 对应Excel中的列号如A、B、C等。

2. 2 保存和读取Excel模板
2. 2. 1 保存Excel模板
本系统将用户设置好的Excel报表模板存入数据库“模板内容”字段。由于本字段存储的是Excel文件内容, 需要采用特殊的存储方式。本系统使用Delph i的TO leContainer控件, 与Excel文件建立连接, 最后存入数据库。因此, 先在模板设置界面上放置TO leContainer控件, 取名为OExcel,主要代码如下:
V ar Stream: TS tream; / /定义保存文件的流
Beg inOExce.l C reateOb jectFromF ile( edtfile. Tex ,t Fa lse);
OExce.l DoV erb( OExce.l Prim aryV erb);
MB. FieldByName(模板名称). As String: = ExtractFileName(edtFile.Text);
Stream: = MB. CreateB lobStream (MB. Fie ldByName( '模板内容)', bmW rite) ;
try
  OExcel SaveToS tream(Stream);
finally
  Stream. Free;
  OExcel DestroyObject;
end;
End;

2. 2. 2 读取Excel模板
当需要打印报表时,需要将相应的Exce l模板从数据库中读出保存, 并用满足要求的数据填充, 其中读出Excel并保存的代码如下:
With TSaveDialog. Create(self) do
Begin
FileName : = trim(MB.FieldByN ame(模板名称). AsString) ; / /保存的模板的名称
Stream: = MB. CreateBlobStream (MB. Fie ldByName(模板内容 , bmRead);/ /建立数据库流
try
  OExce.l LoadFromS tream( Stream) ; / /将数据库中的数据读入O leConta iner
  OExce.l O ldStreamForm at: = true;/ /设置保存的格式不变
  OExce.l SaveA sDocument( FileName);/ /将Excel模板文件保存到当前文件夹
fina lly
  S tream. Free;
end;
End

2. 3 利用TExcelApplication控件实现报表输出
2. 3. 1 存储报表信息
上节中实现了Excel模板的存储与读取, 实际上,在保存Excel模板的同时, 还要往数据库中存入相应的模板信息, 如某一字段的值存入填入Excel表格中的行号和列号, 是打印单行记录还是多条记录等。具体生成报表信息的界面如图3和图4所示:
图3所示是打印多条记录的情况。这种情况下, 只要确定某一字段需要填入模板中的哪一列, 因此,行号不能输入。这种格式主要用于列表式报表。
图4所示是打印单条记录的情况, 需要指出每个字段在Excel中的行号和列号。这种格式主要用于打印卡片式的报表。
        
    图
3
寛/font]
打印多条记录         
     图
4
寛/font]
打印单条记录

2. 3. 2 报表输出
报表输出需要用到Delphi的TExcelApplication控件。TExcelApplication控件是Delphi提供的操作MS Office文档的控件之一, 通过它, 可以实现在Delphi程序中对Excel文档的相关操作。TExcelApplication控件的主要方法有:
ExcelA: = TExcelApplication. Create(self); / /建立控件
ExcelA. Connect;/ /打开一个Excel应用程序
ExcelA. Visible[0] : = true; / /打开的Excel中的Sheet1可见
ExcelA. Workbooks. Open( F ileN ame, EmptyParam, , 0); / /打开文件名为FileN ame的Excel文件
具体的输出代码如下:
Stream: = MB. CreateBlobStream (MB. FieldByName(模板内容), bmRead) ;
O. LoadFromStream( Stream ); / /从数据库中读出Excel模板
O. SaveA sDocument( FileName); / /保存
ExcelA : = TExcelApplication. Create( self);
ExcelA.Connect;
ExcelA.Visible[0] : = true;
ExcelA.Workbooks. Open
( FileName, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
     EmptyParam,EmptyParam, EmptyParam, EmptyParam,
     EmptyParam,EmptyParam, EmptyParam, EmptyParam, EmptyParam, 0); / /打开
Excel
While not DataSet Eof do / /DataSet为输出数据的表
begin
  MB DETA IL. First;
  while not MB DETA IL. Eof do
  begin
   if trim(MB DETA IL. FieldByName(列号). AsString) < > ''then
   begin
   tmpStr : = Trim ( DataSet FieldByName(trim (MB DETA IL. FieldByNam e(字段名). As叜琀爀椀渀最)) . AsString) ;
row : = MB DETA IL. FieldByName(列号). asString+inttostr( RBegin) ;
   ExcelA. Range[ row, row ] . Select;
   ExcelA. ActiveCell FormulaR1C1: = tmpstr;
   end;
   MB DETA IL. Next;
end;
Inc( RBegin) ;
DataSet Next;
  if not DataSet Eof then
   ExcelA. Range[ 懜+inttostr( RBegin) , 竜+ inttostr( RBegin) ] . Insert(xlDown, 0) ; / /按模板格式新建一行
end;

3、结论
在Delphi中可以使用多种报表工具完成报表的设计和打印, 但大多数报表工具都太专业, 普通用户使用有一定困难。Excel是使用非常广泛的办公软件, 简单易学, 通过Excel与De lphi结合, 可以设计出非常复杂的报表格式, 完全实现报表的动态生成与输出。本文使用的方法已经在最近开发的设备管理系统中使用, 用户反映良好。

分享扩散:

沙发
发表于 2012-7-29 19:16:51
哦,哥哥都是骨灰级别人物了,研究delphi?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

返回顶部 返回列表