FastReport报表设计

FastReport报表设计

原文地址:FastReport报表设计做者:小黑html

目录数据库

5.1 前言编程

5.2 基本概念及操做设计模式

5.3 报表设计与范例数据结构

5.4 经常使用功能及函数编辑器

5.5 报表设计经常使用技巧ide

5.1 前言函数

汽车业务管理系统(VBMS)使用FastReport3.0报表系统设计报表。
    本文主要描述使用FastReport设计报表的基本概念、使用方法、设计技巧和范例,不是FastReport的用户手册所以并不针对每一个细节进行阐述。立足于创建设计报表的概念和实用技巧范例的讲解,面对的是具备必定计算机操做水平的用户。
在VBMS中使用FastReport设计报表应该掌握如下知识:
一、 熟悉SQL语言,为设计报表准备数据源。
二、 掌握VBMS的数据结构,可参考相关资料。
三、 掌握FastReport报表的设计使用方法。工具


体系结构
    学习报表设计前应当首先弄清楚VBMS系统与FastReport报表设计之间的关系。报表设计的目的是将VBMS数据库(Firebird1.5)中的数据按照须要的视图方式显示、统计出来,而且能够打印、导出。
    VBMS数据库与VBMS管理系统以及FastReport报表设计之间的关系是:
    Firebird数据库系统是报表的数据源,它存储着客户的业务数据。但该数据的存储方式并不必定是客户但愿直接看到的。
    VBMS管理系统是中间层,它负责链接Firebird数据库和FastReport报表系统,将数据库信息(例如数据库的位置)传入到报表系统中供设计报表时使用。
    FastReport报表系统是报表设计的主体,它负责接收或建立数据源,经过设计报表完成须要的功能。所以在VBMS管理系统的打印模块中存在两种数据源:一种是VBMS系统数据源,即在各模块中将设计好的数据源传入到打印模块中。优势是无须用户干预使用方便,缺点是不够灵活,更改数据源须要升级程序。例如各种单据的打印报表采用的就是系统数据源。另外一种是自行设计数据源,功能强大但对用户的要求较高。例如报表中心中的各种报表。学习


设计步骤
完成一张报表的设计主要包括如下几个步骤:
一、 肯定报表的需求,查阅VBMS关于数据库结构的文档,确认该需求的全部内容在VBMS中均有数据字段记录(即VBMS必须记录了相关数据,不然报表设计无从谈起)。
二、 根据报表的需求,肯定报表应该显示的模式。例如:是简单报表、主从报表或是分组报表等等。由于这涉及的自定义数据源时SQL语言的构成方式。
三、 利用数据库工具(例如:IBExpert),使用SQL语言尝试获取报表但愿的数据集。这里有可能不能经过SQL语言一步到位获取到但愿的结果,但你仍可能经过FastReport报表系统对数据集进行二次加工。
四、 在FastReport报表中自定义数据源(经过上步获取的SQL语句),利用报表系统中提供的各类控件构造出但愿的报表格式。
五、 对于设计好的报表进行测试。

5.2 基本概念及操做

本节主要讲述FastReport报表系统的基本概念、基本操做方法、基本控件使用等内容。

基本概念

最主要的概念是FastReport报表的组成方式和控件主要用途,它通常包括如下方面: 
*页面(Page) --- 默认为Page1
    与咱们现实中使用的纸张类似。但它不只仅指的是一张纸,而是用于咱们设计报表的容器。打印出来能够是一张纸也能够是多张。页面(Page)能够有多个(你能够新增页面New Page),便可以有多个报表容器。利用这一点,你能够设计出复合报表(Composite Report)。 
利用页面设置能够定义大小、方向、边界、打印方式、分栏等参数。这里再也不详述,只特别强调分栏的做用。你能够将页面分红多栏,这样打印时数据将按照从上到下,再从左往右的方式显示。这就是咱们一般说的分栏报表(Splite Report)。 
*区域(Band)
    FastReport将整个页面划分红若干个区域。而每一个区域有着各自不一样的功能,这些功能由FastReport自动加载。一个页面中能够没有区域,也能够只有其中的某些区域,这根据报表的需求而定。放置在页面中的区域有范围,落入区域范围内的控件(例如:TextObject)才具备区域的功能。 
重要的区域包括: 
#报表抬头(ReportTitle)

仅在第一页显示在纸张的上部。通常用于打印报表的标题等信息。

