在Delphi中动态生成QuickReport报表

原创 2003年04月01日 09:03:00

----笔者在前一段使用Delphi开发数据库的工作中,用户提出了这样一个需求:要根据自己的的查询结果动态生成报表然后进行打印。几经摸索,笔者使用动态生成QuickReport控件的方法满足了用户的需求。现将此方法说明如下,希望能为有类似工作要做的朋友们提供一点有益的提示。

 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

一、基本思路

----先将查询的一些参数(如SQL命令,字段名称,字段宽度等)按照一定格式写入一个临时文件中。在生成报表时,根据临时文件中所记录的参数动态生成各种QuickReport控件即可。

 

二、程序实现

2.1临时文件格式

----临时文件的格式可以根据需要自定义,笔者采用了INI的文件格式。Delphi提供了一个TInifile类,使得在Delphi中操作INI格式文件,非常方便。关于INI文件的格式和具体操作相关的文章有不少,我这里不再赘述。临时文件格式如下:

Report.ini 

:报表细节

[rep_detail]

Title=XXXXX

:打印纸设置,1A4,2B5,316K

Page=1

:打印方式,1为横打,0为竖打

Orientation=1

:报表包含的字段数目

columns=8

 

:TQurey组件信息

[QureyData]

QuickReport组件中Tqurey组件的SQL命令的内容

Sql_command=select V_XM,V_JGZW,V_BMMC,V_DWMC,V_DWZW,V_ZY,V_ZC,V_BGDH from Hvzzjg where V_XM  LIKE '%'

 

[col_0]

Caption= 

DataFiled=V_XM

Width=60

……

……

 

2.2动态生成QuickReport报表

--- 报表的主要控件及其主要属性设置如下

控件名称

类名

属性

属性值

Form_rep

TForm

caption

动态报表

QuickRep

TQuickRep

DataSet

REP_QUERY

DetailBand1

TQRBand

BandType

rbDetail

ColumnHeaderBand1

TQRBand

BandType

rbColumnHeader

REP_DataSource

TDataSource

DataSet

Rep_Query

Rep_Query

TQuery

DatabaseName

REPDATABASE

Rep_Database

 

TDatabase

 

Connected

True

Params.Strings

'SERVER NAME=XXX

'USER MAME=XXX'

'PASSWORD=XXX'

DatabaseName

REPDATABASE

上表所示控件是在程序中手工创建的。其他的控件则要在程序中动态创建。

2.2.2主要程序

unit f_rep;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, ExtCtrls, QuickRpt, QRCtrls, DB, DBTables,PRINTERS,QRPrntr,inifiles,

  TeeProcs, TeEngine, DbChart, QRTEE;

 

type

  TForm_rep = class(TForm)

    QuickRep: TQuickRep;

    DetailBand1: TQRBand;

    ColumnHeaderBand1: TQRBand;

    REP_DataSource: TDataSource;

    REP_QUERY: TQuery;

    rep_Database: TDatabase;

    procedure TForm_rep.QuickRepAfterPreview(Sender: TObject);//浏览完毕,释放所有创建的组件

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var  Form_rep:TForm_Rep;

    type //报表的摘要信息

       C_rep_Summary=record

         Title:string;//报表的标题

         Page:TQRPaperSize;//报表的页面设置,采用何种型号的纸

         Orientation:TPrinterOrientation;//报表的页面设置,是横打还是竖打

         Columns:integer;//报表包含的列数

     end;

 

     type

        C_Rep_Col_Summary=record//报表列的摘要信息

           Caption:string;//报表的列名

           DataFiled:string;//报表的列所对应的数据库中的字段名

           Width:integer;//报表的列宽

     end;

 

     type

        C_Rep_Col_Sum_store=record //存储报表列的摘要信息

         Caption_array:array of string;

         DataFiled_array:array of string;

         Width_array:array of integer;

     end;

