ReportListener子类
Visual FoxPro主目录中的FFC(FoxPro基础类)子目录包含了_ReportListener.VCX文件,该文件包含了ReportListener的一些子类,而这些子类的功能比基类更多。这些子类中最有用的是_ReportListener。
_ReportListener最重要的特性之一是对继承(successors)的支持。当你运行报表的时候,你可以希望使用多个报表监听器。例如,如果你希望预览某个报表,同时输出为HTML,就会涉及到一个以上的报表监听器。_ReportListener通过提供Successor(它包含一个引用另一个监听器的对象)属性允许我们构建监听器链。
例如,假设ListenerA和ListenerB都是_ReportListener的子类,它们各自执行某些事务,并且你希望在某个报表上同时使用这两个监听器。下面是把这些监听器链接起来的代码:
loListener = createobject('ListenerA') loListener.Successor = createobject('ListenerB') report form MyReport object loListener | 报表引擎只与REPORT或LABEL命令中指定的监听器(称为lead listener,头监听器)通讯。当报表引擎引发报表事件的时候,头监听器调用它的后继者的适当方法,而后继者又调用自己的后继者的适当方法,这样一直沿着链进行下去。这种架构就是响应链,链中的任何监听器都可以决定执行某些操作或者把消息传递给链中的后继节点。
_ReportListener的另外一种有趣的能力是链接报表。AddReport方法把一个报表添加到定制的ReportFileNames集合中。你给这个方法传递报表名、可选参数还有将要使用的报表子句(例如RANGE子句)和另一个监听器对象的引用。RemoveReports方法从集合中删除所有的报表。RunReports运行报表;传递进去的第一个参数是.T.的时候将在报表运行后从集合中删除报表,第二个参数为.T.时将忽略AddReport指定的任何监听器。下面是一个示例,它运行了两个报表,但是表面看起来好像是一个报表:
loListener = newobject('_ReportListener', home() + 'ffc\_ReportListener.vcx') loListener.ListenerType = 1 loListener.AddReport('MyReport1.frx', 'nopageeject') loListener.AddReport('MyReport2.frx') loListener.RunReports() | HTML和XML输出
由于开发小组的设计目标之一是提供更多的报表输出类型,所以Visual FoxPro 9包含了_ReportListener的两个子类,叫做HTMLListener和XMLListener,分别用来来提供HTML和XML输出。这些监听器都内建在ReportOutput.APP中,但是在_ReportListener.VCX中也可以使用。 监听器类型5指定为HTML输出、4指定为XML输出,因此你可以使用下面的命令把输出指定为HTML:
| report form MyReport object type 5 | 但是如果这样操作你将无法控制将要建立的文件名和其它一些设置。作为替代,调用ReportOutput.APP可以让你得到需要的监听器引用、设置需要的属性、接着告诉REPORT命令使用该监听器。
下面的代码从MyReport报表中建立了一个叫做MyReport.HTML的HTML文件。当你指定为类型5时,ReportOutput.APP使用自己内建的HTMLListener类提供输出。
loListener = .NULL. do (_reportoutput) with 5, loListener loListener.TargetFileName = 'MyReport.html' loListener.QuietMode = .T. report form MyReport object loListener | 下面的代码从MyReport报表中建立MyReport.XML文件,只包含了数据。在这种情况下,代码片断使用了XMLListener类(类型4)。
loListener = .NULL. do (_reportoutput) with 4, loListener loListener.TargetFileName = 'MyReport.xml' loListener.QuietMode = .T. loListener.XMLMode = 0 && 0 = data only, 1 = layout only, 2 = both report form MyReport object loListener | HTML输出实际上使用XML监听器生成XML,接着使用XSLT来生成最终的HTML。
这两个监听器类都有一些附加的属性,你可以使用这些属性进一步控制输出。我推荐你查阅一下Visual FoxPro文档。此外,由于它们是_ReportListener的子类,所以监听器类支持_ReportListener类的能力,包括链接监听器和运行多个报表。下面是一个同时输出XML和HTML的示例:
use _samples + 'Northwind\Orders' loListener1 = .NULL. do (_reportoutput) with 4, loListener1 loListener1.TargetFileName = 'MyReport.xml' loListener1.QuietMode = .T. loListener1.XMLMode = 0 && 0 = data only, 1 = layout only, 2 = both loListener2 = .NULL. do (_reportoutput) with 5, loListener2 loListener2.TargetFileName = 'MyReport.html' loListener2.QuietMode = .T. loListener1.Successor = loListener2 report form MyReport object loListener1 | 建立自己的监听器
由于报表监听器是类,所以报表运行的时候,你可以建立子类来改变报表系统的行为。
例如,我一直希望在运行时动态地格式化字段。在某些条件下,我希望字段用红颜色打印,其它条件下用黑颜色打印。一个字段有时需要加粗而其它时候则不需要。
改变字段在报表中的显示样式的关键是EvaluateContents方法。这个方法在字段被显示之前调用每个字段对象,赋予监听器改变字段样式的权力。该方法的第一个参数是被处理的字段对象的FRX记录号,第二个参数是包含属性和字段对象信息的对象(请查看Visual FoxPro帮助文件中该对象包含的属性列表)。你可以修改任何属性来改变报表中字段的样式。如果你是这样做的,那么还需要把该对象的Reload属性设置为.T.,以通知报表引擎你已经改变了一个或多个属性。
列表1显示了定义_ReportListener的一个子类(叫做EffectsListener)的代码片断,该子类处理可能应用于报表中的字段的不同效果类型。这些效果通过效果处理对象来应用,而这些对象都存储在EffectsListener的oEffectsHandlers属性的集合中。每种效果处理对象处理一种效果。
在报表被处理的时候,监听器需要确定哪些字段应用了效果。它在EvaluateContents方法中查看每个将要显示的字段,实现这种功能。EvaluateContents调用SetupEffectsForObject,它调用每个效果处理程序的GetEffect方法来决定是否给该字段应用某种效果。GetEffect查看FRX中的字段记录的USER备注来指令应用哪种效果。如果该字段需要某种特定的处理程序,该处理程序就被添加到处理该字段的处理程序集合中(因为每个字段可能应用多个效果)。
这意味着在每条记录的每个字段上都会调用EvaluateContents,可是没有必要在一个特定字段上进行多次效果检查(这样做将导致报表性能下降)。因此,BeforeReport建立了一个数组,它存储了FRX中记录的行。如果该数组的第一列为默认值.F.,说明监听器还没有检测将要显示的字段的效果,因此EvaluateContents做出检测并把该数组的第一列设置为.T.,这样FRX就不会再次检测了。
在检测某个字段是否应用了效果后,EvaluateContents进入到该字段的效果处理程序集合中,调用每个程序的Execute方法执行必要的操作。
DynamicForeColorEffect就是一个效果处理程序。它用下面的格式查看报表中某个字段的USER备注:
*:EFFECTS FORECOLOR = expression (你可以从某个对象的属性对话框中的“其它”选项页中看到该对象的USER备注。) | 列表1中使用的TestDynamicFormatting报表的ORDERDATE字段的USER备注中有下面的代码片断指令;它告诉EffectsListener:DynamicForeColorEffect对象应该调整字段的颜色,当装运时间大于订单时间10天以上就用红颜色显示,否则就用黑颜色显示:
| *:EFFECTS FORECOLOR = iif(SHIPPEDDATE > ORDERDATE +10, rgb(255, 0, 0), rgb(0, 0, 0)) |
 图1:TestDynamicFormatting报表。列表1中的代码生成这个报表,它演示了对装运日期和装运形式列的动态格式化。 | DynamicForeColorEffect的Execute方法通过把传递到EvaluateContents中的字段属性对象的PenRed、PenGreen和PenBlue属性设置为适当的颜色,并把Reload设置为.T.(告诉报表引擎已经做了一些修改)来改变字段的颜色。
DynamicStyleEffect使用类似的指令来改变字体样式。此处使用的样式必须是一个数值:0是正常体、1是粗体、2是斜体、3是粗斜体。TestDynamicFormatting报表中的SHIPVIA字段的USER中有下面的指令,它引起SHIPVIA为3(因为该字段的表达式实际上显示为Mail)的字段显示为粗体,否则为正常体。
| *:EFFECTS STYLE = iif(SHIPVIA = 3, 1, 0) | DynamicStyleEffect的工作方式与DynamicForeColorEffect类似,只是改变了字段属性对象的Style属性。
运行TestDynamicFormatting.PRG将出现图1所示的输出结果。
|
|