kl800.com省心范文网

Fastreport使用经验


Fastreport 使用经验
[FORMATDATETIME('mm-dd', [IBqryShipDate."CLOSEDATE"])] [FORMATDATETIME('mm/dd/yy', [IbqryOrderForm."ORDERDATE"])] 金额总计:[FORMATFLOAT('#########0.00', [TotalAmount])] [FORMATFLOAT('#,##0.00',[qryDetail."JinE"])] 订单数量:[COUNT(band1)] 数量合计:[SUM([IBqryShipDate."QUANTITY"])] 婚否:[IF([IbqryPersonal."ISMARRIAGED"]=1, '是', '否')] [IF([qryData."CLOSEDATE"]=0,'',[FORMATDATETIME('yyyy-mm-dd', [qryData."CLOSEDATE"])])] [IF([qryCustoms."EXPORTDATE"]=0,'',[DateEngStyle([qryCustoms."EXPORTDATE"])])] [IF([qryPrints."TOTAL1"]=0,'',[qryPrints."TOTAL1"])] [IF([qryPrint."CURDATE"]=0,'',[FORMATDATETIME('mm-dd',[qryPrint."CURDATE"])])] [IF([qryPrint."STYPE"]='0', [Ban], [Huo])] [Copy([qryData."WASHMETHOD"],1,8)] while iCount < 4 do begin ShowBand(Child1); iCount := iCount + 1; end; begin if FreeSpace < SubBand1.Height then NewPage else begin iTotal10 := iTotal10 + 1; if iTotal10 > 10 then NewPage; end; end 在 Delphi 程序中访问报表对象 最基本的方法就是 frxReport1.FindObject。然后把返回的对象强制转换成它的类型,当然, 在 报 表 中 必 须 真 的 有 这 么 个 东 东 。 如 改 变 一 个 Tfrxmemoview 的 内 容 , 可 以 这 样 写 TfrxMemoView(frxReport1.FindObject('memo1')).Text:='jade'; 还可以用 TfrxReportPage 的 FindBand 方法,这个方法的参数是 Band 类,如报表抬头就可以 直接使用这个方法,因为抬头一个页中只有一个,如果有多个同样的类。则不能使用这种方 法。如果要使用 TfrxreportPage,一般可以用这样的代码 TfrxReportPage(frxReport1.Pages[0])。当然,如果你的这个页是对话框型的,则不行了。但一 般都是报表型的。 ******使用上下标 在 Fastreport 中使用上下标是很简单的,只要用一个 Tfrxmemoview,把 AllowHTMLTags 属性 设为真,就可以使用网页标签来实现上下标了,如 12<sup>2</sup>与 24<sub>3</sub>。就分别是 2 为上标,3 为下标。