var 

     rep_Summary:C_rep_Summary;

     Rep_Col_Summary:C_Rep_Col_Summary;

     Rep_Col_Sum_store:C_Rep_Col_Sum_store;

     Colum_Name:array of tQRRichText;

     Colum_Data:array of TQRDBRichText;

     C_Query:TQuery;

    

 

procedure  Form_rep_init();

procedure DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//动态创建TQRDBText控件

procedure  DynCreat_TQRRichtext(Colum_Num:integer);//动态创建TQRRichtext控件

procedure  DynCreat_TQuery(Inifile_Name:Tinifile);//动态创建TQuery控件的SQL语句

procedure  Get_PageCount();//取得打印总页数

function   Open_IniFile():Tinifile;//打开临时文件

procedure  Read_Col_Summary(Inifile_Name:Tinifile);//读取报表列的摘要信息

procedure  Read_Rep_Summary(Inifile_Name:Tinifile);//读取报表的摘要信息

function   rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//将打印方式设置进行转换

function rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//将打印页尺寸设置进行转换

 

implementation

 

{$R *.dfm}

 

function rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//将打印页类型设置进行转换

begin

    case  Rep_Page of

1:begin

           result:=A4;

           Form_rep.QuickRep.PrinterSettings.PaperSize:=A4;

         end;

       2:begin

           result:=B5;

           Form_rep.QuickRep.PrinterSettings.PaperSize:=B5

         end;

       3:begin

           result:=Executive;

           Form_rep.QuickRep.PrinterSettings.PaperSize:=Executive;

         end;

    end;

end;

 

function rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//将打印方式设置进行转换

begin

    case  Rep_Orientation of

       0:begin

           result:=poPortrait;//0为竖直

           Form_rep.QuickRep.PrinterSettings.Orientation:=poPortrait;

         end;

       1:begin

           result:=poLandscape;//1为水平

           Form_rep.QuickRep.PrinterSettings.Orientation:=poLandscape;

         end;

    end;

end;

 

function  Open_IniFile():Tinifile;//打开临时文件

var Filename:string;

    Ini_Filename:string;

begin

     Filename:=’Report.ini’;

     Ini_Filename:=File_Path+Filename;

     Result:=Tinifile.Create(Ini_Filename);

end;

 

procedure Read_Rep_Summary(Inifile_Name:Tinifile);//读取报表的摘要信息

var  Rep_Page,Rep_Orientation:integer;

begin

    rep_Page:=Inifile_Name.Readinteger('rep_detail','Page',1);

    Rep_Orientation:=Inifile_Name.Readinteger('rep_detail','Orientation',0);

    with  rep_Summary do

     begin

       Columns:=Inifile_Name.Readinteger('rep_detail','columns',0);

       Title:=Inifile_Name.Readstring('rep_detail','Title','未命名报表');

       page:=rep_chanslatepage(Rep_Page);//将打印页尺寸进行转换

       Orientation:=rep_chanslateOrientation(Rep_Orientation);//将打印方式设置进行转换

     end;

end;

 

procedure  Read_Col_Summary(Inifile_Name:Tinifile);//读取报表列的摘要信息

var i_count:integer;

begin

     //将列信息保存在数组中

     with Rep_Col_Sum_store do

     begin

       SetLength(Caption_array,rep_Summary.Columns);

       SetLength(DataFiled_array,rep_Summary.Columns);

       SetLength(Width_array,rep_Summary.Columns);

     end;

     for i_count:=0 to rep_Summary.Columns-1 do

     begin

       with Rep_Col_Summary do

         begin

           Caption:=Inifile_Name.Readstring('col_'+inttostr(i_count),'Caption','未命名');

           DataFiled:=Inifile_Name.Readstring('col_'+inttostr(i_count),'DataFiled','');

           Width:=Inifile_Name.Readinteger('col_'+inttostr(i_count),'Width',0);

         end;

       with Rep_Col_Sum_store  do

         begin

           Caption_array[i_count]:=Rep_Col_Summary.Caption;

           DataFiled_array[i_count]:=Rep_Col_Summary.DataFiled;

           Width_array[i_count]:=Rep_Col_Summary.Width;

         end;

    end;

