FastReport的基本思想来源于Windows版的“1S-Bookkeeping”6.0,因此报表的基本元素是包含多行文本的矩形。
与大多数报表生成器不同,它们的报表页面内容保存在图元文件(EMF格式的图像),在FastReport中准备好的报表是一组对象的集合,描述报表处理后各页面所包含的内容。
FR,与其它报表生成器一样,使用bands逻辑组织报表数据。
Bands分成两类:data-bands(主数据,从数据,等等)和其它(报表标题,页头,等等)。
Data-bands出现在报表的多行部分,例如Ttable的记录行。
考虑最简单的情况。
TfrPage是一个逻辑页,拥有多个Bands,以及其它对象。
TfrPage = class(TObject)
Bands: Array[TfrBandType] of TfrBand;
说明一个Page的同一种类型的Band链接起来
procedure TfrPage.InitReport;
for b := btReportTitle to btNone do
Bands[b] := TfrBand.Create(b, Self);
TossObjects;
两种方式组织对象。
设计时将所有对象依次置于Objects列表中
build时将band类型对象填入Bands列表,同类型的band依次链接。
其它对象按其位置加入到相应band。
procedure TfrPage.TossObjects;
TossObjects设计时的Band对象转换为build时的Band对象。
设置对象的parent为相应的band,将对象加入相应的band的对象列表。
//将对象置于相应的Band,
//注意ColumnXXX objects同时属于两个个带,水平方向 ,垂直方向
//一个page中所有同一类型的band链起来
//band按坐标排序
//connect header & footer to each data-band
参看Group的例子
Group Header
Data
Group Footer
//解析器,数据结构中的表达式求值。p45 3.2
//考虑两个栈,一个操作码,一个操作数
//解析完一条语句。执行。
//全局变量,局部变量
一个栈
stack操作码
res操作数
最后形成一个逆boland表达式如:3 2 4 + *
设计时的TfrPages的object根据情况被添加到相应的Band中。
跟踪Runtime例子
ShowReport
PrepareReport
DoPrepareReport
BuildBeforeModal
DoBuildReport
FormPage
DoLoop// if not b.DataSet.Eof and b.NewPageAfter then NewPage
AddToStack
ShowStack
TfrPage.ShowBand
TfrBand.Draw
DoCalcHeight
DoDraw
DrawObjects
DrawObject
TfrView.Print//Object均由TfrView派生Print到Stream
ExpandVariables //由数据库得到数据值
TfrView.SaveToStream
DrawCross
frParser.Calc(b1.GroupCondition) <> b1.LastGroupValue
b.DataSet.Next;
btCrossData TfrBand.DoAggregate
Parent.DoAggregate([btPageFooter, btMasterFooter, btDetailFooter,
btSubDetailFooter, btGroupFooter, btCrossFooter, btReportSummary]);
为何使用Stack
如果存在多重分组,最小的分组最先处理
DoLoop!!!处理数据
要处理的band进栈,最后ShowBand出栈
if not b.DataSet.Eof then
begin
if (Level = 1) and HasGroups then
InitGroups(Bands[btGroupHeader]);
if b.HeaderBand <> nil then
AddToStack(b.HeaderBand);
if b.FooterBand <> nil then
b.FooterBand.InitValues;
while not b.DataSet.Eof do
begin
Application.ProcessMessages;
if MasterReport.Terminated then break;
AddToStack(b);
WasPrinted := True;
if Level < MaxLevel then
begin
DoLoop(Level + 1);
if BndStackTop > 0 then
if b.PrintIfSubsetEmpty then
ShowStack
else
begin
Dec(BndStackTop);
WasPrinted := False;
end;
end
else ShowStack;
b.DataSet.Next;
每处理一条会调用
TfrDataSet.Eof
FOnCheckEOF
DetailDatasetCheckEOF计算是否完成了一个DetailDataset
frParser.Calc(b1.GroupCondition)计算分组!!
Band->EmFPages
FastReport有22个Bands
名 称 何 时 何 地
报表标题 打印在打印报表之初
报表合计 打印在报表结束时
页头 打印在每页项部
页脚 打印在每页底部
主项头 打印在第一个数据层开始
主项数据 第一层数据——重复每个主项数据记录
主项脚 打印在第一个数据层结束
细项头 打印在第二个数据开始
细项数据 第二层数据——重复每个细项数据记录
细项脚 打印在第二个数据层结束
子细项头 打印在第三层数据开始
子细项数据 第三层数据——重复每个子细项数据记录
子细项脚 打印在第三个数据层结束
覆盖 打印在每页的最底层(用于打印水印)
栏目头 打印在栏目开始
栏目脚 打印在栏目结束
分组头 组标题打印在分组开始
分组脚 打印在分组后
交叉表头
交叉表数据
交叉表脚 这组区域用于创建交叉表,报表上可变栏目。
子 这个区域能被追加到其它任何类型的区域(交叉表和页脚除外)。子区域显示在父区域之后。
在正统的方案中(在细节,在ReportBuilder中)只有一个细节数据区。
FastReport中的方案,你不需要sub-report。在这个表中你可以看到,
你可以在一个报表中使用三层数据(bands:主项数据,细项数据和子细项数据)。
TfrDesignerPage由Panel继承
报表中的对象由TfrView继承
Fr_View.pas的实现比较简单,
TfrPreview直接继承自Tpanel,内含了一个TfrPreviewForm,预览窗体。
在窗体中,有一个关键的控件,PBox: TfrPBox,他继承自Tpanel,
在他的Paint()中,实现了报表画在屏幕上的效果。
TfrPreviewForm
RedrawAll
TfrEMFPages(EMFPages).Draw
在FR_View的绘制函数中,不只一次的调用了TfrEMFPages.Draw(),
而在这个Draw()函数里,分别调用了各个TfrView子类的Draw()函数以达到绘制画布的目的。
同样,在TfrDesignerPage.Mup()中,调用了TfrDesignerPage.DrawPage(),
在DrawPage()中,调用了各个TfrView子类的Draw()。
TfrReport(Doc).EMFPages := TfrEMFPages.Create(Doc);
TfrReport(Doc) Doc是一个TfrReport
PfrPageInfo
TfrEMFPages与TfrPage有何区别与联系?
TfrEMFPages = class(TObject)//主要关注PfrPageInfo,物理页面?
TfrPage = class(TObject)//主要关注与Bands,逻辑页面?
Bands: Array[TfrBandType] of TfrBand;
Objects,RTObjects
TfrEMFPages.ObjectsToPage(Index: Integer);
将2者联系起来
procedure TfrPage.InitReport;
中TfrPage.TossObjects
由Objects创建RtObjects
由RtObject处理脚本
// placing objects over band
// connect header & footer to each data-band
DoBuildReport
TfrPage.FormPage形成页
L4734,L4752:NewPage
L4240:
NewPageAfter := (Flags and flBandNewPageAfter) <> 0;
PageBreak := (Flags and flBandPageBreak) <> 0;
PrepareReport and ShowReport methods starts report building
(ShowReport method runs preview after preparing).
TfrBand
This is build-time version of TfrBandView object. In design-time bands are represents by TfrBandView objects. Before building report, all TfrBandView objects are copyed to the TfrBand objects. TfrBand object contains list of child visual objects (Objects property) and dataset attached to it (DataSet property - only for data-bands).
!!!TfrReport.DoBuildReport;!!!
如何计算分页数目
TfrPage.ShowBand
TfrBand.Draw
////////////////////////
fr4
frxClass,frxEngine核心
frxEngine.ShowBand
DoShow
TfrxEngine.RunPage与3以前的FormPage相对应 未采用Stack而采用List
////////////////////////////////
ReportMachine
RM_Class
procedure TRMReportPage.PlaceObjects;
RM_Grid
TRMGridEx//支持split 融合
设计非拖动,而是表格模式