******打印页码 打印页码是很简单的,只要加入一些常量即可,如打印第几页共几页就可以使用 第[Page#]页 共[TotalPages#]页 这里要注意的一点是如果想正确显示总页数,必须选中二次报表。

******动态建立变量及变量组 建立变量组名 frxreport1.Variables.Add.Name:=' '+变量组名; 建立变量名 frxreport1.Variables.AddVariable('组名,如果为不存的组或空,则为默认组,这里不需要空格 ',变量名,变量初始值); 例如要建立变量组 Yuan,二个变量 Yuan1,Yuan2,则为 frxreport1.Variables.Add.Name:=' Yuan';注意前面是空格 frxreport1.Variables.AddVariable('Yuan',Yuan1,初始值) frxreport1.Variables.AddVariable('Yuan',Yuan2,初始值) ******共用 TFrxreport 及 TfrxDBDataSet 一个程序中,不管多么大的程序,只要打印或预览时是模式的,则完全可以共用一个 TFrxreport 变量及几个 TfrxDBDataSet。只不过,要注意完成一个报表程序的步骤,主要是下 面几步: 1)清除报表,得到一个全新的报表内容。 Frxreport1.clear。 2)设置要使用的 TfrxDBDataSet 的别名,如果不需要可以省略这一步,但一般最好不同的报 表用不同的别名。 注意这一步要在加载报表文件之前,因为一般设计报表文件时已经包含了别名信息。 frxDBDataSet1.UserName:=别名; 3)加载报表或动态建立一个 TfrxReportPage。 Frxreport1.LoadFromFile(报表文件的完整文件名); 4)关联 TfrxDBDataSet 与 TDataset,并设置要使用哪些 TfrxDBDataSet。 Frxreport1.DataSets.Clear;//先清除原来的数据集 frxDBDataSet1.DataSet:=dataset1;//关联 Fastreport 的组件与 TDataset 数据集。 Frxreport1.DataSets.Add(frxDBDataSet1);//加载关联好的 TfrxDBDataSet 到报表中。 经过这几步后,就可以像单独使用一个 Tfrxreport 一样使用共用的报表组件了。 ******加入自定义函数 Fastreport 可以自己加入需要的函数,来实现特定的功能。过程就是: 1)添加函数到报表中。 frxreport1.AddFunction('完整的函数声明'); 如有一个自定义函数,为 GetName(Old:String):String;这个函数通过数据集的一个字段,得到 另一个返回值。 则语句为:frxreport1.AddFunction('Function GetName(Old:String):String;'); 2)脚本中使用函数。 在脚本中或报表中使用自定义函数,就像使用其它 Fastreport 内置函数一样。 3)程序中处理函数。 使用函数是通过 frxreport1 的 OnUserFunction 函数来实现的。

OnUserFunction 的声明如下: Function(const MethodName: String;var Params: Variant): Variant; 比如上面的函数,首先要有一个函数,这个函数是 GetName 的实现部分。如有一个在程序 中实现的函数。 function RealGetName(Old:String):String;这个函数名是无所谓的,也可以是 GetName。 在 OnUserFunction 的事件处理中有如下代码即可完成自定义函数在报表中的使用。 if CompareText(MethodName,'GetName')=0 then Result:=RealGetName(VarToStr(Params[0])); 我一般都是使用 CompareText 来比较函数名,因为我发现二个版本的 Fastreport,一个是 MethodName 全部自动变成了小写,一个是全部自动变成了大写,所以干脆用 CompareText 来比较,肯定不会出错。 如果有多个参数,则依次传递 Params[0],Params[1]即可,要保持顺序一致。 这里要注意一点,如果参数为指针,则不能直接使用 Pointer(Integer(Params[0]))。因为实际 传递过来的是指针的整数值,可以使用 Pointer(StrToInt(VarToStr(Params[0])))。 ******使用脚本,脚本中使用变量 很多时候,我们希望把对报表的控制放到报表的脚本中,通常我这样做有二个原因: 1)能够根据字段内容的变化而使用不同的设置,因为如果想在程序中实现这样功能,就不得 不用自定义函数,函数的实现要放到程序中,函数 可能需要传递很多参数,效率低下。 2)把不同报表的控制放到脚本中,可以实现报表的模块化,程序只是简单的设置数据集的关 系,并加载硬盘上的报表文件,不同报表的不同实 现方式,显示方式,均放到报表文件中,程序简洁,易维护,易升级。 当然,这样的缺点就是程序中加载报表时的数据集别名必须与设计报表时的别名一致。 脚本的使用与通常程序的使用并没有太多的区别, 就是像正常的程序那样引用控件的名称即 可。但注意对变量的使用,需要把变量名或表达式用<>括起来。 ******在脚本中根据字段名改变 Tfrxmemoview 的内容 假设有数据表“用户” ,字段 ID 为用户标识,Name 为用户名,打印时要求,如果用户名为 空,则打印“无用户名” 否则打印出 , “用户名: 实际的用户” ,则可以在 ID 的 Tfrxmemoview 控件的 OnAfterData 事件中写如下脚本。 if <frxDBDataSet1."Name">='' then Memo2.Text:='无用户名' else Memo2.Text:='用户名:[frxDBDataSet1."Name"]' Memo2 是放置用户名称数据的 Tfrxmemoview 控件。 这里注意,要在脚本中访问变量需要把变量用<>包括起来。 ******实现连续打印 很多人认为 Fr 不能实现连续打印, 以为只能通过自己写函数调用打印函数来实现连续打印, 实际上,Fr 可以轻易的实现连续打印,同时,实现时又是非常简单,你甚至可以在你的程 序的打印设置中简单的让客户选择是否连续打印,其它都可以保持不变。 function PelsTomm(Pels:Extended):Extended; begin Result:=Pels/Screen.PixelsPerInch*25.4; end; procedure PrintSerial(Frx:TFrxReport;SequencePage:Byte=0); var P:TfrxReportPage;