#报表合计(ReprotSummary)
仅显示在全部数据的最后末尾。通常用于打印统计信息等。 
#页首(PageHeader)
显示在每页的最上部。经过设置你可让它置于报表抬头之上或者之下。通常用于打印页眉信息等。 
#页脚(PageFooter)
显示在每页的最底部。通常用于打印页序等信息。 
#主数据(MasterData)
用于显示数据源的数据,是最重要的区域。在该区域中能够定义链接哪个数据源,那么该数据源的数据将会按顺序依次将记录打印出。 
数据区域还有明细数据(DetailData)等,一共支持6阶数据。利用明细数据能够设计出主从报表、主-细-子细报表等。例如:各种单据的打印报表就是由单据头(主数据)和单据体(明细数据)共同完成的。 
在打印时,明细一级的数据是受上一级主数据的控制,所以须要进行相关设置。 
#头(Header)
显示在全部数据源的最上部,仅打印一次。通常用于显示相关摘要信息。 
#尾(Footer)
显示在全部数据源的最下部,仅打印一次。通常用于显示全部数据的合计信息。 
#栏首(ColumnHeader)
显示在每页数据源的上部,它在每页均显示。所以通常用于打印数据源字段的栏目信息。 
#栏尾(ColumnHeader)
显示在每页数据源的下部,它在每页均显示。通常可用于统计显示每页数据的页合计信息。 
#群组首(GroupHeader)
用于显示分组数据,在每个分组开始显示。通常可用于显示分组索引数据。例如:将商品档案按商品分类分组显示,在群组首你能够显示商品分类名称。利用群组首能够设计出分组报表,关键是数据源必须按分组索引的字段排序才能达到分组的效果。群组首能够有多个,便可以嵌套使用。 
另外,能够设置让分组索引数据在报表预览时显示在左侧的树型列表框(OutLine)中。 
#群组尾(GroupFooter)
与群组首一一对应。通常用于显示分组数据的统计信息。 
#子(Child)
是一个独立的区域。你能够设置子区域隶属于上述区域中的任何一个。在打印时,打印完父区域后,子区域将会跟随打印。通常可用于打印装饰线、调整高度或者打印子报表(SubReport)。 
#重叠(overlay)
该区域内包含的内容将从页的开始位置计算打印,而不受其余功能区域的影响。通常用于没法在其余功能区域打印的内容的显示。 
*对话框(DialogPage)
你能够经过设计对话框完成对数据源进行动态控制的目的,这也是设计复杂报表的重要手段。 
对话框主要经过各类输入数据控件来接受客户的查询请求,所以能够学习几种主要的控件。 
#标签(Label Control) --- 用于显示文字信息。使用Caption属性修改文字信息。 
#文本编辑框(Edit Control) --- 用于接收用户录入的文字信息。使用Text属性修改文字信息。 
#按钮(Button Control) --- 通常用于肯定和取消。使用Caption属性修改文字信息。 
#多选框(CheckBox Control) --- 用于用户对条件的选择。使用Checked属性肯定是否。 
#单选框(RadioButton Control) --- 用于用户对条件的单一选择。使用Checked属性肯定是否。 
#下拉框(ComboBox Control) --- 用于用户对多个数据列表的选择。使用Text属性修改当前文字信息,使用Items属性填充列表信息。 
#时间框(DateEdit Control) --- 用于用户对时间的选择。利用Date属性改变时间。 

在Code页中,使用Pacal Script(就是类Pascal)语言进行编程,将大大发挥报表的功能。

  



*文本对象(Text Object)
这是FastReport报表中使用最频繁的控件。可用它完成以下主要功能:

  1. 显示通常文字信息 --- 直接录入便可。
  2. 显示数据字段信息 --- 通常格式:[数据源."字段名称"]。
  3. 显示变量内容 --- 通常格式:[<变量名>]。
  4. 显示装饰线等。

文本对象能够进行文字对齐、格式转化、文本着色、字体改变、画边框线等许多功能,这与MicrosoftWord中的操做有诸多相同特征。所以这里再也不一一赘述。

在文本对象中引用数据字段或者变量须要用中括号包含,并且引用变量名时还须要用尖括号包含,这样系统就知道这是一个变量名称而不是其余什么。

  



*子报表(Subreport Object)
放置子报表后,系统会自动增长一个页面,你能够在此页面上设计须要的报表。系统在打印处理时,先按主报表打印,当碰到子报表时会自动转入子报表的页面进行打印处理,完成后继续执行主报表打印的工做,因此咱们又称之为嵌套报表。
设计子报表与主报表基本上相同,惟一的区别是有些功能区域不能在子报表中实现,例如:报表抬头、群组。
*交叉报表(DB cross-tab)
又称动态报表,便可以实现横向和纵向都不能肯定时的报表。该报表的实现须要数据源按必定规格组织数据方能实现。 
*数据感知控件(FIB Query)
利用该控件进行数据源的设计,能够完成设计SQL语句、测试结果、字段别名等工做。

在FIBQuery控件的SQL属性对话框中有一个QueryBuilder工具。利用该工具你能够查看到目前数据库中全部的数据表以及数据字段信息。而且能够在工具中利用向导功能(Model)能够更好的完成SQL语句的编制工做,并能够测试结果(Result)。不过这里列出的仅是数据表(Table),还有视图(View)没有列出。若是须要使用视图或存储过程(Procedure)能够查阅相关资料,FIBQuery一样支持视图和过程。 
在FieldAlias属性中,你还能够将全部数据字段名称修改为中文名称。 
在Master属性中,你能够定义本数据源隶属于另外哪个数据源(即受哪个数据源控制)。 
若是你在数据源的SQL语句中定义了变量,那么在Params属性中,你能够设置这些变量的类型和值。

   

FastReport报表系统中还包含了一些其余控件,这些控件大部分是用于装饰报表的,比较容易理解,使用起来也比较简单,这里也再也不说明了。

基本操做

FastReport中的操做与MicrosoftWord中的操做很是类似,再也不详述。下面仅对一些经常使用功能及操做技巧进行提示。 
*热键 
Arrow --- 在Object之间移动 
Del --- 删除一个Object
Enter --- 调出选择的Object的编辑器 
Shift+Arrow --- 改变Object的尺寸大小 
Ctrl+Arrow --- 移动Object的位置 
Alt+Arrow --- 移动选择的Object到相邻的Object的旁边而且对齐 
*鼠标 
Left button --- 选择、移动一个Object,对于多选的一组Object,能够拖动右下角的红点同时改变所选的Object的尺寸大小 
Right button --- 调出右键菜单 
Shift+left button --- 多选Object
Ctrl+left button --- 按住Ctrl键不放用鼠标左键能够拖出一个虚线矩形框,释放鼠标按钮能够将该矩形框内全部Object选中,而后使用left button将选中的Object移动到所需位置 
Alt+left button --- 若是针对Text Object使用,将能够直接编辑内容,无需弹出编辑窗

   

5.3 报表设计与范例

