如何使用 Delphi 3 动态生成报表(200分)

  • 主题发起人 question
  • 开始时间
Q

question

Unregistered / Unconfirmed
GUEST, unregistred user!
请问如何在 Delphi 3 中动态生成报表?
需要能动态改变列数等信息。
例如:我通过一个不定条件的查询获得了一个查询结果,现在需要将
它打印出来,我该如何做?如:可能需要打印这次打印姓名,性别,
籍贯,民族而下次可能打印民族,性别。
报表要求美观!Help Me
 
推荐使用我的控件:PrintAtOnce,对Delphi3提供最好的支持,你只需在Form上
放一个DBGrid,把它的DataSource指向你的查询结果的Datasource即可。
<a href=http://www.zg169.net/~randolph>我的主页</a>上有详细的使用方法。
还有,如果你喜欢用文本方式打印,可以使用DBGridText。
 
你可以下载一个叫 cube_rpt.zip 的样例,它是动态更换并打印DELPHI3 的决策
控件的例子,地点在QuickReport 公司。
 
你如果使用 qreport ,
可以读取数据字段的名称和长度,
然后create一个qrlabel,和一个
qrdblabel分别在title band和
detil band,当然尺寸要换算好。
用RBbuilter更好一些,你还可以把
动态设置好的报表格式存放到数据库
中。
 
麻烦的问题
我也做过类似的报表,从那以后,就自己开发了一个自带外挂编辑器的报表工具
外挂环境类似于WORD里制表工具, 编辑环境里放一个报表控件就可以
需要改动报表样式时,只需在外部编辑报表格式文件就可以了
需要的话, emailto:hehe@tonghua.com.cn
如果您使用QRREPORT的话,完成上述操作要这么做
首先自定义一个INI文件(REGISTER里写也可以)
然后,做一个小编辑环境,改动INI(OR REGISTER)
然后使用动态对象数组的办法,手动生成报表