end;

 

procedure DynCreat_TQRRichtext(Colum_Num:integer);//动态创建TQRRichtext控件,此控件用来显示报表每列的中文名称

var Colum_Name_list:TStrings;

begin

     Colum_Name[Colum_Num]:=tQRRichtext.Create(application); //创建TQRRichtext控件

     Colum_Name[Colum_Num].Parent:=Form_rep.ColumnHeaderBand1;

     Colum_Name[Colum_Num].Frame.DrawTop:=true;

     Colum_Name[Colum_Num].Frame.DrawBottom:=true;

     Form_rep.ColumnHeaderBand1.Height:=40;

     Colum_Name[Colum_Num].Height:=40;

     Colum_Name[Colum_Num].Font.Height:=-14;

     Colum_Name[Colum_Num].Font.Name:='黑体';

     Colum_Name[Colum_Num].Top:=0;

     Colum_Name[Colum_Num].Alignment:=taCenter;

     Colum_Name[Colum_Num].AutoStretch:=false;

      //画表格线

     Colum_Name[Colum_Num].Frame.Style:=psSolid;

     Colum_Name[Colum_Num].Frame.Width:=1;

     Colum_Name[Colum_Num].Frame.DrawRight:=true;

     Colum_Name[Colum_Num].Frame.DrawBottom:=true;

     if Colum_Num=0 then

        begin

          Colum_Name[Colum_Num].Frame.DrawLeft:=true;

        end;

     //将记录RRep_Col_Sum_store中的信息赋给Colum_Name

     Colum_Name_list:=TStringList.Create;

     Colum_Name_list.Add(Rep_Col_Sum_store.Caption_array[Colum_Num]);

     Colum_Name[Colum_Num].Lines:=Colum_Name_list;

     Colum_Name[Colum_Num].Width:=Rep_Col_Sum_store.Width_array[Colum_Num];

     Colum_Name[Colum_Num].Visible:=true;

     //计算左边界

     if Colum_Num>0 then

        Colum_Name[Colum_Num].Left:=Colum_Name[Colum_Num-1].Left+Colum_Name[Colum_Num-1].Width

     else

        Colum_Name[Colum_Num].Left:=0;

end;

说明:此处采用TQRRichtext控件是因为当名称过长时,TQRRichtext控件可以自动换行。

    

procedure DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//动态创建TQRDBText控件,此控件用来显示每列的值

begin

Colum_Data[Colum_Num]:=tQRDBText.Create(application);

    Colum_Data[Colum_Num].Parent:=Form_rep.DetailBand1;

    //设置数据集

    Colum_Data[Colum_Num].DataSet:=DataSet_Name;

    //将数组Colum_Data.DateField属性设置为C_Rep_Col_Sum_store中的字段名

    Colum_Data[Colum_Num].DataField:=Rep_Col_Sum_store.DataFiled_array[Colum_Num];

    Colum_Data[Colum_Num].Width:=Rep_Col_Sum_store.Width_array[Colum_Num];

    Colum_Data[Colum_Num].Height:=Colum_Height;

    Form_rep.DetailBand1.Height:=Colum_Height;

    Colum_Data[Colum_Num].Top:=0;

    Colum_Data[Colum_Num].AutoSize:=false;

    Colum_Data[Colum_Num].AutoStretch:=false;

    Colum_Data[Colum_Num].WordWrap:=false;

    Colum_Data[Colum_Num].Visible:=true;

    //画表格线

    Colum_Data[Colum_Num].Frame.Style:=psSolid;

    Colum_Data[Colum_Num].Frame.DrawRight:=true;

    Colum_Data[Colum_Num].Frame.DrawBottom:=true;

    if Colum_Num=0 then

      Colum_Data[Colum_Num].Frame.DrawLeft:=true;

    //计算左边界

     if Colum_Num>0 then

       Colum_Data[Colum_Num].Left:=Colum_Data[Colum_Num-1].Left+Colum_Data[Colum_Num-1].Width

     else

        Colum_Data[Colum_Num].Left:=0;