根据报表需求的不一样,你能够利用多种报表方式完成报表。下面我将结合VBMS中已经实现的报表范例讲述各类报表的设计方法和思路。

简单报表(Simple list)

*报表格式 
通常由报表抬头、页首、页脚(或者栏首、栏尾,或者头、尾)、主项数据组成。 
*报表范例 
#商品档案列表 
步骤以下:

  1. 新建数据源(FIB Components->FIB Query),起名tblProduct。(修改Name属性)
  2. 获取所需数据(tblProduct->SQL)。
  3. 依次添加ReportTitle、PageHeader、MastData、PageFooter区域。
  4. 设置MastData区域链接的数据源->tblProduct。(双击MastData区域)
  5. 在ReportTitle中添加文本对象,录入报表名称。
  6. 在PageHeader中添加若干文本对象,录入字段中文名称。
  7. 在MastData中添加若干文本对象,并链接该文本对象至对应数据字段。(能够从下拉框中选取)
  8. 在PageFooter中添加文本对象,录入页码。(使用FastReport中的系统变量 [Page])

SQL语句:
SELECT * FROM TB_PRODUCT;

通常报表都是从简单开始构建,而后逐步细化后得出的。所以能够利用FastReport报表中的新建报表向导功能(菜单->文件->新建…->标准报表向导)快速搭建起一个报表的雏形,并且他会自动将各个字段排列整齐,这样能够节约一些时间。 
若是但愿在报表抬头打印本公司的名称以及电话等信息,可使用自定义变量(Custom)中的相关变量,该变量内容为VBMS在参数设置中定义的本公司资料。 
在向PageHeader中添加中文栏目和向MastData中添加数据字段时,你能够直接用鼠标从右侧的数据列表框中拖拽相应字段到相应的区域中。你能够将栏目和字段一块儿创建,固然数据列表框下方的多选框要打勾。 
能够在PageFooter中添加页码(Page)和总页数(TotalPages)。通常在文本对象中的格式为:共[TotalPages]页 第[Page]页。可是须要声明的是,必须将报表设置成两遍报表(Double pass)模式后TotalPages变量才起做用不然为0。这很好理解,当报表引擎(Engine)执行第一遍时并不知道数据将充满几页纸,只有当第一遍完成后才计算得出,所以须要二遍报表才能打印出总的页数。所以两遍报表在FastReport中是一个重要概念,对于某些特殊报表可能会用到。例如:须要将统计的合计值打印在全部明细以前而不是以后。


技巧: 
    前面说过,你能够利用字段别名修改英文的字段名称为中文名称,这样对于系统不很熟悉的人也能够看得懂报表。这里介绍另外一个方法,使用该方法既能够达到修改中文名称的目的,又能够令报表制做更加快捷。例如仍是上面这张商品档案列表。咱们能够直接在SQL语句中加入中文别名。 
SQL语句:(中文别名须要用双引号包含)
SELECT
PRODUCTNUMBER AS "商品编号",
PRODUCTNAME AS "品名规格",
PRODUCTUNIT AS "单位",
SELLPRICE AS "零售价"
FROM TB_PRODUCT
这样作的好处,一是报表中的数据字段均为中文容易理解,二是在执行上面六、7步骤时,你能够拖拽右侧的数据字段同时创建栏目头和字段,而此时栏目头中也跟随着变成了中文,避免了从新修改为中文的麻烦。固然因为vbms中的报表数量庞大,所以并未采用这种方法。 

*报表中的变量

FastReport中的变量分为三种。 
#系统变量 
系统定义的一些与报表打印相关的变量,这里介绍几个经常使用的变量。 
Date --- 系统当前日期 
Time --- 系统当前时间 
TotalPages --- 总页数(必须设置Double pass) 
Page --- 当前页码 
Line --- 当前行序号 
Line# --- 也是当前行序号,但区别是在一个新的数据区域(Band)内该变量将从新计数。 
#自定义变量(Custom)
自定义变量是由VBMS系统传入到报表系统中的。 
#编程(Code)中使用的全局变量 
你能够在Code页的起始处定义一些须要的全局变量。 
例如: 
var
S: string;
这里S就成了一个全局的字符型变量,你能够对它进行赋值、取值。也能够在文本对象中引用它,格式为:[<S>]。 

其实在FastReport报表系统中,全部对象诸如 页(Page)、区域(Band)、文本对象(TextObject)、对话框控件、数据源字段、系统变量、自定义变量等,你都可以在文本对象中显示他们的值,只是引用他们的方式不一样罢了。 
例如:经过文本对象(TextObject)
打印文本编辑框的内容能够引用Text属性,格式:[Edit1.Text]。 
打印公司名称能够引用自定义变量,格式:[CompanyName]。 
打印数据字段值,格式:[tblProduct."商品编号"]。其实数据字段也能够当作变量。 
打印自定义的全局变量,格式:[<S>]。这里S须要用尖括号包含,其实通常状况下对于变量而言均须要用尖括号包含,只是FastReport对于非自定义的变量(不是在Code中定义的)有了一个预先判断,容许省略尖括号而已,你加上尖括号也不会出错。但在编程(Code)中全部变量被引用就必定须要有尖括号。 
特别提醒:在文本对象中打印全部变量都必须用中括号[]将变量包含起来。

 

主从报表(Master Detail)