下面是我的一个例子, 把另一个数据表的表记录写到报表的列头上
使用了动态数组
unit danaprint;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
quickrpt, Qrctrls, Db, DBTables, ExtCtrls;
type
TResultArray = array[0..0, 0..0] of Real;
PResultArray = ^TResultArray;
//从表中得到的数据暂时保存在这里
TShuJuArray = array[0..0,0..0] of TQrLabel;
PShuJuArray = ^TShuJuArray;
//用于显示交叉表中的数据
THangArray = array[0..0] of TQrLabel;
PHangArray = ^THangArray;
//用于显示行头
TLieArray = array[0..0] of TQrLabel;
PLieArray = ^TLieArray;
//用于显示列标题
Tdanaprintfrm = class(TForm)
DataSource1: TDataSource;
Query1: TQuery;
Query2: TQuery;
QuickRep1: TQuickRep;
QRBand1: TQRBand;
TitleBand1: TQRBand;
QRMemo1: TQRMemo;
QRLabel5: TQRLabel;
QRGroup2: TQRGroup;
QRSubDetail2: TQRSubDetail;
QRLabel8: TQRLabel;
Query3: TQuery;
QRLabel1: TQRLabel;
procedure QRSubDetail2BeforePrint(Sender: TQRCustomBand;
var PrintBand: Boolean);
procedure QuickRep1BeforePrint(Sender: TQuickRep;
var PrintReport: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
danaprintfrm: Tdanaprintfrm;
pfl_array:pHangArray;
pks_array:pLieArray;
pArrayOfResult: PResultArray;
pSum_array:pShuJuArray;
implementation
uses kssf_ylb;

{$R *.DFM}
procedure Tdanaprintfrm.QRSubDetail2BeforePrint(Sender: TQRCustomBand;
var PrintBand: Boolean);
//用于初始化临时数据数组
//var i,j:integer;
begin
PrintBand := False;
{ query1.open;
query1.first;
query2.open;
query2.first;
query3.open;
query3.first;
try
GetMem(pArrayOfResult, query2.recordcount * query3.recordcount * SizeOf(real));
//为数组分配内存
for i := 0 to query2.recordcount-1do
for j := 0 to query3.recordcount-1do
pArrayOfResult^[i, j] := 0;
while not query1.EOFdo
begin
query2.first;
i:=0;
while (not (query2.fieldbyname('aa').asstring = query1.FieldByName('aa').asstring))
and (not query2.eof)do
begin
i:=i+1;
query2.next;
end;

query3.first;
j:=0;
while (not (query3.fieldbyname('flmc').asstring=query1.FieldByName('flmc').asstring))
and (not query3.eof)do
begin
j:=j+1;
query3.next;
end;

pArrayOfResult^[i,j]:=pArrayOfResult^[i,j]+query1.fieldbyname('column3').value;
query1.next;
end;
finally
FreeMem(pArrayOfResult, query2.recordcount * query3.recordcount * SizeOf(real));
end;
ShowMessage('Done');}
end;


procedure Tdanaprintfrm.QuickRep1BeforePrint(Sender: TQuickRep;
var PrintReport: Boolean);
begin
//row:=0;
end;

{ pfl_array:pHangArray;
pks_array:pLieArray;
pArrayOfResult: PResultArray;
pSum_array:pShuJuArray;}
procedure Tdanaprintfrm.FormCreate(Sender: TObject);
var
BandWidth,bandleft,bandtop,bandheight:integer;
i,j: integer;
// printshape:tqrshape;
begin
qrlabel1.Caption:=KsSf_ylb_Frm.MaskEdit1.Text+'至'+KsSf_ylb_Frm.MaskEdit2.Text+' 收费一览';
Query1.ParamByName('param1').AsDateTime:=KsSf_ylb_Frm.Query1.parambyname('param1').AsDateTime;
Query1.ParamByName('param2').AsDateTime:=KsSf_ylb_Frm.Query1.parambyname('param2').AsDateTime;
Query1.Prepare;
query1.open;
query1.first;
Query2.Prepare;
query2.open;
query2.first;
Query3.Prepare;
query3.open;
query3.first;
// BandWidth := Trunc(QRBand1.Width / Query3.RecordCount);
BandWidth:=QrLabel5.Width;
bandleft:=qrlabel5.left+qrlabel5.Width;
//所有标签的其始LEFT偏移地址
bandtop:=qrlabel5.Top+qrlabel5.Height;
bandheight:=qrlabel5.Height;
GetMem(pfl_array,Query3.RecordCount * sizeof(TQrlabel));
GetMem(pks_array,Query2.RecordCount * sizeof(TQrlabel));
GetMem(pArrayOfResult, query2.recordcount * query3.recordcount * SizeOf(real));
//为数组分配内存
GetMem(pSum_array,query2.recordcount * query3.recordcount * SizeOf(TQrlabel));
for j := 0 to Query3.RecordCount-1do
begin

Pfl_Array[j] := TQRLabel.Create(self);
with pfl_Array[j]do
begin
Parent := QRBand1;
AlignToBand := False;
AutoSize := True;
AutoStretch := False;
Color := clWhite;
Top := qrlabel5.top;
height:=BandHeight;
//Width := BandWidth;
if j=0 then
Left :=BandLeft + 6 + j*(BandWidth)
else
Left :=pfl_Array[j-1].left+pfl_array[j-1].Width+8;
caption:=query3.fieldbyname('flmc').asstring;
Font.Style := [];
Font.Name :='宋体';
Font.Size :=10;
end;
Query3.Next;
end;
for i:=0 to Query2.RecordCount-1do
begin
Pks_Array := TQRLabel.Create(self);
with pks_Arraydo
begin
Parent := QRBand1;
AlignToBand := False;
AutoSize := false;
AutoStretch := False;
Color := clWhite;
Left := qrlabel5.Left;
Width := BandWidth;
Height :=BandHeight;
Top:=BandTop + 6 + i*(BandHeight+6);
// frame.DrawTop :=true;
// frame.DrawLeft :=true;
// frame.DrawBottom :=true;
// frame.DrawRight :=true;
Caption:=query2.fieldbyname('ksmc').asstring;
Font.Style := [];
Font.Name :='宋体';
Font.Size :=11;
// printshape:=TQrShape.Create(self);
// printshape.parent:=qrband1;
// printshape.Top :=pks_Array.top;
// printshape.Height :=pks_Array.height+12;
// printshape.Width :=bandWidth;
// printshape.left :=qrlabel5.left;
AlignToBand := False;
end;
query2.Next;
end;
i:=0;
j:=0;
query1.first;
query2.first;
query3.first;
try
for i := 0 to query2.recordcount-1do
for j := 0 to query3.recordcount-1do
pArrayOfResult^[i, j] := 0;
while not query1.EOFdo
begin
query2.first;
i:=0;
while (not (query2.fieldbyname('ksmc').asstring = query1.FieldByName('ksmc').asstring))
and (not query2.eof)do
begin
i:=i+1;
query2.next;
end;
//end while...
query3.first;
j:=0;
while (not (query3.fieldbyname('flmc').asstring=query1.FieldByName('flmc').asstring))
and (not query3.eof)do
begin
j:=j+1;
query3.next;
end;
//end while...
pArrayOfResult^[i,j]:=pArrayOfResult^[i,j]+query1.fieldbyname('column3').value;
query1.next;
if pArrayOfResult^[i,j]<>0 then
begin
Psum_Array[i,j] := TQRLabel.Create(self);
with psum_array[i,j]do
begin
Parent := QRBand1;
AlignToBand := False;
AutoSize := false;
AutoStretch := False;
Color := clWhite;
Font.Style := [fsitalic];
Font.Name :='Arial';
Font.Size :=6;
top :=pks_array.top;
left :=pfl_array[j].left;
height:= pks_array.height;
width :=pfl_array[j].left;
caption:=Format('%m', [pArrayOfResult^[i,j]]);
//Format('%8.2f', [pArrayOfResult^[i,j]])
end;
//with
end;
//if 实数数组的数字不为0,那么产生一个TQRLABEL对象,并赋值给这个对象
end;
//end while not query1.eof...
// 上面这段过程预先分配数值给一个2维实数数组
finally
FreeMem(pArrayOfResult, query2.recordcount * query3.recordcount * SizeOf(real));
end;
{try}
end;


procedure Tdanaprintfrm.FormDestroy(Sender: TObject);
var i,j:integer;
begin
for i:=0 to query2.RecordCount-1do
pks_array.free;
for j:=0 to query3.RecordCount -1do
pfl_array[j].free;
// for i:=0 to query2.recordcount -1do
// for j := 0 to query3.recordcount -1do
// psum_array[i,j].free;
end;

end.
 
我实现这个问题的办法比较麻烦了, 我自己做了个通用报表设计器, 又做了个报表
打印器, 然后交给用户, 他们爱怎么定义报表就怎么定义. :)
如果你要的话, 我可以给你一份.我先自我吹嘘一下:
. 可以自动产生输入界面(如果需要输入的话)
. 自动生成采集数据所需sql, 数据可来源于不同表或数据库
(目前只支持dbf数据库和ms sql server的表)
. 提供20来种数学计算公式,6种日期公式,1种时间函数, 3种字符串函数
2种中文金额转换函数, 3种逻辑字段表示方法(其中一种是图形方式),
2种自动增减变量, 2种条件控制(if...else
型 和 case型)
. 可以根据设计时的情况控制页长, 页宽, 多页, 分栏.
. 可以打印斜线
. 设计时所见即所得
. 设计时只需简单地用鼠标拖动各表格单元, 程序自动判断各单元格之间的关系
. 打印时表格单元高度和宽度可根据设计时的选项自动调整
. 支持图象
遗憾的是help一直懒得做.
 
