- 註冊時間
 - 2006-3-13 
 - 最後登錄
 - 2025-7-23 
 - 在線時間
 - 675 小時 
 - 閱讀權限
 - 200 
 - 積分
 - 417 
 - 帖子
 - 1109 
 - 精華
 - 0 
 - UID
 - 2 
  
 
 
 
    
 | 
 
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 都有。 |   
 
  
 |