*报表格式 
通常由报表抬头、页首、页脚(或者栏首、栏尾,或者头、尾)、主项数据、细项数据组成。 
*报表范例 
#销售单据列表 
步骤以下:

  1. 新建2个数据源(FIB Components->FIB Query),起名tblOrder、tblItem。
  2. 获取所需数据(tblOrder->SQL、tblItem->SQL)。
  3. 依次添加ReportTitle、PageHeader、MastData、Header、DetailData、Footer、PageFooter区域。
  4. 设置MastData区域链接的数据源->tblOrder,DetailData->tblItem。
  5. 在ReportTitle中添加文本对象,录入报表名称。
  6. 在PageHeader中添加若干文本对象,录入字段中文名称(单据头)。
  7. 在MastData中添加若干文本对象,并链接该文本对象至对应数据字段。
  8. 在Header中添加若干文本对象,录入字段中文名称(单据体)。
  9. 在DetailData中添加若干文本对象,并链接该文本对象至对应数据字段。
  10. 在Footer中添加System Text对象,用于显示金额合计。
  11. 在PageFooter中添加文本对象,录入页码。(使用FastReport中的系统变量 [Page])

SQL语句:
#tblOrder
SELECT * FROM TB_ORDER WHERE ORDERTYPE='销售出库';
#tblItem
SELECT * FROM TB_ITEM WHERE ORDERID=:ORDERID;

主从报表的关键是须要关联主数据源和从数据源。通常状况须要经过如下方式关联: 
#从数据源的SQL语句中通常须要有用于关联的关键字段(外键)。例如上例中的ORDERID=:ORDERID。前面的ORDERID为tblItem的外键,即明细数据经过ORDERID与某一条主项数据关联。而:ORDERID为一个变量(在SQL语句中使用<冒号+变量名称>表示一个变量)。而通常这个变量的名称(ORDERID)的定义与tblOrder(主项数据)中的主键的名称相同,即变量名称定义为:ORDERID而不是:O或者其余。这样作的目的是系统能够自动进行匹配。 
#定义tblItem的属性Master等于tblOrder。这样明细数据就被主项数据所控制了。 
#定义tblItem的属性Params中的变量ORDERID的类型为整型(Integer),值为变量<tblOrder."ORDERID">。当你打开Params时,ORDERID变量已经默认存在了,这是由于你在tblItem的SQL中定义了这个变量的缘故。未来你可能会在一个数据源中定义多个变量,操做方法是相同的。设置值等于<tblOrder."ORDERID">表示当须要获取:ORDERID变量的值时,将会从主项数据中获取。这样当主项数据的ORDERID发生变化时,明细数据也随之变化。这个值的选取你能够经过按钮(fx)更方便的获取。


*SystemText对象 
该对象与文本对象(TextObject)基本上相同,区别在于使用SystemText能够更加方便的对一个数据集进行求和或者其余的操做。虽然你也能够直接在文本对象(TextObject)中使用求和函数对数据集进行求和,不过使用SystemText能够令你不须要记忆许多函数,由于它帮你作了,基本上它就是一个构建函数向导的工具。固然若是你对FastReport中的函数比较熟悉,彻底能够没必要使用SystemText而直接使用TextObject更加快捷。 
SystemText的用法以下: 
#放置一个SystemText对象到Footer中,用于对销售明细数据中的金额进行求和。 
#系统会当即弹出一个对话向导框。你能够选择三种方式中的一种:系统变量、求和、文本。这里主要将求和,另外两种方式很好理解(系统变量用于打印时间、页码等,而文本与TextObject中同样)。 
#选择求和(Ageregate value)。选择函数->SUM(其余为最大值、最小值、平均值、数量),数据Band->DetailData1(设置你须要求和的数据区域,这里固然是明细数据),数据库->tblItem(上一步选择好后,系统自动会设定为该数据区域链接的数据源),下一步你能够从数据字段中选择须要求和的字段(例如:TotalTaxSum)。或者在表达式中构造更为复杂的求和内容(这里暂不讲述)。 
#按肯定后,SystemText中的文本自动生成为[SUM(<tblDetail."TOTALTAXSUM">,MasterData2)]。当你再次双击该SystemText,你会发现对话框中系统默认为文本,而文本内容就是上面的内容。因而可知,SystemText其实就是TextObject加上函数向导。 

你们若是仔细会发如今求和向导对话框中有两个选项,一个是"计算不可见Band的数据",一个是"执行总数"。这两个选项是作什么用的呢? 
"计算不可见Band的数据":有时候在报表中咱们会对数据源作一些设置,例如知足某些条件的数据不显示出来(例如:维修结算单打印中仅打印自付内容)。那么这个选项可使得系统在求和时只计算可见的数据。 
"执行总数":咱们知道,对于主从报表中明细的求和,例如销售明细中商品的销售金额。该金额是表示本单据的合计。当单据变化时,这个合计值也随之变化。而有些时候,咱们可能不但愿这样,而是但愿有一个值一直在累加合计金额,而不是随着单据的变化这个合计值被重置。那么这个选项可使得系统一直累计合计值直到最后一张单据。 
上面两个选项对于不少报表是颇有用处的。


*SUM函数 
完整定义:SUM(Expr,Band,Flags);
Expr:你须要求和的变量或者更加复杂的函数,例如:<tblItem."TOTALTAXSUM">。 
Band:你须要求和的数据区域名称,例如:DetailData1。 
Flags:默认为0,能够省略。 
1 --- 计算不可见Band数据 
2 --- 执行总数 
3 --- 1 而且2(计算不可见Band数据 而且 执行总数)

分组报表(Group)