我做报表可惨了,用临时表,改变QREPORT里的值,实在麻烦的要死!
诸位大侠,(Another_eYes,Shenxinaz,坏人!)
有什么好东西,大家参考参考!MAIL 我一份吧!!谢谢!!!
cjcjc@online.sh.cn
顺便说:王兄,你主页速度太慢,新闻组笔记传到一般就中断了,能不能MAIL我一份?
 
Another_eYes,我很感兴趣,勿请有劳您Email给我?
 
不好意思, 我发觉我的东西打印时速度太慢, 正在动大手术, 等完成后还请各位
帮忙测试
 
以前我也做了一个这样的报表生成器.
用户用 formula 3设计报表.在程序中读入
xls文件再打印.借助 formula 的功能.可由
用户轻易完成报表的设计,打印.程序是单位的.
不好意思给.大思路可以说一下:
1在 formula 之中先生成数据页 sheet_data
2在数据页中,添入数据项.
3在另一页 sheet_print 中,设计报表.如:
sheet_print.a1=sheet_data.needdata
.......
4 在打印中,将数据页中的数据添上后打印.
优点.程序简单.报表设计功能多(formula 替你做的 :))
缺点:formula 支持中文性差.
同样的思路可用到 中文excel 中.它的中文支持性强.
我完成项目后据懒得移了.若你像这样写的话.完成后给俺
一份.
 
