Delphi报表制作技巧20篇 - 图文(3)

2019-06-17 16:56

end; aText := TQRDBText.Create(Form2); '设置显示字段内容 aText.Parent := DetailBand1; with aText do begin AutoSize:=False; AutoStretch:=True; Height:=DetailBand1.Height; DataSet:=Table1; DataField:=Table2.FieldbyName( 'FieldsName').AsString; Alignment:=taCenter; end; LeftValue:=LeftValue+80; Table2.Next; end; end; end; ---- 好了,运行程序可以看到报表预览的效果,显示了Goods中的ID,Name,Price。在运行时完全可以控制table1和table2中的数据内容。显示不同数据库的不同信息,改变table2中的记录顺序可改变报表中的显示顺序。而且,由于报表的各部分,甚至包括各band和system data均可在程序运行时依据上述方法动态生成。其属性也可动态设置。所以我们完全可以制作一个类似于Dephi中Form Wizard一样的报表精灵,还可提供一个灵活而且强大的打印设置功能。 ---- 以上代码在delphi3中运行通过。 把查询信息输出到word打印 我喜欢用EXECEL输出,这是我文档管理的报表代码,DELPHI可以直接调用EXECEL对象 WORD行的,不过我这里没资料有EXECLE的,因为EXECEL就是做报表的嘛 记得USE里用到comobj, 在说下两个变量v,sheet:variant;是窗体类里申明了的 procedure Tfmsearch.expbtClick(Sender: TObject); var range:variant; i,j:integer; begin if dm1.qrinfo.RecordCount=0 then begin MessageBox(handle,Pchar('没有记录可输出'),'输出提示',0+48); exit; end; v:=createoleobject('excel.application'); v.workbooks.add; v.workbooks[1].worksheets[1].name:='文章清单'; sheet:=V.workbooks[1].worksheets[1]; v.visible:=true; range:=sheet.range['A1:E1']; range.merge; range.borders.linestyle:=0; range.formular1c1:='文 章 清 单'; range.horizontalalignment:=3; range.verticalalignment:=2; range.characters.font.name:='宋体'; range.characters.font.fontstyle:='加粗'; range.characters.font.size:=15; range.characters.font.colorindex:=2; range.interior.color:=$00bbbbbb; // range:=sheet.range['A2:E2']; range.merge;

11

