您的位置:首页 > 编程语言 > Delphi

在Delphi中动态生成QuickReport报表

2003-04-01 09:03 274 查看
----笔者在前一段使用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表
:打印纸设置,1为A4纸,2为B5纸,3为16K
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_repTFormcaption动态报表
QuickRepTQuickRepDataSetREP_QUERY
DetailBand1TQRBandBandTyperbDetail
ColumnHeaderBand1TQRBandBandType rbColumnHeader
REP_DataSource TDataSourceDataSetRep_Query
Rep_QueryTQueryDatabaseNameREPDATABASE
Rep_Database
 
TDatabase
 
ConnectedTrue
Params.Strings'SERVER NAME=XXX
'USER MAME=XXX'
'PASSWORD=XXX'
DatabaseNameREPDATABASE
上表所示控件是在程序中手工创建的。其他的控件则要在程序中动态创建。
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;
10f05

     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 和我一起讨论细节。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息