qucikReport 源代码剖析
按设计期与外部运行Exe单元分类:
外部运行Exe:
qrdatasu 报表数据源设置Dialog
qrdatawz 从报表数据源中选择字段Dialog
qreditor 报表设计器 Dialog,用于外部使用,和qrdatasu,qrdatawz 都有关联
qrexpred 表达式显示格式Dialog
QRLABLWZ - MAILING LABEL SETUP DIALOG
qrmdsu 主从表设置Dialog
qrwizard 新报表的wizard Dialog
设计期与独立Exe公用单元:
qrcomped 设计期报表属性设置Dialog
qrabout about Dialog
qrenved 用户自定义函数Dialog
qrexpbld 表达式设置Wizard Dialog
qrprev 打印预览Dialog
qrprgres 打印进度条Dialog
qrprnsu 打印机设置Dialog
qrLablEd 增强型qrlabel的属性编辑器 Dialog
比较重要的类:
qrexpr 表达式计算
qr3const 定义了一些提示常量,打印纸张列表常量。
qrexport 把报表输出到各种文件,如ascii,csv,xls,html,rtf,text,wmf
qrctrls 设计期控件
重要的类:
qrprntr 打印预览基础类,是一个重要的单元 打印控制时重要.
quickrpt Quickrpt组件源码 设计期重要
未知:
qrextra 附加类,作用未明
TQrPrinterSettings 设置打印属性
TQrStandardPreViewInterface 建立预览窗口
TQrPreviewImage 打印和预览的图象
TQrPreView 控制预览
这是三个很重要的类:
TQrStream 存图象的流
TQrPagelist 图象内存页的列表
TQrPrinter 控制打印
QuickRept在预览时做了些什么?给你段源码你就明白了。
procedure TCustomQuickRep.Preview;
begin
Application.ProcessMessages;
if PrepareQRPrinter and not QRPrinter.ShowingPreview then
begin
QRPrinter.Destination := qrdMetafile;
QRPrinter.Master := Self;
QRPrinter.OnPrintSetup := PrinterSetup;
QRPrinter.OnExportToFilter := ExportToFilter;
QRPrinter.Title := ReportTitle;
if assigned(FOnPreviewEvent) then
QRPrinter.OnPreview := FOnPreviewEvent;
QRPrinter.Preview;
CreateReport(false);
if Cancelled then
begin
QRPrinter.Free;
Exit;
end;
repeat
Application.HandleMessage
until (QRPrinter = nil) or (not QRPrinter.ShowingPreview) or Application.Terminated;
end;
end;
有人说程序压栈了,NO,是REPEAT了,你的退出方式符合QuickRep的条件吗?呵呵。。。
打印原理:
在内存中建立一个内存流,再每一个BAND做处理[其中细节还没有探明],把band信息存到内存流中[writebuffer]。在预览或打印时,建立一个TMetaFile文件,先写入EMFHEADER。把内存流的信息LoadFromStream到MetaFile文件中,在打印或预览时就进行文件的定位,读取[seek,read,write],然后就在打印机的纸上输出。输出时用Canvas.StreahDraw(Rect, MetaFile);走纸控制是按打印机设置走纸的。如果设置当前打印机不支持,则按默认首选项打印,可以动态用API改变默认打印首选项来控制走纸。
关于metaFile文件类型:
是一种可无级缩放的矢量图。在WINDOWS中有一种WMF文件就是此格式。矢量图可由WINDOWS控制缩放,打印。QUIEKREPORT就是利用了元文件的这个好处,不需自己管走纸,预览打印了。而国人王寒松写的EREPORT用的是DOS下常用的找位置用程序生画线textout的手法。metafile文件一旦建立,得到文件句柄,你就象面对一张白纸一样,往上用函数画你的东西吧。画完用打印机的CANVAS打印即可。ArcoBat Reader得PDF文件也是这个原理。
metafile文件可缩放的工作原理:
在文件中存放的其实是图象的相对位置,在具体的设备上显示时,才通过坐标映射关系转换为具体的坐标。
关于Delphi对MetaFile的编程,Graphics.pas就有TMetaFile的源码,我就不多费口舌了。
主要处理点:
如何把各BAND信息存到流里去。想改变Qr的打印速度和打印方式,需要从此下手。
对MetaFile文件格式的处理。在王寒松做的eReport中是纯粹用线画,用Textout,没有用MetaFile,用MetaFile速度会慢,但处理缩放很好,用线画,对打印速度会有提高,但无级缩放,达不到矢量图的效果。
打印是用Qrprinter打印的。但quickrep.print与quickrep.qrPrinter.print打印在源代码上不一样,还没有深研究。
qrprinter只在预览和打印中才产生,没有预览和打印,没有qrprinter.
quickrep几个最主要的事件:
afterpreview 只在关闭预览窗口才触发
afterprint 只在打印完最后一页才触发
beforeprint 在打印第一页时触发
OnEndPage 在一页末下一页开始前的间隔触发
OnNeedData
OnPreview 在预览前触发
OnStartPage 在每一页开始触发
bandtype
rbtitle 在第一页的头部
rbpageheader 在每一页的头部
rbDetail 记录区
rbPageFooter 在每页纸的尾部
rbsummary 在detail区和group footer区的下
rbcolumnheader 在每页纸的头部。
如何多张互不关联报表连打[节约纸张]?
答:用复合报表制作。在OnAddReports中把报表Reports.add(报表)
缺点:每一个报表的CloumnHeader,PageHeader只能在每张纸的头出现。
如果两张报表在一张纸上,第二个报表的CloumnHeander,PageHeader不出现。
如改为Title,就可出现,但在后续的纸的头部就不出现了。
或许在 TQuickRep.OnNeedData中可以办到,但没仔细想。
用报表生成器做连续打印的思想:
1 建立一个不定长数组,存放quickRep,ClientDataSet
把一个报表取下,把值添好,把它用流的技术复制一份[单纯赋值只是引用指针,因为我们
是用一个QuickRep恢复,所以下一张报表会把我们当前的报表冲掉,而流技术可以复制一份],
从流里边恢复控件必须把流里控件所涉及到的类都用RegisterClass注册一遍,否则从流中恢复时
Owner有可能不认识这个类[Form类和Components类会系统自动识别],无法利用RTTI信息建立控件和保存控件的运行期信息。然后就把数组中的报表增加到复合报表中连打,因为就一个cdsReportDataSet, 而报表连的都是
cdsReportDataSet,现在新建了一个cdsReportDataSet的副本,所以只能把报表上的控件的DataSet都换掉}
不要在其他地方给复合报表.Reports赋值,因为在复合报表内部处理时,它只认在OnAddReport中增加的报表,具体的内部细节是它有一个内部方法:CreateComposite,第一句就是Reports.Clear;在第5句就有一句:
if Assigned(OnAddReports) then OnAddReports(Sender);
Createcomposite在 Print,Preview,prepare都有。