end;

 

procedure DynCreat_TQuery(Inifile_Name:Tinifile);//动态设置TQuery控件的SQL语句

var

    Sql_command:string;

begin

     Flag_CreatQuery:=false;

     Sql_command:=Inifile_Name.Readstring('QureyData','Sql_Command','');

     Form_rep.REP_QUERY.Close;

     Form_rep.REP_QUERY.SQL.Clear;

     Form_rep.REP_QUERY.SQL.Append(Sql_command);

     if not Form_rep.REP_QUERY.Prepared then

       Form_rep.REP_QUERY.Prepare;

     try

       Form_rep.REP_QUERY.ExecSQL;

       Form_rep.REP_QUERY.Active:=true;

       Form_rep.REP_QUERY.AutoCalcFields:=true;

       Flag_CreatQuery:=true;

     except

       Application.MessageBox('SQL语句错误!','系统提示',MB_ICONWARNING);

       Flag_CreatQuery:=false;

     end;

end;

 

procedure Form_rep_init();

var  i_count:integer;

     Rep_IniFile:Tinifile;//打开的INI文件名

     Col_Height:integer;

     Flag_Sum:boolean;

begin

   Rep_IniFile:=Open_IniFile);//打开临时文件文件

   Read_Rep_Summary(Rep_IniFile);//读取报表的摘要信息

   Read_Col_Summary(Rep_IniFile);//读取报表列的摘要信息

   //根据读取的报表的各项参数,动态创建报表控件

   with   Form_rep  do

   begin

      Flag_CreatTQRExpr:=false;//表示现在还没有创建TQRExpr控件

      DynCreat_TQuery(Rep_IniFile);

         if  Flag_CreatQuery then

            begin

             QRLabel_title.Caption:=rep_Summary.Title;

             QRLabel_Header.Caption:=rep_Summary.Title;

             //设置页面信息

             QuickRep.Page.Orientation:=rep_Summary.Orientation;

             QuickRep.Page.PaperSize:=rep_Summary.Page;

             SetLength(Colum_Data,rep_Summary.Columns);

             SetLength(Colum_Name,rep_Summary.Columns);

             for  i_count:=0 to rep_Summary.Columns-1 do

               begin

                  DynCreat_TQRRichtext(i_count);//动态创建TQRRichtext控件

                                 DynCreat_TQRDBRichText(i_count,Col_Height,Form_rep.REP_QUERY)//动态创建TQRDBText控件

               end;

              //关闭rep_x.ini文件

              Rep_IniFile.Destroy();

            end

          else

             Form_rep.Close;

    end;

end;

 

procedure TForm_rep.QuickRepAfterPreview(Sender: TObject);//浏览完毕,释放所有创建的组件

var i_count:integer;

begin

  for i_count:=0 to rep_Summary.Columns-1 do

   begin                         ;

     Colum_Name[i_count].free;

     Colum_Data[i_count].free;

   end;

end;

end.

 

三、需要注意的问题

----QuickReport中绘制表格线,除了文中提到的方法外,还可以使用QRShape控件。但不管使用那种方法,都要仔细计算,要根据打印的效果反复调整,才能保证表格线不产生偏差。

----所有动态创建的控件使用过后,一定要释放掉。

----临时文件在使用过后,也要清空。

 