*报表格式 
通常由报表抬头、群组首、主项数据、群组尾组成。 
*报表范例 
#商品档案报表(按商品分类分组)
步骤以下:

  1. 新建1个数据源(FIB Components->FIB Query),起名tblProduct。
  2. 获取所需数据(tblProduct->SQL)。
  3. 依次添加ReportTitle、GroupHeader、MastData、GroupFooter区域。
  4. 设置MastData区域链接的数据源->tblProduct。
  5. 在ReportTitle中添加文本对象,录入报表名称。
  6. 双击GroupHeader,设置分组条件,选择数据字段tblProduct->PRODUCTSORT。
  7. 在MastData中添加若干文本对象,并链接该文本对象至对应数据字段。
  8. 在GroupHeader中添加若干文本对象,录入字段中文名称。
  9. 在GoupHeader中添加一个文本对象,录入<tblProduct."PRODUCTSORT">。用于显示商品分类名称。
  10. 在GroupFooter中添加System Text对象,用于显示合计数。
  11. 在PageFooter中添加文本对象,录入页码。(使用FastReport中的系统变量 [Page])

SQL语句:
SELECT * FROM TB_PRODUCT ORDER BY PRODUCTSORT;

所谓分组报表,就是按某一个字段进行分组显示,该字段具备相同的值的数据记录将被归类显示在一块儿。例如:上例中将商品档案按照商品分类归类显示。 
要达到分组的目的,其中一个关键是该数据集必须按分组条件排序。即SQL语句中必定要有ORDER BY这样的排序语句,而排序字段就是分组的字段。 
分组是能够多级的,也就是能够嵌套分组。例如:商品档案定义时可能用商品分类表示大类,商品类型表示小类。分组显示时但愿按大类包含小类这样嵌套方式显示。那你可让数据集按ORDER BY PRODUCTSORT,PRODUCTSTYLE这样来排序。排序时,排在前面的字段首先被排序,在相同的条件下,对排在后面的字段再进行排序。一样的这种状况下,你须要增长两个群组首尾,让他们嵌套排列。居于外层的设置分组条件为商品分类,居于内层的设为商品类型。


*分组条件设置中的选项 
在你设置GroupHeader的分组条件时,有如下几个选项,他们的用途以下: 
#保持与群组在一块儿 --- 这个选项表示,FastReport报表系统老是试图将一个群组的内容打印在一张纸上而不作分割。例如:有一个群组的内容比较多,而这个群组的开始打印位置居于纸的中部,所以本页将没法将所有该群组的内容显示完毕。那么FastReport将把这个群组打印在新的一页上,这样上页纸的底部将会留出空白。固然若是这个群组在新的一页仍然没法显示完毕,那FastReport就接着显示,再也不作其余处理了。 
#换页 --- 这个选项与上面这个选项基本概念相同,只是他老是将新的分组内容打印在新的一页上,而无论这个分组的内容有多少。固然这样纸张的空白也更多更浪费。但这种方式对于某些客户来讲仍然多是须要的。 
#显示在大纲 --- 若是选择本选项,那么在你预览报表时,你可使用纲要功能(有一个纲要按钮)。他能够将分组的名称显示在左边的树型框中,这样你能够更加方便的定位到相应的分组。 

若是你想预览时老是显示纲要(不须要老是按纲要按钮)。你能够选择左侧Page1中的Report对象,在属性PreviewOptions->OutlineVisibe设置为True。



*Reprint On NewPage
    若是你选择GroupHeader区域,而后点击鼠标右键弹出菜单(Context PopupMenu)。你会发现有一个选项Reprint On NewPage,这个在其余区域的右键菜单中是没有的。他是起什么做用呢? 
    咱们知道,通常分组报表设计时,老是将分组条件和中文字段名称显示在群组首。这样打印时,碰到一个新的分组,FastReport先是打印群组首中的内容,例如:商品分类的名称等。而后再打印该分组的数据。但若是数据较多时不能在一页中显示,那么剩余内容将打印在后面的一页中。这带来一个问题就是,若是独立看待后面一页纸,上面显示的数据咱们不知道是属于哪个商品分类的(分组),必须返回去查看上一页中的群组首才知道。而使用Reprint On NewPage,则FastReport将在新的一页中将群组首中的内容再打印一遍(Reprint)。这样你就能够清楚知道本组数据的归属了。固然这样的话,群组首中的内容将可能会被打印超过一遍,这取决于数据的多少。

分栏报表

待续...

多列报表

待续...

子报表

待续...

交叉报表

待续...

   

5.4 经常使用功能及函数

经常使用功能

*报表设置 
何时须要两遍报表(Double pass)? 
应用1 用于显示总的页数(TotalPages),例如:页脚显示 第1页/共20页。系统第一遍扫描报表时计算出TotalPages,而后第二遍实际生成报表。若是不使用Double pass,则TotalPages返回0。 
应用2 用于将明细项的合计值打印在报表起始位置,而不是在末尾。这须要在第一遍扫描报表时计算出而后在第二遍生成报表时显示在起始位置。 
密码 --- 用于将报表加密,这样在设计或者显示报表时须要输入密码。 
*页面设置 
分栏 --- 能够将报表在一张纸上分红若干列来打印,比较利于节省纸张。这与在主项数据的Band中设置多个列(Column)不一样,分栏打印顺序是从上往下,而后从左往右。多列打印顺序是从左往右,再从上往下。

函数

ListValue --- 根据SQL语句自动填充一个列表的值; 
procedure ListValue(ASQL: string;AList: TStrings);
begin
tblList.Close;
tblList.SQL.Text := ASQL;
tblList.Open;
tblList.First;
while not tblList.Eof do
begin
AList.Add(tblList.Fields[0].AsString);
tblList.Next;
end;
end;

   

ShowLoginSector --- 登录分公司列表自动选择,若是不是管理部门则不容许选择; 
procedure ShowLoginSector(L: TfrxComboBoxControl);
var
S: string;
begin
S := VarToStr(Get('LoginSector'));
if S = '' then S := '管理部门';
L.ItemIndex := L.Items.IndexOf(S);
L.Enabled := S = '管理部门';
end;

   

   

