VFP 学习、开发漫谈 (26)
这一期与大家聊一聊关于报表的话题。在前面的讲座中,我曾说过:除非用户有明确的要求,且报表格式固定,我才设计报表,否则一律导出至 Excel。下面,我就谈谈在报表设计方面的使用体会。一、关于报表引擎的版本
与 SQL 一样,VFP 9.0的报表引擎也有 80 和 90 两个版本,但是与 SQL 不同的是:系统默认的报表引擎版本是 80 而不是 90。我曾尝试通过 Set ReportBehavior 90 将报表引擎设为 90,结果在实际应用中带来一系列的问题。比如:当域控件来源于一个计算表达式时,如:TRIM(材料代码)+" "+TRIM(材料名称),则在预览或打印时域控件显示为空!出现这么严重的问题,看来 VFP 将默认报表引擎设为 80是有道理的。在我开发的应用程序中,仍然保留默认值,即:Set ReportBehavior 80。
二、关于报表的数据环境
我一般不在报表设计器中为报表指定专门的数据环境,通常情况下,在表单的命令按钮中调用“Report Form”命令来执行报表打印。这样,报表将使用表单的数据环境。例如,下面是表单中 cmdPrint.Click 中的一段代码:
程序代码:
* 将要打印的数据输出至临时表curPrint LOCAL nSelect nSelect = SELECT() SELECT 入库单号,制单日期,材料代码,材料描述,单位,数量,单价,金额,供应商,采购员,订单号 ; FROM Orders ; ORDER BY 入库单号 ; INTO CURSOR curPrint * 用自定义函数打印报表 = UdfPrint('Orders') * 恢复环境 USE IN curPrint SELECT (nSelect)
三、是否保存打印机环境
如果用户选择了保存打印机环境,则在打印报表时会使用打印环境中的打印机、纸张类型、纸张大小、纸张方向、份数等。一般情况下,选择不保存打印机环境,打印时系统会自动选择 Windows 默认打印机及其设置,更加灵活。
四、设计自己的报表打印函数 UdfPrint()
程序代码:
FUNCTION UdfPrint(tcReportName) && tcReportName(报表名称) * 获取总页数 LOCAL nEndPage REPORT FORM (tcReportName) NOCONSOLE nEndPage = _PageNo * 打印预览 DO FORM frmPrint NAME frmPrint REPORT FORM (tcReportName) NOCONSOLE RANGE 1,nEndPage PREVIEW WINDOW frmPrint TO PRINTER PROMPT frmPrint.Release ENDFUNC
下面,详细介绍一下 UdfPrint() 函数。
本函数实现的功能是:先显示最大化的打印预览窗口,单击预览窗口中的打印按钮时,弹出一个选项对话框,在其中可以选择打印机、打印份数和页码范围。
在打印之前,为什么要统计总页数呢?因为,若不为 Report Form 指定 Range 参数,则打印选项对话框中的页码范围是“1-65534”,不太友好。若报表有10页,则显示为“1-10”更好一些。因此,先统计总页码,然后在 Report Form 中添加 Range 1,nEndPage。
VFP 不是有一个 _PageTotal 系统变量吗?不统计总页数,而直接将报表打印命令中的 nEndPage 替换为 _PageTotal 可以吗?不可以。_PageTotal 可以在报表内部直接调用,但在报表外部调用则其不会自动更新为当前报表的总页数。其实,在报表内部调用 _PageTotal 时,系统也会自动执行一遍 Report Form。
另一个重要的问题是:为什么将打印预览窗口显示在表单 frmPrint 中呢?因为默认的打印预览窗口没有最大化,为了解决此问题,我专门设计了一个表单 frmPrint,使打印窗口继承该窗口的属性。其主要属性如下:
AlwaysOnTop = .t. && 显示在最上层,防止其他窗口遮挡
ShowWindow = 2 && 作为顶层表单,可脱离VFP主窗口,摆脱其影响
TitleBar = .f. && 不显示标题栏
WindowState = 2 && 窗口最大化
ShowInTaskbar = .f. && 作为顶层表单的打印窗口不显示在 Windows 任务栏上
打印前,先运行该表单,然后通过为 Report Form 命令添加 Window frmPrint 选项,使打印预览窗口显示在该表单窗口中。
下面需要解释的是:为什么在添加了 Preview 选项时还要添加 To Printer Prompt选项呢?这主要是为了添加 Prompt 参数,只有添加了 To Printer 选项后,才能在其后面添加 Prompt 参数,才能实现单击预览窗口中的打印按钮时,弹出打印选项对话框。不添加 To Printer Pompt 选项时,单击预览窗口中的打印按钮,则不弹出选项窗口直接打印输出。另外,需要说明的是:当 Preview 和 To Printer 共存时,Preview 优先。
另外需要说明的是:在默认报表引擎(80)下,Range 参数对打印预览是无效的,Range 参数仅设置打印对话框中页码范围的默认值。但在 90 报表引擎下,Range 参数对打印预览有效,但对打印对话框中的页码范围无效,仍显示“1-65534”。
在我的自定义函数中,为了使打印窗口最大化,采用的方法是将打印窗口显示在一个最大化的表单窗口中。也可以不使用表单窗口也能使打印预览窗口最大化,如下所示:
KEYBOARD "{ALT+F10}"
REPORT FORM (tcReportName) NOCONSOLE RANGE 1,nEndPage TO PRINTER PROMPT PREVIEW
将打印预览窗口最大化也有副作用。比如:非最大化的打印预览窗口带有标题栏,其中显示当前预览的是第几页,而将预览窗口最大化后,将失去标题栏,因而无法显示当前预览的页码,并且窗口一旦最大化,我还没有找到还原窗口的方法。我们都知道:在多文档窗口下,按下“Alt+空格”弹出应用程序窗口菜单,按下“Alt+减号”弹出文档窗口菜单。但不知道是什么原因,在最大化的预览窗口中,按下“Alt+减号”时则系统崩溃。在这种情况下,通过单击工具栏上的“转到”按钮可间接了解当前页码。
五、关于 ??? 命令
VFP 有一条直接将表达式输出至打印机的命令 ???,如:要打印输出变量 cValue的值,可输入:??? cValue。该命令不经过打印机驱动程序的转换,直接将内容输出至打印机。如果 cValue 包含中文,你可以发现,字符串中的中文打印为乱码。但在一些带中文硬字库的打印机(如:LQ-1600K)可正常输出。对于常用的激光打印机和喷墨打印机来说,都不带中文硬字库,所以该命令在实际应用中很少用到。
六、关于 ?/?? 命令
如果用户想把某个字段、变量或表单控件的值输出至打印机,则最简单的方法是使用 ? 或 ?? 命令,前者是换行输出,后者是不换行输出。以打印表单上的编辑框 edtNotes 中的内容为例,代码如下:
程序代码:
SET PRINT ON SET CONSOLE OFF ? THISFORM.edtNotes.Value SET PRINT OFF SET PRINT TO
其中:第二条语句的作用是:内容仅输出至打印机,不显示在当前表单或主窗口中。最后一条语句 SET PRINT TO 也十分重要。若没有该语句,则系统并不会立即打印,而是当退出 VFP 时才打印,而添加了该语句后,系统则立即打印输出。
七、不打印空行/溢出时扩展行
有一个考试成绩表 Test.dbf,如下所示:
从表内容来看,我们在打印报表时,需要解决两个问题:第一个问题是,如何实现不打印表中的空白记录(第 3 条记录);第二个问题是,由于家长信息内容较多,而报表宽度有限,在打印内容超过控件的设计宽度时,如何使报表自动扩展高度将字段内容打印完整。
对于第一个问题,有两种解决思路,一种是通过 SQL 命令或为表设置过滤条件,在数据环境中将空记录过滤掉。另一种方法是,在报表打印时不打印空记录。本文采用的是第二种方法。
对于第二个问题,通过设置域控件的“Stretch with overflow(溢出时扩展)”属性来解决。这两个问题,看似很简单,但要真正实现起来,一些细节非常重要。下面是设计好的报表布局:
如果不做任何特殊设置,则预览效果如下图:
可以看出,第一行和第二行的“家长信息”显示不完整,且第三条空记录也打印了出来。
若要不打印空行,首先,语文成绩的 0.00 不能显示,其次,细节带区的四条竖线不能显示,最后,三个域控件和四条竖线都要选择属性中的“Remove line if blank(若为空则删除行)”。
对于域控件“语文”,可在其属性框中将类型指定为数值型,再选择“Blank if zero”。对于四条竖线,可设置其打印条件为“!empty(姓名) or !empty(语文) or !empty(家长信息)”。
若要通过扩展控件的高度来实现打印完整的“家长信息”,需按如下步骤操作:
1. 在域控件“家长信息”的属性框中,选择“Stretch with overflow(溢出时扩展)”。
2. 当家长信息扩展了高度时,该行中的四条竖线也必须扩展高度。因此,在四条竖线的属性框中,选择“Stretch relative to height of band(相对于带区高度伸展)”。
3. 当字段内容和竖线的高度改变时,必须将细节带区下方的表格横线向下调整。因此,在细节带区的横线属性框中,选择“Fix relative to bottom of band(相对于带区底部位置固定)”
最终的打印效果如下图:
八、报表编辑器中的几个快捷键
1. 按下 Shift键,双击某个带区分隔条,则选定该带区内的所有控件。
2. 选定一个对象后按 Alt+Enter,则打开对象属性对话框,相当于双击该对象。
3. 要修改一个标签控件,通常采用的方法是双击该控件,在弹出的属性对话框中修改。也可以再次单击报表控件工具栏上的“A”按钮,然后在要修改的标签上单击。我再介绍一个快捷键:选择标签后按下 Ctrl+E,直接进入修改状态。
关于 90 版报表引擎的高级功能,如:动态格式以及报表侦听器,限于本人的水平,在测试和学习过程中还有不少疑问待解,就不在这里献丑了。
[ 本帖最后由 liuxingang28 于 2014-7-18 11:48 编辑 ]