R,R1:Extended; begin {必须是二遍报表,否则无法计算总页数。 下面的方法只适用于没有页脚的情况,因为如果有页脚的话 FreeSpace 就始终为 0 了。可以用报表脚来代替。 因为是连续打印,也可以看作只有一页,报表脚也就相当于页脚了} if not Frx.Engine.DoublePass then Exit; //SequencePage 指要连续打印的页面,普通报表就是 0 P:=TfrxReportPage(Frx.Pages[SequencePage]); R1:=P.TopMargin+P.BottomMargin; while Frx.PrepareReport do begin if (Frx.Engine.TotalPages<=1) then Break; R:=Pelstomm(Frx.Engine.TotalPages*Frx.Engine.PageHeightFrx.Engine.FreeSpace)+R1; P:=TfrxReportPage(Frx.Pages[SequencePage]); P.PaperHeight:=R; end; {必须用上面的循环代码来得到准确的空白区域 不能用通过计算总页数减去各页的页边距的方法来获得空白区域 因为如果碰到一条记录过宽的情况导致换页,就不准确了。} R:=Pelstomm(Frx.Engine.TotalPages*Frx.Engine.PageHeightFrx.Engine.FreeSpace)+R1; P:=TfrxReportPage(Frx.Pages[SequencePage]); P.PaperHeight:=R; end; 在预览或打印前先调用 PrintSerial 即可。 也谈为 Delphi 中数据库报表加网格开发者在线 Builder.com.cn 更新时间:2007-11-02 作者: 佚名 来源:中国计算机报社 本文关键词: delphi 数据库 报表 网格 看了贵报第 63 期《为 Delphi 3.0 中数据库报表加 上网格线》一文,笔者发现原文中的程序在不同分辨率的打印机(如 180dpi 的针式打印机 和 600dpi 的激光打印机)上打印表格,效果会完全不同。如作者以针打作为他的输出打印机设 计的程序,在激光打印机上输出,就会发现表格和文字错位,而且表格会打印得很小。而且 原文中打印坐标的确定,必须靠反复的试验才能达到比较满意的效果。 针对原目标,笔者设计了一段程序。首先在窗体上添加一个 DBGrid 来显示我们所要打 印的数据,在这里,DBGrid 不只是起到显示数据的作用,而且用户对 DBGrid 作的调整,例 如改变了各字段的排列顺序,各字段的显示宽度等,都将直接反映到打印结果中去,也就是 说,我们实际上就是要把 DBGrid 的内容直接输出到打印机。以下程序在 Win 98+Delphi 4 下 编译通过,代码如下: procedure TForm1.Button2Click(Sender: TObject); const LeftBlank=1; //定义页边距,单位厘米 RightBlank=1;