5.5 报表设计经常使用技巧

A 为系统数据源增长自定义数据源,达到扩展数据的目的

    在VBMS中的报表中心咱们能够本身设计数据源而后设计本身须要的报表。 其实,咱们在其余的模块中同样能够本身设计数据源(原来觉得不能够)。 
设计方法与报表中心中是同样的。 
下面我举一个例子: 
在客户档案模块中的打印报表中,增长每一个客户的对应的车辆资料的显示。 
原报表中已经有了一个系统传入的数据源dsCustomer。 
1.  FIB->FIB Query,新增一个数据源 dsVehicle。 
SQL语句为: 
SELECT * FROM TB_VEHICLE WHERE CLIENTID=:CLIENTID; 
其中:CLIENTID为变量,是随着dsCustomer的变化而变化的。 
(注意:若是你但愿这个变量由主数据源来控制,则该变量的命名必须与主数据源中的字段名称一致。) 
2. 设置dsVehicle的以下属性: 
Master -> dsCustomer;(设置主数据源) 
Params -> CLIENTID,数据类型 Integer,值 <dsCustomer."CLIENTID">
(设置参数:设置值时能够选择按钮fx来选择) 
3. 插入一个Band(明细数据)。 
设置链接数据库为dsVehicle。而后放入相关的字段(Text Object)。 
4. 鼠标右键设置MastData1的 Print if Detail Empty。目的是若是该客户没有车辆依然须要打印出来。

总结: 
    如今,咱们既能够在报表中心,也能够在任何位置的打印报表中设计本身的数据源,而且能够将本身的数据源与vbms系统传入的数据源进行关联。这样的应用可使报表设计更加灵活、更增强大。

   

B 为报表增长分组显示功能 
在vbms系统的设计报表功能中,有一个群组头、群组尾的功能。 
    若是将群组头和群组尾分别置于主项数据的上面和下面,则能够对该主项数据进行分组统计功能,设置群组头时,系统会询问对哪个字段进行分组。而后你能够在该群组头上放置一个该字段的TextObject来显示分组内容,在群组尾放置一个用于求和的SystemText。这样就能够按照该字段来分组统计了。 
注意:要让相同组别的记录显示在一块儿,必须使数据源按该字段排序。所以,在通常报表中,若是你但愿按照某个字段来分组统计,必须在打印所在的窗体上点击数据列表的该字段项(即排序,能够正排和逆排),而后再进入打印对话框来打印;若是是在报表中心中设计的报表,则在SQL中必须加上ORDER BY语句来排序。 
另外,在群组头的属性中有一个OutLine,若是等于True。则能够在预览中使用列表导航。

   

C 将对话框(DialogForm)中的信息显示在报表中。 
例如:对话框中录入开始日期和结束日期,你但愿将该时间范围显示在报表头上。 
方法是,在报表头上加一个Text Object,而后录入[edtBD.Text];edtBD就是开始日期编辑框的Name,记住要用中括号括起来。其余的类推。 
*在对话框中的下拉框中显示一个列表。 
例如,在对话框中你可能须要用一个下拉框让用户选择某一个供应商,下拉框中存储了全部供应商。 
方法是,首先建一个数据源(tblProvider),该数据源返回了全部供应商。在对话框中放一个下拉框(cmbClientName),在对话框的OnShow事件中编写以下代码: 
tblProvider.Open;
tblProvider.First;
while not tblProvder.Eof do
begin
cmbClientName.Items.Add(tblProvider.FieldByName('CLIENTNAME').AsString);
tblProvder.Next;
end;
该方法通用,只须要替换相应的数据源就能够实现其余的内容。

   

D 在分组脚或者栏尾显示多个数据项的合计。 
例如,对于导购人员统计表,有销售金额、项目金额、其余金额三项,我但愿在栏尾显示三项的合计值(不是每一项的合计)。 
若是要分别统计每一项的合计,你只需这样。 
SUM(<tblBMAccount."SELLSUM">)就能够统计销售金额了。 
将三项加起来,则写以下代码 
SUM(<tblBMAccount."SELLSUM">+<tblBMAccount."SERVICESUM">+<tblBMAccount."OTHERSUM">)

*这里讲一下一些语法格式。 
取一个字段的格式, 
格式:TableName."FieldName"
表名+逗号+字段名,字段名用双引号引发来。

若是你但愿在一个TextObject中显示某一个字段内容, 
格式是:[TableName."FieldName"]
用中括号括起来,中间是字段。

若是该字段内容做为参数参加运算或者做为一个函数的参数,则须要用<>尖括号将字段括起来。 
格式:SUM(<TableName."FieldName">)
好比:SUM(<tblBMAccount."SELLSUM">); 
或者 <tblBMAccount."SELLSUM">+<tblBMAccount."SERVICESUM">; 
一样的,若是但愿将他们放在Text Object中显示,还必须加上中括号。 
例如:[SUM(<TableName."FieldName">)]

这里关键记住,若是想在TextObject中显示要用[]中括号,要在函数的参数中引用字段或者使用字段进行运算,须要用<>尖括号将字段括起来。

   

