---- 笔者在前一段使用 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 <SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-f