分享
 
 
 

在Delphi中动态生成QuickReport报表

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

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

一、基本思路

----先将查询的一些参数(如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_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 和我一起讨论细节。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有