TopBlank=1; BottomBlank=1; var PointX,PointY:integer; PointScale,PrintStep:integer; s:string; x,y:integer; i:integer; begin //获取当前打印机的分辨率 PointX:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/2.54); PointY:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSY)/2.54); //根据打印机和屏幕的分辨率计算出从屏幕转换到打印机的比例 PointScale:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX) /Screen.PixelsPerInch+0.5); //横向打印 printer.Orientation:=poLandscape; //打印的字体和大小 printer.Canvas.Font.Name:=′宋体′; printer.canvas.Font.Size:=10; //根据字体的大小确定每行的高度 s:=′漳州市刑警支队′; PrintStep:=printer.canvas.TextHeight(s)+16; //打印的起点位置 x:=PointX*LeftBlank; y:=PointY*TopBlank; //DataSource1 是 DBGrid1 所连接的数据源 if ((DataSource1.DataSet).Active=true) and ((DataSource1.DataSet).RecordCount〉0) then begin printer.BeginDoc; (DataSo e1.DataSet).First; while not (DataSource1.DataSet).Eof do begin //打印 DBGrid 中的所有列 for i:=0 to DBGrid1.FieldCount-1 do begin //假如所要打印的列超出了打印范围,则忽略该列 if (x+DBGrid1.Columns.Items[i].Width*PointScale) =(Printer.PageWidth-PointX*RightBlank) 〈 then begin //画表格线 //每页的第一行打印表头 Printer.Canvas.Rectangle(x,y,x+DBGrid1.Columns. Items[i].Width*PointScale,y+PrintStep); if y=PointY*TopBlank then Printer.Canvas.TextOut(x+8,y+8,DBGrid1.Columns[i].Title.Caption) else Printer.Canvas.TextOut(x+8,y+8,DBGrid1.Fields[i].asString);

end; //计算下一列的横坐标 x:=x+DBGrid1.Columns.Items[i].Width*PointScale; end; if not (y=PointY*TopBlank) then (DataSource1.DataSet).next; x:=PointX*LeftBlank; y:=y+PrintStep; //换页 if (y+PrintStep)〉(Printer.PageHeight-PointY*BottomBlank) then begin Printer.NewPage; y:=PointY*TopBlank; end; end; printer.EndDoc; (DataSource1.DataSet).First; Application.MessageBox(′打印完成′,′打印′,32); end; end; 今天开始研究 FastReport。 以下是动态创建 FASTREPORT 的 DEMO var Page: TfrxReportPage; Band: TfrxBand; DataBand: TfrxMasterData; Memo: TfrxMemoView; begin { clear a report } frxReport1.Clear; { add a dataset to the list of ones accessible for a report } frxReport1.DataSets.Add(frxDBDataSet1); { add a page } Page := TfrxReportPage.Create(frxReport1);

{ create a unique name } Page.CreateUniqueName; { set sizes of fields, paper and orientation by default } Page.SetDefaults; { modify paper's orientation } Page.Orientation := poLandscape; { add a report title band} Band := TfrxReportTitle.Create(Page); Band.CreateUniqueName; { it is sufficient to set the &laquo;Top&raquo; coordinate and height for a band } { both coordinates are in pixels } Band.Top := 0; Band.Height := 20; { add an object to the report title band } Memo := TfrxMemoView.Create(Band); Memo.CreateUniqueName; Memo.Text := 'Hello FastReport!'; Memo.Height := 20; { this object will be stretched according to band's width } Memo.Align := baWidth; { add the masterdata band } DataBand := TfrxMasterData.Create(Page);

DataBand.CreateUniqueName; DataBand.DataSet := frxDBDataSet1; { the Top coordinate should be greater than the previously added band's top + height} DataBand.Top := 100; DataBand.Height := 20; { add an object on master data } Memo := TfrxMemoView.Create(DataBand); Memo.CreateUniqueName; { connect to data } Memo.DataSet := frxDBDataSet1; Memo.DataField := 'xm'; Memo.SetBounds(0, 0, 100, 20); { adjust the text to the right object's margin } Memo.HAlign := haRight; { show the report } frxReport1.ShowReport; FastReport 问题整理 http://blog.163.com/ex_plus/blog/static/1795953220090811151264/ FastReport 程序员手册 http://www.evget.com/zh-CN/Info/ReadInfo.aspx?id=9451

通用打印模块。 在系统中经常需要用到对已经得到的数据集,进行打印。为此特意制作了该单元

{hl created 20090423 提供通用打印功能

} unit DfReportFrm;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, frxDesgn, frxClass, Db, frxDBSet, dbClient, frxVariables;

type TPrintType = (ptPrint, ptPreview, ptDesign, ptAllDesign);

TDfReportForm = class(TForm) frxReport: TfrxReport; frxDesigner: TfrxDesigner; private { Private declarations } frxDBDataset: TfrxDBDataset; ClientDataSet: TCustomClientDataSet;