E 如何将报表底部的合计显示在报表头 
若是直接将合计的TextObject放在主项数据的前面,将不能统计值,由于此时还没有解析出全部数据。 
利用FastReport的两遍报表和临时变量功能实现。 
首先设置该报表为两遍报表(Double Pass)。 
在底部的某一个Band中的OnBeforePrint事件中加入如下代码: 
例如: 
Set(<tblBMAccount."BM">,SUM(<tblBMAccount."SELLSUM">+<tblBMAccount."SERVICESUM">+<tblBMAccount."OTHERSUM">));
说明:Set是一个函数,他将一个值存入了一个变量中。 
Set(var,value);其中变量var能够利用数据表中的某一个字段,Value是你的合计值。 
在主项数据(MastData)的上面的某一个Band中放一个TextObject(例如:memTotal) 
而后在该TextObject的OnBeforePrint事件中加入以下代码: 
例如: 
if Engine.FinalPass then
memTotal.Text := Format('%8.2f',[Get(<tblBMAccount."BM">)]);
说明:Engine是FastReport管理报表的对象,FinalPass表示最后一遍报表。 
Get(var)将变量var的值返回。Format是一个格式化数字的函数。

   

F 在底部显示多个数据源某个字段的合计值 
例如:将三个明细的合计相加后显示总的合计。 
方法一: 
公式以下: 
[SUM(<dsServiceItem."TOTALTAXSUM">,MasterData1)+SUM(<dsProductItem."TOTALTAXSUM">,MasterData2)+SUM(<dsOtherItem."TOTALTAXSUM">,MasterData3)]

但有一个问题是,当三个明细不是所有存在时,打印时会发生Variant Operate操做错误。 
我分析该错误产生的的缘由是当其中一个明细不存在时,此时SUM后的结果为NULL(空值)而不是0,因此当一个NULL值与其余一个数值相加时会发生上述错误。 
解决的方法是,判断一下:若是SUM后为NULL,则给它赋值0。刚好FastReport中有一个函数IIF(Expression,TureValue,FalseValue);该函数能够经过判断条件,若是条件为True,则返回True值,为False则返回False值。 
因此将上述表达式进行一些改造。 
IIF(SUM(<dsServiceItem."TOTALTAXSUM">,MasterData1)<>null,SUM(<dsServiceItem."TOTALTAXSUM">,MasterData1),0)
上面这个表达式表示:若是合计值不为空,则返回合计值,不然返回0。

所以,整个表达式以下: 
[IIF(SUM(<dsServiceItem."TOTALTAXSUM">,MasterData1)<>null,SUM(<dsServiceItem."TOTALTAXSUM">,MasterData1),0)+IIF(SUM(<dsProductItem."TOTALTAXSUM">,MasterData2)<>null,SUM(<dsProductItem."TOTALTAXSUM">,MasterData2),0)+IIF(SUM(<dsOtherItem."TOTALTAXSUM">,MasterData3)<>null,SUM(<dsOtherItem."TOTALTAXSUM">,MasterData3),0)]

方法二: 
在Code页的最顶部定义三个变量,例如: 
var
V1,V2,V3: Double;

在每一个数据源的主项脚的OnBeforePrint的事件中分别录入: 
主项脚1的OnBeforePrint:
V1 := SUM(<dsServiceItem."TOTALTAXSUM">,MasterData1);
主项脚2的OnBeforePrint:
V2 := SUM(<dsProductItem."TOTALTAXSUM">,MasterData2);
主项脚3的OnBeforePrint:
V3 := SUM(<dsOtherItem."TOTALTAXSUM">,MasterData3);

在须要显示合计的TextObject中使用: 
[<V1>]或者[<V2>]或者[<V3>]或者[<V1+V2+V3>]便可。

   

G 在报表中引入本身的数据源 
有客户需求:但愿打印条码时同时打印出商品的品名规格和零售价(或其它商品相关信息),但条码库数据表中没有相应的数据字段。如何进行设计呢? 
其实利用条码库数据表中的商品序号(ProductID),能够本身增长一个数据源(dsBarCodeEx),经过ProductID做为主键来链接数据表TB_BARCODE和TB_PRODUCT,将TB_PRODUCT表中的某些字段引入(根据须要)。 
数据源多是以下内容: 
SELECT
TB_BARCODE.PRODUCTID,
TB_BARCODE.BARCODE,
TB_PRODUCT.PRODUCTNUMBER,
TB_PRODUCT.PRODUCTNAME,
TB_PRODUCT.SELLPRICE
FROM
TB_BARCODE
LEFT JOIN TB_PRODUCT
ON TB_PRODUCT.PRODUCTID=TB_BARCODE.PRODUCTID

这样,你能够利用本身设计的数据源(原来的数据源dsBarCode不去管他)设计出相应的条码打印报表(能够打印零售价等)。

   

H 在报表中实现可变数据源 
在报表中能够根据对话框中的条件实时调整数据源中的参数。 
例如:在库存情况表中导出到条码库后(全部商品均导出),有时须要只打印某些商品的条码。你能够设计一个对话框,能够按照商品编号筛选,若是筛选条件为空,则打印全部商品,不然打印筛选出的商品。 
设计数据源以下: 
SELECT
BA.PRODUCTID,
BA.BARCODE,
PR.PRODUCTNUMBER,
PR.PRODUCTNAME,
PR.SELLPRICE
FROM
TB_BARCODE BA
LEFT JOIN TB_PRODUCT PR
ON PR.PRODUCTID=BA.PRODUCTID
WHERE PR.PRODUCTNUMBER = :N

而后在数据源的Params中设置N的参数。

此时,若是筛选条件为空,则查询出来的数据也为空。 
这是由于条件 WHERE PR.PRODUCTNUMBER = :N 致使的。 
筛选条件为空时,数据源应该去掉该条件。此时须要根据条件动态调整数据源。

在btnOK(对话框中的肯定按钮)的OnClick事件中加入如下代码: 
procedure btnOKOnClick(Sender: TfrxComponent);
var
S: string;
begin
S := 'SELECT BA.PRODUCTID,BA.BARCODE,PR.PRODUCTNUMBER,PR.PRODUCTNAME,PR.SELLPRICE'+
' FROM TB_BARCODE BA'+
' LEFT JOIN TB_PRODUCT PR'+
' ON PR.PRODUCTID=BA.PRODUCTID';
if edtProductNumber.Text<>'' then
begin
S := S + ' WHERE PR.PRODUCTNUMBER = :N';
dsBarCodeEx.ParamByName('N').Value := edtProductNumber.Text;
end;
dsBarCodeEx.SQL.Text := S;
end;
该代码根据筛选条件不一样,对数据源的SQL语句进行不一样的设置。 
这样就能够达到要求了。


I 在对话框中,显示开始日期和结束日期。 

在DialogPage1的OnShow事件中加入如下代码: 
方式1: 
procedure DialogPage1OnShow(Sender: TfrxComponent);
begin
edtBD.Text := DateToStr(Date); 
edtED.Text := DateToStr(Date);
end;

说明: 
edtBD,edtED为开始日期、结束日期的编辑框。 
DateToStr()函数将日期型变量转为字符串。 
如今,开始日期和结束日期默认为今日。

方式2: 
procedure DialogPage1OnShow(Sender: TfrxComponent);
var
Y,M,D: Integer;
begin
Y := YearOf(Date);
M := MonthOf(Date);
D := DaysInMonth(Y,M);
edtBD.Text := DateToStr(EnCodeDate(Y,M,1));
edtED.Text := DateToStr(EnCodeDate(Y,M,D));
end;

说明: 
YearOf()函数返回某个日期的年份; 
MonthOf()函数返回某个日期的月份; 
DaysInMonth()函数返回某月的天数; 
EnCodeDate()函数将年、月、日整型数转为日期型;

如今,开始日期为本月的1号,结束日期为本月的最后一天。

   

J 在对话框DialogPage1中使用警告框提醒输入相关内容

例如:你可能须要用户必须录入某些查询内容,不然提醒用户输入。 
在btnOK(肯定按钮)的OnClick事件中加入如下代码:

procedure btnOKOnClick(Sender: TfrxComponent);
begin
if edtDepotName.Text = '' then
begin
ShowMessage('请输入仓库!');
edtDepotName.SetFocus;
DialogPage1.ModalResult := mrNone;
Exit;
end else
DialogPage1.ModalResult := mrOK;
end;

说明: 
ShowMessage()函数用于显示一条警告信息。 
edtDepotName.SetFocus 表示该编辑框获取输入焦点; 
DialogPage1.ModalResult := mrOK    表示经过; 
DialogPage1.ModalResult := mrNone  表示不经过;

   

K 单据打印中如何实现空表格填满剩余的空行,达到指定的行数。

在原来的报表基础上,增长一个子Band(Child1),在这个Band上设计空白行。 
能够将Footer1的高度Height设置为0;

在Code页中录入如下代码:

var
PageLine: Integer;         //在如今页打印到第几行 
PageMaxRow: Integer = 8;   //指定的每页固定行数 你能够修改

//在MasterData1的OnBeforePrint事件中加入如下内容 
procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
begin
PageLine := <Line#> mod PageMaxRow;
if (PageLine = 1) and (<Line#> > 1) then
Engine.NewPage;
end;

//在Footer1的OnBeforePrint事件中加入如下内容 
procedure Footer1OnBeforePrint(Sender: TfrxComponent);
var
i: Integer;
begin
i := iif(PageLine=0,PageMaxRow,PageLine);
while i < PageMaxRow do
begin
i := i + 1;
Engine.ShowBand(Child1);  //增长一个子Band,在该Band上设计空白的行 
end;
end;

   

L 在报表中使用金额大写 
在FastReport的设计模式下,在Code页中加入如下函数:

function SumToCaps(const Value : Double): string;
const
d = '零壹贰叁肆伍陆柒捌玖分角元拾佰仟万拾佰仟亿';
var
m,k : string;
j   : Integer;
begin
k :='';
m :=FloatToStr(int(Value*100));
for j:=length(m) downto 1 do
k := k+d[(strtoint(m[Length(m)-j+1])+1)*2-1]+
d[(strtoint(m[Length(m)-j+1])+1)*2]+d[(10+j)*2-1]+d[(10+j)*2];
result := k;
end;

当你须要将一个金额转换为金额大写时能够以下操做: 
一、在Code页的开始处定义一个字符串。 
Var
TOTALSUM_CAPS: string;

二、在相应的事件(多是OnBeforePrint)中加入 
TOTALSUM_CAPS := SumToCaps(TOTALSUM);
注:这里的TOTALSUM多是一个变量,也能够是数据源中的字段或者合计值。例如: 
<tblMaster."TOTALSUM">或者SUM(<tblMaster."TOTALSUM",MasterData1,1>)。

三、在须要显示大写金额的TextObject中键入[<TOTALSUM_CAPS>]。

   

M 如何隐藏某些主项数据记录

一般当某个数值为零时,咱们不但愿这条记录被打印或者显示。 
步骤以下: 
一、选择主项数据MastData1的OnBeforePrint时间。 
二、在OnBeforePrint事件中填写代码 
if <tblMaster."TotalSum">=0 then
MastData1.Visible := False else
MastData1.Visible := True;
其中<tblMaster."TotalSum">=0是条件,你能够定义为本身的条件。

   

N 如何强调某些主项数据的内容 有时咱们但愿当知足必定条件时,某些数据的字体或者颜色显示不一样,以达到强调的目的。 步骤以下: 1 选择须要强调的TextObject。 2 选择工具栏中的强调按钮。 3 在对话框中录入须要强调时的条件。例如:<tblMasterData."TotalSum"> >= 10004 选择强调的字体,颜色。

相关文章
相关标签/搜索