看来这样的东西大家都做得不错,不知道能不能由斑竹协调一下,
吸收大家的精华,搞一个完整的东西,也可以是算我们delphiBBS
的一大成果.
昨天看这一期的<读者>,有一篇讲数学的一个学派,每次都要把
预备发表的东西互相攻击,直到排除一切可以想到的不完善之处,
发表后就质量极高,我们是不是也可以这样做?
只是大家不能太气短,大家争起来打成一团就糟了.
 
晓钢说的有道理!我同意!
写程序可能我的水平有限,不过读程序和找毛病...我可是一流!
 
我对Quick Report作了一些改进,可以动态生成报表,带表线,支持主从关系,有意请与我联系
 
jzy,请寄给我,可以在此贴出来。
 
通过调用Excel是比较方便的,恐怕也是最好的吧?
 
What so special about creating QReport at runtime?
QReport is a delphi class, isn't it?
To create a Quick Report object at runtime is exactly the same as
create other object.
If you want to see a example, you cando
wn load a file <a href="http://www.zhanglong.com/softwork/components/dcuberep.zip">DCubeRep.Zip</a> which generates a quick report at run time for a DecisionGrid.
 
太麻烦了,用ReportBuilder,它有EndUser Design功能
 
为什么不用EXCEL呢,DELPHI中完全可以打开EXCEL,然后用EXCEL的宏来做可能
会方便些
 
最新的Delphi Tip: <big>Creating Reports at runtime</big>
可以使用 QRExtra.dcu中的 QRCreateList 函数动态创建 Report
QRCreateList(var AReport: TCustomQuickReport;
AOwner: TComponent;
ADataSet: TDataSet;
ATitle: String;
FieldList: TStrings);
AReport ------- 返回的 Report Instance
AOwner -------- Report 的 Owner 可以是一个 TForm
ADataSet ------ 数据源, 可以是 Table 或 Query
ATitle -------- Report 的标题
FieldList ----- 数据源中的 Fields
如果此项为 nil 或 TStrings 的 Count = 0 则包括所有字段
例如:
uses ..., QuickRpt, QRExtra;
type
TForm1 = class(TForm)
Button1: TButton;
Table1: TTable;
procedure FormDestory(sender: TObject);
//用来释放 Report, FieldList
private
public
Report: TQuickReport;
FieldList: TStringList;
end;

var
Form1: TForm1;
Implementation
procedure TForm1.Button1Click(sender: TObject);
begin
AReport := nil;
//该项必须为 nil
FieldList := TStringList.Create;
//选择适当的字段
FieldList.Add(字段名);
...
{Call QRCreateList to make the report. The report has a Column
Header band and a Detail band. You can customize it later to
add more band or QRCtrls, before calling preview or print.}
QRCreateList(Report, Self, Table1, '动态生成的报表', FieldList);
//用户化 Report
...
end;

用此函数多少可以省却初始化 QReport 的工作, 如果要漂亮还得做很多事情
 
FarPoint公司的动态报表东东spead 5M(activex),梦想级,不知各位要不要,要的话就找一个ftp搁上去。
 
顶部