frxVariable: TfrxVariable;

public { Public declarations } //向报表中增加数据集 procedure AddDataSet(ADataSetArray: array of TDataSet; AData: Variant; AServerDate: TDateTime); end;

procedure _DfPrintReport(ADataSetArray: array of TDataSet; APrintType: TPrintType; AData: Variant; ATemplateFileName: string = ''; AServerDate: TDateTime = 0); overload;

procedure _DfPrintReport(ADataSetArray: array of TDataSet; APrintType: TPrintType; AData: Variant; ATemplateStream: TStream; AServerDate: TDateTime = 0); overload;

implementation

{$R *.dfm}

procedure _DfPrintReport(ADataSetArray: array of TDataSet; APrintType: TPrintType;

AData: Variant; ATemplateFileName: string = ''; AServerDate: TDateTime = 0); var DfReportForm: TDfReportForm; begin DfReportForm := TDfReportForm.Create(Application); try with DfReportForm.frxReport do begin Clear; //装载数据 DfReportForm.AddDataSet(ADataSetArray, AData, AServerDate); if FileExists(ATemplateFileName) then LoadFromFile(ATemplateFileName); // ReportOptions.Name := ARptName;

//显示 case APrintType of ptPrint: begin //打印 if PrepareReport() then Print; end;

ptPreview: //预览 ShowReport;

ptDesign, ptAllDesign: begin //设计 FileName := ATemplateFileName; DesignReport; if Modified then begin SaveToFile(ATemplateFileName); end; end; end; end;

finally FreeAndNil(DfReportForm); end;

end;

procedure _DfPrintReport(ADataSetArray: array of TDataSet; APrintType: TPrintType; AData: Variant; ATemplateStream: TStream; AServerDate: TDateTime = 0);

var DfReportForm: TDfReportForm; begin DfReportForm := TDfReportForm.Create(Application); try with DfReportForm.frxReport do begin Clear; //装载数据 DfReportForm.AddDataSet(ADataSetArray, AData, AServerDate);

ATemplateStream.Position := 0; if ATemplateStream.Size > 0 then LoadFromStream(ATemplateStream); // FileName := ARptName; // ReportOptions.Name := ARptName; //显示 case APrintType of ptPrint: begin //打印 if PrepareReport() then Print; end;

ptPreview: //预览 ShowReport;

ptDesign, ptAllDesign: begin //设计 DesignReport; if Modified then begin ATemplateStream.Position := 0; SaveToStream(ATemplateStream); end; end; end; end;

finally FreeAndNil(DfReportForm); end; end; { TDfReportForm }

procedure TDfReportForm.AddDataSet(ADataSetArray: array of TDataSet;

AData: Variant; AServerDate: TDateTime); var i: Integer; intTmp: Integer; begin frxReport.DataSets.Clear; for i := 0 to Length(ADataSetArray) - 1 do begin frxDBDataset := TfrxDBDataset.Create(Self); frxDBDataset.Name := ADataSetArray[i].Name; frxDBDataset.DataSet := ADataSetArray[i];

frxReport.DataSets.Add(frxDBDataset); end; //传入自定义数据 if AData <> null then begin ClientDataSet := TCustomClientDataSet.Create(Self); ClientDataSet.Data := AData; frxDBDataset := TfrxDBDataset.Create(Self); frxDBDataset.Name := 'SelfDefineData'; frxDBDataset.DataSet := ClientDataSet;

frxReport.DataSets.Add(frxDBDataset); end; intTmp := frxReport.Variables.IndexOf('ServerDate');

if intTmp < 0 then begin frxVariable := frxReport.Variables.Add; frxVariable.Name := 'ServerDate'; end else frxVariable := frxReport.Variables.Items[intTmp];

frxVariable.Value := AServerDate; end;

end.

使用方法: _DfPrintReport([HlAdoClientDataSet1], ptDesign, HlAdoClientDataSet1.Data, 'd:\test.fr3', Now); FASTREPORT 中自定义函数的使用 今天看到同事在写一个 REPORT,竟然可以将程序中的函数传递给 FASTREPORT 写程序的时 候使用,感觉很奇怪,研究一下,其实很简单,不过功能很强大。 主要增加一个 UNIT,就可以在这个单元中增加自定义函数了。