range.borders.linestyle:=0; range.formular1c1:='输出用户:'+curuser+ ' 输出日期:'+formatdatetime('yyyy\年\月\日\range.horizontalalignment:=3; range.verticalalignment:=2; range.characters.font.name:='宋体'; range.characters.font.size:=10; range.characters.font.colorindex:=2; range.interior.color:=$00Bbbbbb; // sheet.cells[3,1]:='编号'; sheet.cells[3,2]:='文章名称'; sheet.cells[3,3]:='录入日期'; sheet.cells[3,4]:='录入用户'; sheet.cells[3,5]:='保密性'; // for i:=1 to 5 do begin sheet.cells[3,i].borders.linestyle:=1; sheet.cells[3,i].horizontalalignment:=3; end; dm1.qrinfo.First; j:=3; while not dm1.qrinfo.Eof do begin inc(j); sheet.cells[j,1]:=dm1.qrinfotextid.AsString; sheet.cells[j,2]:=dm1.qrinfotextname.AsString; sheet.cells[j,3]:=dm1.qrinforecdate.AsDateTime; sheet.cells[j,4]:=dm1.qrinforecuser.AsString; sheet.cells[j,5]:=dm1.qrinfotextsec.AsString; dm1.qrinfo.next; if dm1.qrinfo.Eof then break; end; range:=sheet.range['A4:'+'E'+inttostr(j)]; range.borders.linestyle:=1; // sheet.cells.entirecolumn.autofit; sheet.pagesetup.printtitlerows:='$1:$3'; sheet.pagesetup.rightheader:='execel报表'; sheet.pagesetup.leftheader:='共'+inttostr(dm1.qrinfo.RecordCount)+'篇文章'; sheet.pagesetup.centerfooter:='共&N页'+'/第&P页'; sheet.pagesetup.centerhorizontally:=true; sheet.pagesetup.orientation:=1; sheet.pagesetup.draft:=false; sheet.pagesetup.blackandwhite:=true; sheet.pagesetup.zoom:=100; v.displayalerts:=false; sheet.printpreview; end; 财务报表 1、哪个单位的财务科都有几本厚厚的台帐,我院财务科提出打印药库的台帐,好脱掉手工帐,也算是办公现代化了,

12

要求合情合理,院长也说应当如此。看着财务科提供的红绿相间的、统一印制的、行间距3毫米的台帐专用小卡片,我不由想到中国人节俭的美德。考虑到每个药品至少打印一张,而且表格线一个都不能少,加上中医院药品有二千多种,所以这个报表必须用激光打印机来打印(至于如何让院长同意购买激光打印机,则是另一回事,办公自动化哪能没有代价呢)。程序实现的思路基本上是把打印纸当做画布在上面画一个个小矩形,具体由以下几个过程实现:(设Form名为Ttzview)。 先在程序中定义二个类:titlerecord=record Currect:Trect; Atitle:string;end;detailrecord=record Arect:Trect; alignment:word;end; ---- 再建立以下四个过程; RectDraw(Acanvas:Tcanvas;s:string;R:Trect;frame:boolean;position:word); 这个过程就是画矩形用的,frame决定是否画线(这里当然要画啦!); printinitit(firsttop,firstleft:integer); 这个过程是初始化用的,就是定义各个小矩形在纸上的位置; printtitle(acanvas:Tcanvas); 这个过程是打印表头的,因为表头的字总是要大一些; printdetail(acanvas:Tcanvas;Qtz:Tdataset;acount:integer;firstpage:integer); 这个过程才是打印具体内容的,一页打印40行,不够就换页,总之一页只能是一个药品; printhj(acanvas:Tcanvas); 一看就知道,这个过程就是打印合计的啦! 只要建个Botton,顺序调用printinitit,printtitle,printdetail,printhj这四个过程就行了, (调用格式:printtitle(printer.canvas);) 对了,Qtz就是查询出来的台帐数据,如何生成的这里就不谈了。 此程序在delphi1,delphi3版本WIN3.2,WIN95,WIN97,WIN98平台下运行通过,顺便提供台帐数据库的库结构 2、非常复杂,无法取巧的报表 我院肿瘤科需要打印病人的病案,这可是特色专科现代化建设的一部分,卫生局要来检查的,所以必须完成任务。每一个病案有100多个项目,若用Qreport,中间如果要加减一个项目(这事常有),几十个项目的调整排列会使人昏倒。我一下子建立100多个临时变量,在虚拟的画布上画啊画,运行在我的PII233,64M内存的机子上倒是顺顺当当的,不过换到肿瘤科的486,8M内存的机子上时(大家别笑),系统堆栈马上溢出,所以只好祭出指针大法(我的编程水平好象又有长进,窃喜),方法如下: 先建立titleprint类: titleprint=^Titlerecord;titlerecord=record Currect:Trect; Atitle:string[50];end;再建立过程printnow(Form的名称叫zlk,printdot就是打印机的点数,一般针打是180);procedure Tzlk.printnow(acanvas:Tcanvas);var i,x,y,pc_count:integer; myprint:array[0..200] of titleprint;begin firsttop:=round(int(0.5/2.54*printdot)); firstleft:=round(int(0.1/2.54*printdot)); rowheight:=round(int(0.7/2.54*printdot)); x:=0+firstleft;y:=round(int(1.3/2.54*printdot))+firsttop; pc_count:=0; inc(pc_count); new(myprint[pc_count]); myprint[pc_count]^.currect:=rect(x+round(int(0.1/2.54*printdot))+firstleft,y,x+round(int(3.0/2.54*printdot))+firstleft,y+firsttop+round(int(0.5/2.54*printdot)));myprint[pc_count]^.atitle:=Lname.caption+DBname.text;ACanvas.MoveTo(myprint[pc_count]^.currect.left, myprint[pc_count]^.currect.top-round(rowheight/5));{下面的四行还要重复100多次,基本差不多,就不都写出来赚稿费了}inc(pc_count); new(myprint[pc_count]);myprint[pc_count]^.currect:=scalerect(myprint[pc_count-1]^.currect,round(int(2.5/2.54*printdot)),0); myprint[pc_count]^.atitle:=Lxb.caption+Cxb.text; ACanvas.LineTo(myprint[i]^.currect.right, myprint[i]^.currect.top-round(rowheight/5)); ....... {打印} printtitle(acanvas); {这个函数就不提供了,表头不要也没关系} for i:=1 to pc_count do begin RectDraw(Acanvas,myprint[i]^.atitle,myprint[i]^.currect,false,dt_left or dt_singleline or dt_vcenter); end; dispose(myprint[pc_count]); {别忘了把指针占用的内存释放}end; 最后建个Botton,加个是否真的打印的判断,再调用这几个函数就行了。 (调用格式:printtitle(printer.canvas);) 看了以上两个例子,是不是觉得WINDOWS下的打印其实很简单,就跟你手工画表一样,而且表格内容的位置是居中、居左、还是居右,全由打印内容的Alignment决定,打印格式由内容的Display Format决定,用不着自己去算,方便极了。 报表 一、问题的提出 ---- Delphi作为强大的数据库开发工具,正被愈来愈多的编程人员所采用,\聪明的程序员用Delphi\更形象生动的道出广大程序员的心声,但这并不意味着所有功能的实现都非常容易,例如,笔者在开发军队的某个信息系统中,就在为数据分析模块中DecisionGrid1控件的数据进行报表输出时走了不少的弯路。广大的Delphi的爱好者在今后的学习或工作中也有可能会遇到类似的问题,而在许多参考书中,很少有甚至没有关于它们的解决方法,于是,我想花费一点时间把它整理出来,以供大家参考。本文中报表动态生成的公用模块具有很大的灵活性和易操作性,其中的思路、实现的功能和通用性等方面的优缺点就由大家看了本文后自有定论。

13

二、建立报表的动态输出公用模块 ---- 下面,结合公司人事管理信息系统说明其实现的方法和技术。 ---- 1、基本思路:首先从DecisionGrid1中获得报表所需数据,放到二维数组PA中,然后在C:\\DataWork中动态创建一个数据表tjb.dbf,存放报表数据,最后用T able1与tjb.dbf相连接,以后工作就与一般的动态输出报表(如查询报表)相类似,在这里我就无须赘述了。 ---- 2、建立窗体文件:放入六个用于数据分析的常用控件DecisionQuery1、DecisionSource1、DecisionCube1、DecisionGraph1、DecisionPivot1、DecisionGrid1,设置DecisionSource1的decisionCube属性为decisionCube1,decisionCube1的Dataset属性为decisionQuery1、decisionQuery1的DatabaseName属性为c:\\datawork;一个Table1控件,用于连接数据表tjb.dbf;一个QuickRep1控件,用于数据的报表输出;两个Button1和Button2控件,其Caption分别设为\报表输出\和\返回\。分别设置decisionCube1的Dataset属性为decisionQuery1、decisionQuery1的DatabaseName属性为c:\\datawork.。 ---- 3、单元文件的主要控件代码 Button1控件的代码如下(定义变量部分略),主要分以下8个功能块来加以说明: ---- ⑴删除同名或上一次建立的数据表 if FileExists('c:\\DataWork\\tjb.dbf') then deletefile('c:\\ DataWork \\tjb.dbf'); ---- ⑵根据DecisionGrid1控件的cells属性,获得报表所需数据,并将其默认的'Sum'值汉化成'总计'、'合计'、'小计'以符合汉语的习惯要求,所求得的数据存放于二维数组PA中 for i:=1-DecisionGrid1.FixedCols to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 dofor j:=0-DecisionGrid1.FixedRows to DecisionGrid1.RowCount-DecisionGrid1.FixedRows-1 do beginpa[i,j]:=DecisionGrid1.cells[i,j];//处理DecisionGrid1控件中固定列的值为'Sum'的数据项if ((i=1-DecisionGrid1.fixedcols) and (pa[i,j]='Sum')) then pa[i,j]:='总 计' else if ((i = -1) and (pa[i,j]='Sum')) then pa[i,j]:='小 计' else if ((i<-1) and (i>1-DecisionGrid1 .FixedCols) and (pa[i,j]='Sum')) then pa[i,j]:='合 计';//处理DecisionGrid1控件中固定行的值为'Sum'的数据项 if (pa[i,j]='Sum' ) and (j=-1) thenpa[i,j]:='总 计';end; ---- ⑶用T able1动态创建数据表tjb.dbf Table1.Active:=false;with Table1 dobegin DatabaseName := 'c:\\DataWork'; TableName := 'tjb'; TableType := ttDBase; with FieldDefs do begin Clear; for i:=1 to 40 do Add(IntToStr(i),ftString,30, False); end; CreateTable;end;//下面将DecisionGrid1控件中的数据放入数据表中Table1.Active:=true;for j:=1-DecisionGrid1.FixedRows to DecisionGrid1.RowCount-DecisionGrid1.FixedRows-1 do begin K:=0; Table1.Insert;for i:=1-DecisionGrid1.FixedCols to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do begin Table1.Fields[K].AsString:=pa[i,j]; K:=K+1; end; Table1.Post; Table1.Next; end; ---- ⑷下面代码确定输出报表的每列宽度 SetLength(M,DecisionGrid1.ColCount);//动态设置数组copy(M,1-DecisionGrid1.FixedCols,DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1);//重新设置动态数组的起始位置for i:=1-DecisionGrid1.FixedCols to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do begin M[i]:=0;for j:=1-DecisionGrid1.FixedRows to DecisionGrid1.RowCount-DecisionGrid1.FixedRows-1 do IF M[i]< Length (Trim (PA[I,J]))*8 THEN M[i]:= Length (Trim (PA[I,J]))*8; end; ---- ⑸如果要求输出报表的列宽相同(除DecisionGrid1控件的固定列,下同),可将数据项的最大列宽作为输出报表的列度,如果不要求,可跳过下面代码 max:=0;for i:=0 to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do if m[i]>max then max:=m[i];for i:=0 to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do m[i]:=max;ZK:=0;//报表总宽for i:=1-DecisionGrid1.FixedCols to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do ZK:=ZK+M[i]+1; ---- ⑹判断报表的宽度,超宽?横向报表?还是纵向报表? if ZK>1123 then beginApplication.MessageBox('报表超宽,请调整再输出!','警告', 1);//输出对话框 exit; endelse if ZK>794 then QuickRep.Page.Orientation:=poLandscape //横向 elseQuickRep.Page.Orientation:=poPortrait;//纵向 ---- ⑺以下代码完成了动态数据报表,与一般的动态输出报表功能相类似, for i:=1 to QuickRep.Bands.TitleBand.ControlCount DO//取消系统对控件的控制,下同 QuickRep.Bands.TitleBand.RemoveControl (QuickRep.Bands.TitleBand.Controls[0]);for i:=1 to QuickRep.Bands.DetailBand.ControlCount DO QuickRep.Bands.DetailBand.RemoveControl (QuickRep.Bands.DetailBand.Controls[0]);SetLength(QRShape,DecisionGrid1.ColCount); //动态设置数组SetLength(QRDBText, DecisionGrid1.ColCount); //动态设置数组K:=0;//动态生成对象的数,Lx:=(QuickRep.Width-ZK)DIV 2;//生成对象的左坐标//报表的动态生成For j:=1-DecisionGrid1.FixedCols to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do begin QRShape[K]:=TQRSHAPE.Create(tj1);//自定义对象的创建(下同) QRShape[K].Parent:=QuickRep.Bands .DetailBand;// 自定义对象的父类对象(下同)

14

QRDBText[K]:=TQRDBText.Create(tj1); QRDBText[K].parent :=QuickRep.Bands.DetailBand; QRShape[K].LEFT:=Lx;//生成对象的左坐标 QRShape[K].WIDTH:=M[J]+2; //生成对象的宽度 QRShape[K].HEIGHT:=QuickRep.Bands .DetailBand.Height+1; //生成对象的高度 QRShape[K].TOP:=-1; //生成对象的纵坐标 QRDBText[K].WIDTH:=QRShape[K].WIDTH-10; QRDBText[K].Left :=QRShape[K].LEFT+1; QRDBText[K].HEIGHT:=QRShape[K].Height div 2; QRDBText[K].Top :=QRDBText[K] .Height div 2+QRShape[K].Top; QRDBText[K].AutoSize:=false; QRDBText[K].Alignment:=taCenter; //生成对象居中 QRDBText[K].DataSet:=Table1; QRDBText[K].DataField:=IntToStr(k+1); Lx:=Lx+M[J]+1; Inc(k); end;//动态生成报表的标题 Caption := TQRLabel.Create(tj1);Caption.Parent := QuickRep.Bands.TitleBand;Caption.Alignment:=taCenter;//标题居中Caption.Width:= Length (Trim (ptitle))*8; //标题的宽度Caption.Left:=(QuickRep.Width- Length (Trim (ptitle))*8)div 2; //标题的左坐标Caption.Height:=QuickRep.Bands.TitleBand.Height-1; //标题的高度Caption.Top:= 0;Caption.Caption:=ptitle; //标题的名称,ptitle为调用该公用模块时的输入参数QuickRep.DataSet:=Table1;QuickRep.Preview;⑻动态生成对象的内存释放k:=0;for j:=1-DecisionGrid1.FixedCols to DecisionGrid1.ColCount-DecisionGrid1.FixedCols-1 do begin QRShape[K].Free; QRDBText[K].Free; inc(k); end;Caption.Free;Table1.Active:=false;//关闭数据表end; ---- 以上程序是在Delphi 4.0中调试通过,其数据文件应放在C:\\DataWork,类型为DB或DBF。 三、应注意以下几个问题 ---- 1、QuickRep1的Bands中的HasColumnHeader、HasDetail、HasTitle三个属性必须设置为true; ---- 2、不能忘记公用模块中QuickRep对象的DataSet属性设置,即源代码中的QuickRep.DataSet:=Table1语句; ---- 3、动态生成组件的宽度计算必须放在定义其字体属性完成后进行; ---- 4、另外,动态数组给定的内存(即数组容量)以及指定动态数组的起始位置(不一定为0,根据DecisionGrid1控件的固定列确定)很重要,因为一方面当数据库很大时它会大大减少内存的消耗,另一方面便于操作该数组,大大增强了程序的灵活性和通用性。 ---- 5、如果让QRDBText控件的数据居中,必须先设置其AutoSize属性为false,然后才能设置其Alignment属性为taCenter。这一点往往容易忽略,直接设置Alignment属性为taCenter,往往达不到数据居中的目的。 四、结束语 ---- 当然,由于客户对数据报表的可能特殊要求,此公用模块或许不能完全解决。但是,作为公用模块,能实现实现代码的重复利用,提高我们开发程序的效率,当然可以在此模块的基础上进行一些修改或补充,以满足大多数用户的要求,用以下两点加以说明。 ---- 1、如果要对数据表的字段进行动态选择输出,则可以将动态产生的数据表字段传递到另一个窗体进行输出选择,然后根据你所选择的字段进行报表输出,源程序几乎无须修改即可实现。 ---- 2、若要改变数据分析的内容(即直方图的维)时,只须修改SQL语句即可,动态、静态均可,具体的操作也就无须我多言了。各位Delphi编程爱好者不妨一试。 格式化整数输出。 比较大的数字在输出时会显得不易阅读,在Delphi中显示带分节号的数字是相当简单的一件事,如下即可:xxxxx.caption:ΚFormatFloat(′#′,524667500)。 任意打印 有时我们要打印任意排列的表或往已经印好的登记表上对号入座写上数据时,可以新建一个窗体(假设为Form1),再把Form1的BorderStyle设为bsNone、AutoScroll设为True,接下来再创建一个新窗体(假设为Form2),再建个按钮Button1,编写代码: procedure TForm2.Button1Click(Sender: TObject); begin Form1.Width :=900; Form1.Height :=800; Form1.Print;

15


Delphi报表制作技巧20篇 - 图文(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:西兴互通边施工边通车安全专项方案 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: