FastReport報表控件使用技巧總結
1.FastReport中如何訪問報表中的對象?
可以使用FindObject方法。
TfrxMemoView(frxReport1.FindObject('memo1')).Text:='FastReport';
2.FastReport中如何使用上下標?
設置frxmemoview.AllowHTMLTags:= True;在Text輸入如下
上標:mm<sup>2</sup>
下表:k<sub>6</sub>
舉一反三,你還可以使用其他HTML標記。
3.FastReport中如何打印總頁數?
設置兩次報表后加入引號內內容 "第[Page#]頁共[TotalPages#]頁"
4.FastReport中如何動態加入變量及變量組?
建立變量組名
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,初始值)
5.FastReport中如何加入自定義函數?
Fastreport可以自己加入需要的函數,來實現特定的功能。過程就是:
1)添加函數到報表中。
frxreport1.AddFunction('完整的函數聲明');
如有一個自定義函數,為GetName(Old:String):String;這個函數通過數據集的一個字段,得到另一個返回值。
則語句為:frxreport1.AddFunction('Function GetName(Old:String):String;');
2)腳本中使用函數。
在腳本中或報表中使用自定義函數,就像使用其它Fastreport內置函數一樣。
3)程序中處理函數。
使用函數是通過frxreport1的OnUserFunction函數來實現的。
OnUserFunction的聲明如下:Function(constMethodName: String;var Params: Variant): Variant;
比如上面的函數,首先要有一個函數,這個函數是GetName的實現部分。如有一個在程序中實現的函數。
function RealGetName(Old:String):String;這個函數名是無所謂的,也可以是GetName。
在OnUserFunction的事件處理中有如下代碼即可完成自定義函數在報表中的使用。
if CompareText(MethodName,'GetName')=0 thenResult:=RealGetName(VarToStr(Params[0]));
我一般都是使用CompareText來比較函數名,因為我發現二個版本的Fastreport,一個是MethodName全部自動變成了小寫,一個是全部自動變成了大寫,所以干脆用CompareText來比較,肯定不會出錯。
如果有多個參數,則依次傳遞Params[0],Params[1]即可,要保持順序一致。
這里要注意一點,如果參數為指針,則不能直接使用Pointer(Integer(Params[0]))。因為實際傳遞過來的是指針的整數值,可以使用Pointer(StrToInt(VarToStr(Params[0])))。
6.FastReport中如何共用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一樣使用共用的報表組件了
7.FastReport中如何使用腳本,腳本中使用變量?
很多時候,我們希望把對報表的控制放到報表的腳本中,通常我這樣做有二個原因:
1)能夠根據字段內容的變化而使用不同的設置,因為如果想在程序中實現這樣功能,就不得不用自定義函數,函數的實現要放到程序中,函數可能需要傳遞很多參數,效率低下。
2)把不同報表的控制放到腳本中,可以實現報表的模塊化,程序只是簡單的設置數據集的關系,並加載硬盤上的報表文件,不同報表的不同實現方式,顯示方式,均放到報表文件中,程序簡潔
,易維護,易升級。
當然,這樣的缺點就是程序中加載報表時的數據集別名必須與設計報表時的別名一致。
腳本的使用與通常程序的使用並沒有太多的區別,就是像正常的程序那樣引用控件的名稱即可。
但注意對變量的使用,需要把變量名或表達式用<>括起來。
實現打印分組的頁數。基本的原理就是:
1)必須使用二遍報表,因為FS算總頁數就是需要二遍報表的。
2)在第一遍報表中,在GroupBand打印前,動態的建立整數型數組變量,用以保存上一個分組的總頁數。
3)在最后一遍報表時,需要顯示分組頁數的Tfrxmemoview取得數組中的數據,但最后一個分組不會有總數,可以通過總頁數減去GroupBand事件中保存的頁數來取得。
4)代碼中處理了一頁多組,及一組多頁打印分組頭的情況。可以看到這些特殊處理的代碼說明。
5)我特意在分組尾及頁腳都用了Tfrxmemoview來顯示這些數據,說明在不同情況下的顯示。
8.FastReport中如何在腳本中根據字段名改變Tfrxmemoview的內容?
假設有數據表“用戶”,字段ID為用戶標識,Name為用戶名,打印時要求,如果用戶名為空,則打印“無用戶名”,否則打印出“用戶名:實際的用戶”,則可以在ID的Tfrxmemoview控件的
OnAfterData事件中寫如下腳本。
if<frxDBDataSet1."Name">='' then
Memo2.Text:='無用戶名'
else
Memo2.Text:='用戶名:[frxDBDataSet1."Name"]'
Memo2是放置用戶名稱數據的Tfrxmemoview控件。
這里注意,要在腳本中訪問變量需要把變量用<>包括起來。
9.FastReport中如何動態調整高度?
我經常使用下面的幾個函數來實現Band及Tfrxmemoview高度的動態調整,需要注意的是:下面的函數只能調整一個Band中多行的最后一行,如果只有一行(多數情況下應該是這樣)就無所謂了
,而且這是在寬度已經固定的前提下。在想要調整高度的Band的OnBeforePrint事件中寫SetMemo(Sender);,代碼如下,粘貼到代碼頁中就可以使用。
下面的代碼也可以演變一些,實現動態寬度等。我多處都判斷了Tag是否為7635,因為我經常需要單獨調用其中的某個函數。
//7635為保留數字,表示不作任何調整,通常用在多行的最上方
function Biger(Old:Extended):Integer; begin Result:=Trunc(Old);
if Frac(Old)>0 then Result:=Result+1; end; procedure JustHeight(Sender:TfrxComponent); var RealHeight:Integer; begin
RealHeight:=Biger(TFrxMemoView(Sender).CalcHeight+TFrxMemoView(Sender).Top);
ifBiger(TfrxBand(Sender.Parent).Height)<RealHeight then begin
//若MEMO的高度小於BAND但計算高度大於BAND,則在調整BAND的函數中就會被調整
TfrxBand(Sender.Parent).Height:=Biger(RealHeight);
JustBandHeight(Sender.Parent); end else
TfrxMemoView(Sender).Height:=TfrxBand(Sender.Parent).Height
-TfrxMemoView(Sender).Top; end;
procedureJustBandHeight(Sender:TfrxComponent); var I:Integer;
begin for I:=0 to Sender.Objects.Count-1 do if TObject(Sender.Objects.Items[I]) isTFrxMemoView then
ifTFrxMemoView(Sender.Objects.Items[I]).Tag=7635 then Continue else
//如果小才改變,如果大則不能改變 ifBiger(TfrxMemoView(Sender.Objects.Items[I]).Height+
TfrxMemoView(Sender.Objects.Items[I]).Top)<>Biger(TfrxBand(Sender).Height)then
TfrxMemoView(Sender.Objects.Items[I]).Height:=
Biger(TfrxBand(Sender).Height-TfrxMemoView(Sender.Objects.Items[I]).Top);
end; procedure JustMemo(Sender:TfrxComponent); begin if not Engine.FinalPass then Exit; if Sender.Tag<>7635 then
JustHeight(Sender); end; procedure SetMemo(Sender:TfrxComponent);
var I:Integer; begin for I:=0 to Sender.Objects.Count-1 do
if TObject(Sender.Objects.Items[I]) isTFrxMemoView then
ifTfrxMemoView(Sender.Objects.Items[I]).Tag<>7635 then
TfrxMemoView(Sender.Objects.Items[I]).OnAfterData:='JustMemo'; end;
10.FastReport中如何實現套打?
紙張是連續的帶鋸齒的已經印刷好的,類似於通信公司發票這里設計的是客戶銷售記錄。
客戶有兩個要求:
1、因為打印紙張是印刷的,明細記錄只有8行,所以,如果明細記錄如果不到8行,就將公司名稱、銷售記錄打印在上面,下一個公司的信息打印在下一頁,而不能接在該頁上(呵呵,是啊,如
果接在一起,那印刷單就失去意義了)
2、如果銷售記錄超過8行,則從第9行開始的銷售記錄打印在下一頁(所謂下一頁,其實就是鋸齒分割的下一*,稱呼“下一份”比較妥切?),並且抬頭(也就是公司名稱)也要打上(如果不打印抬頭,撕下了后,可能弄混淆了,不知道這一頁是哪個公司的)
問題描述標准說法是不是應該叫“打印固定行”、“強制換頁”?
回答:每頁打印抬頭的問題,就是把包含公司名稱的Band每頁重復打印即可。屬性中有一個的。
勾選就行了。
至於固定行,實際上設計套打時,頁面大小都是固定的,每一行的高度也都是固定的,頁眉與頁腳也是固定的,這樣設計出來的報表可打印的行數自然就是你要求的 8行了。根本不需要什么強
制換頁。因為根據紙張會自動換頁的。你要做的就是設計好紙張盡寸、頁面布局,就得了,套打是一種最簡單的打印,不用想的太復雜。
11.FastReport中如何實現連續打印?
很多人認為Fr不能實現連續打印,以為只能通過自己寫函數調用打印函數來實現連續打印,實際上,Fr可以輕易的實現連續打印,同時,實現時又是非常簡單,你甚至可以在你的程序的打印設
置中簡單的讓客戶選擇是否連續打印,其它都可以保持不變。
function PelsTomm(Pels:Extended):Extended; begin
Result:=Pels/Screen.PixelsPerInch*25.4; end;
procedurePrintSerial(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) thenBreak;
R:=Pelstomm(Frx.Engine.TotalPages*Frx.Engine.PageHeight-
Frx.Engine.FreeSpace)+R1; P:=TfrxReportPage(Frx.Pages[SequencePage]);
P.PaperHeight:=R; end;
{必須用上面的循環代碼來得到准確的空白區域不能用通過計算總頁數減去各頁的頁邊距的方法來獲得空白區域因為如果碰到一條記錄過寬的情況導致換頁,就不准確了。}
R:=Pelstomm(Frx.Engine.TotalPages*Frx.Engine.PageHeight-
Frx.Engine.FreeSpace)+R1; P:=TfrxReportPage(Frx.Pages[SequencePage]);
P.PaperHeight:=R; end;
在預覽或打印前先調用PrintSerial即可。
12.如何在程序中指定打印機名稱?
frxReport1.Report.PrintOptions.Printer := '打印機名稱';
13.如何使用打印機直接打印?
implementation uses Printers; {$R *.dfm} procedure TForm1.Button1Click(Sender:TObject); begin Printer.PrinterIndex := 0;{網絡打印機也是要安裝在你本地的操作系統中的,直接使用順序 試試吧}
Printers.Printer.SetPrinter('HP1020','HP1020','LPT1',0);{打印機名字,驅動,端口等,
自查,我是用虛擬打印機測試的} Printers.Printer.BeginDoc;
Printers.Printer.Canvas.TextOut(10,10,'打印這一行字');
Printers.Printer.EndDoc; end;
14.如何打印空白處?
在打印報表的Band處的OnBeforePrint事件中添加代碼:
while FreeSpace > 20 do ShowBand(Child1)
15.如何打印指定行數后換頁?
在master band中OnBeforePrint事件中寫代碼:
var vLineCount: integer; begin vLineCount := vLineCount + 1;
if vLineCount = 10 then begin vLineCount := 0; NewPage; end;
end;
16.fastreport中如何把數據顯示為百分比
DisplayFormat屬性,其中的Kind你設置成fkNumeric,FormatStr [<frxDBDataset1."sjl">*100#n%2.2f]%”。
17.FastReport如何打印表格式的空行?
var PageLine: integer; //在現在頁列印到第幾行 PageMaxRow: integer=15; //設定每頁列數
procedure MasterData1OnBeforePrint(Sender:TfrxComponent); begin
PageLine := <Line> mod PageMaxRow; if(PageLine = 1) and (<line> > 1) then Engine.newpage; child1.visible := False;
end; //Footer1高度設為0 procedure Footer1OnBeforePrint(Sender:TfrxComponent); var i:integer; begin
i:= iif(PageLine=0, PageMaxRow, PageLine); child1.visible := True;
while i < PageMaxRow do begin i:= i + 1;
Engine.ShowBand(Child1); //印空白表格 end; child1.visible := False;
end; begin end.