(*********************************************************************** Fastreport 报表附加函数单元 LWD, 2009/03/19 ************************************************************************) unit lxbl_RptAddinFunc; interface uses fs_iinterpreter; type TRptAddinFuncLib = class(TfsRTTIModule) protected function CallMethod(Instance: TObject; ClassType: TClass; const MethodName: String; var Params: Variant): Variant; function SetFwrxx(fwrxm1:string;fwrxm2:string;fwrdw:string):string; function SetFwrxmdw(fwrxm1,fwrxm2,fwrdw1,fwrdw2:string):string; public constructor Create(AScript: TfsScript); override; end; implementation //uses lxbl_SysUtil; const FUNCLIB_CAT = '离线笔录附加函数'; { TRptAddinFuncLib }

function TRptAddinFuncLib.CallMethod(Instance: TObject; ClassType: TClass; const MethodName: String; var Params: Variant): Variant; begin if MethodName = 'GETSYSDMVALUE' then begin // Result := TLxblSysUtil.GetSysDmValue(Params[0], Params[1]); end else if MethodName = 'SETFWRXX' then begin Result := setFwrxx(Params[0], Params[1], Params[2]); end else if MethodName = 'SETFWRXMDW' then begin Result := SetFwrxmdw(Params[0], Params[1], Params[2], Params[3]); end else if MethodName = 'FORMATDATESTR' then begin // Result := TLxblSysUtil.FormatDateStr(Params[0],Params[1],Params[2]); end; end; function TRptAddinFuncLib.SetFwrxx(fwrxm1: string; fwrxm2: string; fwrdw: string):string; var tmpFwrxx:string;

begin if fwrxm1<>'' then tmpFwrxx := fwrxm1; if fwrxm2<>'' then tmpFwrxx := tmpFwrxx + '、' + fwrxm2; if fwrdw<>'' then tmpFwrxx := tmpFwrxx + ',' + fwrdw; result := tmpFwrxx; end; function TRptAddinFuncLib.SetFwrxmdw(fwrxm1,fwrxm2,fwrdw1,fwrdw2: string):string; var tmpFwrxmdw:string; begin if(fwrdw1=fwrdw2)then begin if fwrxm1<>'' then tmpFwrxmdw := fwrxm1; if fwrxm2<>'' then tmpFwrxmdw := tmpFwrxmdw + '、' + fwrxm2; if fwrdw1<>'' then tmpFwrxmdw := tmpFwrxmdw + ',' + fwrdw1; end else

begin if fwrxm1<>'' then begin tmpFwrxmdw := fwrxm1; if fwrdw1<>'' then tmpFwrxmdw := tmpFwrxmdw + ',' + fwrdw1; end; if fwrxm2<>'' then begin tmpFwrxmdw := tmpFwrxmdw + ';' + fwrxm2; if fwrdw2<>'' then tmpFwrxmdw := tmpFwrxmdw + ',' + fwrdw2; end; end; result := tmpFwrxmdw; end; constructor TRptAddinFuncLib.Create(AScript: TfsScript); begin inherited Create(AScript); with AScript do begin AddMethod('function GetSysDmValue(flagtype: string; lagid: string):string',

CallMethod, FUNCLIB_CAT, '根据代码返回相应的值'); AddMethod('function SetFwrxx(fwrxm1: string; fwrxm2: string; fwrdw: string):string', CallMethod, FUNCLIB_CAT, '设置发问人信息'); AddMethod('function SetFwrxmdw(fwrxm1,fwrxm2,fwrdw1,fwrdw2:string):string', CallMethod, FUNCLIB_CAT, '设置发问人姓名单位'); AddMethod('function FormatDateStr(dateStr: string; oldFmt: string; newFmt: string):string', CallMethod, FUNCLIB_CAT, '转换日期格式'); end; end; initialization fsRTTIModules.Add(TRptAddinFuncLib); end.


赞助商链接