FastReport報表控制元件使用技巧總結

鳥棲沙岩發表於2016-05-26

1.FastReport中如何訪問報表中的物件?

可以使用FindObject方法。

TfrxMemoView(frxReport1.FindObject('memo1')).Text:='FastReport';

2.FastReport中如何使用上下標?

設定frxmemoview.AllowHTMLTags:= True;在Text輸入如下

上標:mm2

下表:k6

舉一反三,你還可以使用其他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.

相關連結

FastReport中文官網

FastReport最新版下載

相關文章