----上文所示程序仅仅是笔者为了说明思路而简化的例程。在笔者实际的应用中,所有用到的控件(包括表单Form,都是动态生成的。而且在生成报表时,还可以动态生成统计信息,插入图表等,有兴趣的朋友可以发信到 chief_marshal@sina.com 和我一起讨论细节。

给ireport的报表添加序号

在做ireport时,有时需要让报表在前面给我们自动排号,可以利用ireport本身提供的变量来实现 如上图,拖动这个变量,放到你要的位置,比如 右键,选择 Edit expression...
  • a602049511
  • a602049511
  • 2016年08月11日 11:18
  • 1638

DELPHI 7.0软件 自带有报表 Quick Report组件(TQRShape等所有组件 说明)

DELPHI7.0软件自带有报表Quick Report组件,但是默认的情况下,工具栏中是没有的,需要手动添加,步骤:   component->install packages->add->\bo...
  • u011704389
  • u011704389
  • 2014年02月26日 15:41
  • 1530

delphi开发学习五:QuickReoprt报表控件使用实例

报表是数据库应用程序设计中非常重要的一部分,数据库应用程序通常都要生成报表,并且打印出来。      在Delphi7.0中,默认情况下没有直接使用的QuickReport组件,使用时需先进行手工安装...
  • u011846249
  • u011846249
  • 2015年08月20日 21:46
  • 2384

汇总Delphi第三方控件—报表、图表、界面、数据库

有网友问我常用的Delphi第三方控件及功能。我先大概整理一下,以后会在文章里面碰到时再仔细介绍。 报表图表: TeeChart Pro 在 delphi 的图形显示方面目前唯一的选择,虽然从de...
  • dyllove98
  • dyllove98
  • 2013年03月19日 16:19
  • 5640

Delphi 之创建动态库

Delphi 之创建动态库     动态库是什么,这里不多说,百度一大把。今天我们说说怎么用Delphi 创建自己的动态库(DLL)。      我这里的环境是      window7+delph...
  • u013051638
  • u013051638
  • 2016年11月25日 15:35
  • 421

Report Machine(RM)报表控件简单用法-delphi

RM(Report Machine)是一个功能强大的Delphi报表控件包。使用它可以制作出非常复杂的报表。下面讲述最简单的用法: 在Form上放上两个数据库控件:ADOConnection和ADO...
  • zisongjia
  • zisongjia
  • 2017年03月03日 18:03
  • 687

Delphi7下面关于动态创建控件和释放的个人总结

昨天,一个网友在动态创建控件时释放出了错。他的情况是,动态创建了N个Panel,然后双击Panel就释放掉该Panel。可问题就来了,一释放就出错。然后就一顿讨论。当然也有其他的高手给出了代码,可高手...
  • www1157763637qqcom
  • www1157763637qqcom
  • 2014年01月04日 14:54
  • 3791

如何在程序中执行动态生成的Delphi代码

如何在程序中执行动态生成的Delphi代码  经常发现有人提这类问题,或者提问内容最后归结成这种问题  前些阵子有位高手写了一个“执行动态生成的代码”,这是真正的高手,我没那种功力,我只会投机...
  • wc1000
  • wc1000
  • 2015年07月18日 16:04
  • 1038

如何利用FastReport创建交叉报表?

转自:http://www.fastreportcn.com/Article/92.html 本文我们将创建一个交叉报表,用于显示员工四年中的工资。要创建交叉报表,我们需要使用到Fa...
  • cw370008359
  • cw370008359
  • 2014年12月11日 13:24
  • 1082

Delphi的“动态窗体”技术实际应用

在Delphi可视化设计环境中,允许程序员在代码编辑器中以文本的方式浏览和修改DFM文件内容。当用File/Open命令直接打开DFM文件或者选择窗体设计窗口的弹出式菜单上的View as Text命...
  • MaxWoods
  • MaxWoods
  • 2014年06月04日 23:00
  • 2055
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在Delphi中动态生成QuickReport报表
举报原因:
原因补充:

(最多只允许输入30个字)