深入QuickReport(二)

本文深入介绍QuickReport例程,通过多个例子展示其组件应用。包括TQuickRep、TQRLabel等组件在报表设计中的使用,如显示数据库表内容、分组统计等。还讲解了主/明细报表设计,涉及数据表连接和TQRSubDetail组件设置,助于进行简单及复杂报表设计。

深入QuickReport(二)

作者:董维春

(本文已在《优快云开发高手》04年第一、二、三期上发表,应广大网友的要求,经编辑同意,发表在优快云作者本人文档中,略有修改,但仅即于此,未经优快云或作者本人同意任何个人与网站不得转载、摘抄,否则任何涉及到版权的行为后果自负)

 

第二部分:深入QuickReprot例程

 

在应用中学习,在实践中进步,这是我学习QuickReport的最大感受,通过上面的介绍,我想你对QuickReport也有了一定的了解,那么下一步我们将通过例程逐步深入QuickReportJ

 

例一:TQuickRep、TQRLabel、TQRDBText组件的应用
        
实践是最好的老师,我们先通过一个例子来看一下QR的快捷与方便。
         1
建立一个新Project
         2
)放一个TTableForm上,这里我们用BCB中自带的数据库。DatabaseName设为BCDEMOSTableName指向Customer表,Active设为true
         3
放一个TQuickRep控件在Form上,DataSet属性为Table1(即要显示Table1所指向的表的内容)。
         4
展开TQuickRepBands属性,设HasDetailtrue,这时自动增加个Detail Band(一个TQRBand控件,故也可以直接放一个TQRBand控件,BandType属性设为rbDetail就行了)。这个区段是重复区段。
         5
)放一个TQRLabelTQRDBText控件在Detail Band上面,TQRLabelCaption属性设置为“公司:”二字;TQRDBText DataSet指向Table1DataField指向Company
        6
)选TQuickRep控件(不要指在区段上),按右键,选择“Preview”预览,应该看到表Customer的字段Company中所有字段值。
        
到这一个简单的例子就OK了。但这个程序你编译后,会得到与你布置时一样的QuickReport组件,看不到你想要的报表内容。程序要实现刚才Preview时的效果只能利用TQRuickRep自带的打印功能了,我们只要在Form中加上一个按钮,在它的OnClick事件中写上:QuickRep1->Preview(); 就可以了。没有人希望那个什么也不显示的TQuickRep组件摆在窗体上,这也告诉我们一点我们的程序中最好有两个Form:一个是放置控制QuickReport显示、打印或实现其它功能的,比如本例中放置控制按扭;一个是提供给QuickReport布置组件的。

当然这不是说在一个Form中实现不了上述功能,其实你只要在窗体的OnCreate事件中把TQuickRep组件隐藏起来就可以了:

void __fastcall TForm1::Form1Create(TObject *Sender)

{

    QuickRep1->Hide();

}

要注意QR你不能用Show()调用,那你将得不到你想要的程序,当然用Preview()就没错了。以下是本例的程序源代码:

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

        : TForm(Owner)

{

}

//---------------------------------------------------------------

void __fastcall TForm1::Form1Create(TObject *Sender)

{

    QuickRep1->Hide();

}

//---------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

       QuickRep1->Preview();

}

//---------------------------------------------------------------

进一步思考:有时我们想实现垂直输出,比如用TQRLabel里的内容我们想垂直显示能否实现?

当然能实现。只要我们按如下设置就可以实现:

AutoSize=false;//默认为true

AutoStrech=true;// 默认为false

WordWrap=true;// 默认为true,这是设置中的重点,这与Label中的设置是一样的

Caption的值要注意,每个字符间一定要有空格;//一般的设置我们不会留空格,因为设计空格除了美观,没什么实际意义,但在这里必须留空格

进一步思考:我们想显示有两位小数的数字,应该如何办呢? 
只要把该可视化组件的mask属性设为0.00就可以实现了。

 

例二:TQRGroup、TQRExpr组件的应用  

该报表先列出州名,接着列出该州的所有公司及公司总数,一个州列完后空一行(Group中断),列出新的州名,接着列新州下的所有公司,没有填州名的公司统一列在“不清楚什么地区的”下面。
         1
)新建一个Project
         2
)放一个TQueryTForm上,其SQL属性为:select * from customer order by State,Company,即根据州、公司排序,DatabaseNameBCDEMOSActivetrue
        3
放一个TQuickRep控件在Form1上,DataSetQuery1
        4
)放一个TQRBandTQuickRep上面,把其BandType设成rbDetail

5)放一个TQRGroup控件在TQuickRep上,这时默认为Group Header。(任何时候当Group中断或更高级别的Group中断,这个Header都将打印出来,如果有表达式,根据表达式的值显示内容),接着添加一个Group Footer Band,但我们却不能找到这样的一个组件,那应该如何设计出Group Footer Band区段呢?我们只要放一个QRBand2在报表上,把TQRGroup的FooterBand属性指向QRBand2,看一下,QRBand2是不是变成了Group Footer Band TQRGroup的一个重要特性是表达式,任何时候当表达式的值改变时,Group都将中断,如表达式是按省列出城市名,当前列出辽宁省,当属于辽宁省的城市列完后,表达式值改变,这时Group中断,接着显示其他省的城市名),TQRGroup1Expression属性设为Query1.State(根据不同的州来中断)

注意:为什么不直接再放一个TQRGroup,因为无论我们放多少个系统都会默认为 Group Header。
       6
)放一个TQRExpr控件在Group Header上面,其Expression属性为:IF(Query1.State <> '',Query1.State,'不清楚什么地区的'),即如果公司的州没填,就归入“不清楚什么地区的”,否则归入具体的州。
       7
)放三个TQRDBTextDetail上,他们的DataSet都指向Query1DataField分别指向CompanyContactPhone
       8
)再放一个TQRExpr控件在Group Footer  Band上面,ExpressionQuery1.State+'共有:'+STR(COUNT)+’个公司,作用是在每个州的公司列完后显示这个州总共有多少个公司。
       9
)把鼠标放在QuickRep组件上(不能放在Band区段上),按右键选预览,应该看到不同的州名及其公司名称和该州公司总数。

注意:大家发现看到并不是每个州公司的总数,每个州后列出的都是把上一个州的总数也加上的累计值,难道是我们错了,没有,检查一下你的Expression组件(运行COUNT那个)的ResetAfterPrint的属性值是否为true,如果不是把他改为true,现在看一下J

进一步思考:每一组内容都联在一起,有些不爽,要是每组内容之间被什么分隔开就好了?

其实这并不难实现,我们只要把QRBand2(group Footer)的HasChild属性设为true就可以了。当然你直接把一个TQRChildBand组件放在QuickRep1上,把她的ParentBand属性设置为QRBand2,同样可以实现上面的设置。另外我们同样可以在TQRChildBand布置其它可视化组件J

进一步思考:要是每组结束后就换页,那不是更爽吗?

只要我们把QRGroup1的ForceNewPage属性改为true就可以了,同样的组件还有一个ForceNewColumn。但一定要注意,我们改了哪个区段的这两个属性,就从哪个区段开始NewPage/NewColumn。

 

例三、TQuickRep组件的Page属性应用

PVC胸卡有些朋友一定见过,做这样的卡片并不太难,最近笔者就参与制作了一批胸卡,这里我们要讲的是卡片的设计。

1)新建一个Project。

2)放一个Table组件,把它指向我们的资源数据库,并把Active设为true。

3)放置一个TQuickRep组件在Form1上,并把它DataSet设置为Table1,在她上面放一个TQRBand,把其BandType值设置成rbDetail。在Band区段上面按下图放置好四个TQRLabel组件、三个TQRDBText组件与一个TQRDBImage组件。

4)三个TQRDBText组件的设置基本上一样的,把DataSet指定为Table1,然后在从DataField中选取正确的字段。我们可以同样的设置好TQRDBImage的相关属性。

5)对页面进行设置,这是关键。一张纸上我们不可能只打印一个,打印得越多越多好,左边打完,在右边继续打印,这样才能充分利用原材料。我们这里用到了分栏,把Number of columns属性设为2,也就是分两栏。TQuickRep中使用组件的快捷菜单Report  settings打开Page的属性编辑器窗口,做如下设置:

其中Pager size选择为自定义,在其后输入纸的大小 ,其它设置按上图即可。当然我们也可以在对象查看器窗口单击Page属性左端的编辑按钮,展开其属性值来进行正确的设置,如下图:

 

6TQRBandWidth设为228,然后重新调整好Band上组件的位置。228实际上是由38×6得到的。

7)把鼠标放在QuickRep组件上(不能放在Band区段上),按右键选预览,看一下效果吧。

难点:为了定位方便、准确, TQuickRep组件提供了坐标(一格一格的,边上带数字的,不会告诉我没看见吧J),从对纸张的设置我们知道这些坐标每整格相距为10mm,但在QR中,很多组件都没有单位,对于这10 mm,QR中对应的单位长度是38,这一点你一定要记住。

 

通过上面的三个例子,我们已经可以进行了一些简单的报表设计,从例四开始我们将进一步的学习QuickReport,下面例程也只讲关键点,着重分析,省略一些重复性的语言。

 

例四、主/明细(Master/Detail)报表与TQRSubDetail组件的应用

设计主/明细报表的关键有两点:一是主/明细数据表的连接;二是对TQRSubDetail组件的正确使用。

 

主从数据表连接示意图1(TTable与TTable)

 

Master                 关联             Detail

组件名                     TTable          TDataSource1       TTable

重要属性                 Name     <=== DataSet              Name

                        TableName                Name   <====DataSource

DabaseName<===指向同一库名==>DabaseName

(指定索引字段)IndexFieldName                          MasterField(点击右侧“…”调出Field Link Designer对话框,设置好关联字段)

Active<=======同设为true=======>Active

 

 

主从数据表连接示意图2(TTable与TQuery)

 

Master                 关联             Detail

组件名                     TTable          TDataSource1       TTQuery

重要属性                 Name     <=== DataSet              Name

                        TableName                Name   <====DataSource

DabaseName<===指向同一库名==>DabaseName

(指定索引字段)IndexFieldName                                     SQL(点击右侧“…”调出String  list  Editor对话框设置好关联字段)

Active<=======同设为true=======>Active

 

TQRSubDetail组件的设置:

1Master的值设为所在TQuickRep组件的名;

2DataSet的值设为连接明细表的组件名;

3)点击Bands前面的“+”,展开属性,能看到HasFooterHasHeader 两个属性,把其值设为true,这样我们就得到了一对Group(当然完全我们完全可以用别的方法)。

注意:通过TQRSubDetail属性Band里的HasHeader、HasFooter产生的Group组,在Group Header中没有Expression,她们默认按主/明细表的关联关系分组。其实没有他们,TQRSubDetail也是这样用的。                                       

我们建立如下图的主/明细报表:

 

 

1)设置数据集

在窗体上放置TTableTDataSourceTQuery组件,把Table1Query1DatabaseName属性设置为BCDEMOS,把Table1TableName设为customer.db(主表名),把IndexFieldName设为索引字段名CustNo。把DataSource1DataSet设为Table1,为做主/明细数据做好准备。

连接明细表的Query1,我们把其DataSource设为DataSource1,从而建立关联关系,并将其SQL属性设成:

 

SELECT  *        FROM  orders         WHERE       CustNo         =:             CustNo

          ^                          ^                     ^              ^             ^                    ^

          ||                          ||                     ||             ||             ||                    ||

选择所有字段   从orders表(从表)    条件   从表的字段   建立主从关系  主表字段

 

 

这样我们就建立了明细表与主表的关联,明细表是按上式关系分组的,就是把CustNo一样的放在一起。

2)设置报表结构

首先,在前面设计的窗体上放置一个报表组件TQucikRep,在对象查看器窗口中把Band属性展开,将其HasColumnHeaderHasDetailHasPageFooterHasPageHeaderHasSummaryHasTitle属性设为true

QuickRep1DataSet属性设为Table1,为报表主表指定数据源。

然后,把TQRSubDetail组件放到QuickRep1组件上,作为明细表Band区段。把其Master属性设置为QuickRep1,设置Bands的子属性HasHeaderHasFootertrue,并将其DataSet属性设置为Query1,指定明细表数据来源。

3)设置主/明细报表的主体

ColumnHeaderBand1区段中添加主表中各字段的标题使用的报表标签组件(TQRLable),它们的Caption分别为客户号、公司、电话、传真和所在城市。在DetailBand1区段中添加显示主表字段值的报表组件(TQRDBText),与前面标题对应设置其字段,要注意的是它们的DataSet都为Table1

在明细报表部分,我们首先在GroupHeaderBand1中放置明细表的表头标签(TQRLable),它们的Caption依次设置为定单号、条款、付款方式、款项总额和未付款额。在QRSubDetail1区段中放置显示明细报表的组件对象(TQRDBText),其DataSet属性全设为Query1,字段名称依次是OrderNoTermsPaymentMethodItemsTotal。接着添加一个TQRExpr组件,设置其Master属性为QRSubDetail,打开表达编辑器,输入下面的表达式:

INT(Query1.ItemsTotal-Query1.AmounPaid)

GroupFooterBand1区段中添加统计报表组件QRExpr2,并将其属性设置为QRSubDetail1,打开表达式编辑器,输入如下 表达式:

SUM(INT(Query1.ItemsTotal-Query1.AmounPaid))

即计算未付款项的总额,并设置ResetAfterPrinter属性为true,这样,就可以统计出明细表的总额了。

SummaryBand1区段中添加一个QRExpr3,打开表达式编辑器,在其中输入如下语句:

SUM(INT(Query1.ItemsTotal-Query1.AmounPaid))

这样这个报表的主体我们就做完了,其它设置看一下上面的图你就应该明白了。

下面我们再添加例一中的那样的程序代码,至此这样的一个复杂报表我们就完成了。

本例是用TTableTQuery做的主/明细数据关联,同样我们可以用TTableTTable做主/明细数据关联,实现本例这样的报表。

 

第一部分 快速开发的基础 第1章 Delphi 5下的Windows编程 1 1.1 Delphi产品家族 1 1.2 Delphi是什么 3 1.2.1 可视化开发环境 3 1.2.2 编译器的速度和已编译代码的效 率 4 1.2.3 编程语言的功能及其复杂性 4 1.2.4 数据库结构的灵活性和可扩展性 5 1.2.5 框架对设计和使用模式的扩充 5 1.3 历史回顾 5 1.3.1 Delphi 1 5 1.3.2 Delphi 2 6 1.3.3 Delphi 3 6 1.3.4 Delphi 4 7 1.3.5 Delphi 5 7 1.3.6 未来 7 1.4 Delphi 5的IDE 7 1.4.1 主窗口 8 1.4.2 窗体设计器 9 1.4.3 Object Inspector 9 1.4.4 代码编辑器 9 1.4.5 代码浏览器 10 1.4.6 源代码生成器 10 1.5 创建一个简单的应用程序 11 1.6 事件机制的优势在哪里 12 1.7 加速原型化 13 1.8 可扩展的组件和环境 13 1.9 IDE最重要的十点功能 13 1.10 总结 15 第2章 Object Pascal语言 16 2.1 注解 16 2.2 新的过程和函数特征 17 2.2.1 圆括号 17 2.2.2 重载 17 2.2.3 缺省值参数 17 2.3 变量 18 2.4 常量 19 2.5 运算符 20 2.5.1 赋值运算符 20 2.5.2 比较运算符 20 2.5.3 逻辑表达式 21 2.5.4 算术运算符 21 2.5.5 按位运算符 22 2.5.6 加减运算过程 22 2.6 Object Pascal类型 23 2.6.1 类型的比较 23 2.6.2 字符 24 2.6.3 字符串 24 2.6.4 变体类型 32 2.6.5 Currency 39 2.7 用户自定义类型 39 2.7.1 数组 39 2.7.2 动态数组 40 2.7.3 记录 41 2.7.4 集合 42 2.7.5 对象 43 2.7.6 指针 44 2.7.7 类型别名 46 2.8 强制类型转换和类型约定 46 2.9 字符串资源 47 2.10 测试条件 47 2.10.1 if语句 47 2.10.2 case语句 48 2.11 循环 49 2.11.1 for循环 49 2.11.2 while循环 49 2.11.3 repeat...until 50 2.11.4 Break()过程 50 2.11.5 Continue()过程 50 2.12 过程和函数 50 2.13 作用域 50 2.14 单元 55 2.14.1 uses子句 55 2.14.2 循环单元引用 56 2.15 包 56 2.15.1 使用Delphi的包 56 2.15.2 包的语法 56 2.16 面向对象编程 57 2.17 使用Delphi对象 58 2.17.1 声明和实例化 58 2.17.2 析构 59 2.18 方法 59 2.18.1 方法的类型 60 2.18.2 属性 61 2.18.3 可见性表示符 62 2.18.4 友类 62 2.18.5 对象的秘密 63 2.18.6 TObject:所有对象的祖先 63 2.18.7 接口 63 2.19 结构化异常处理 66 2.19.1 异常类 68 2.19.2 执行的流程 70 2.19.3 重新触发异常 71 2.20 运行期类型信息 72 2.21 总结 72 第3章 Win32 API 73 3.1 对象:以前和现在 73 3.1.1 内核对象 73 3.1.2 GDI和用户对象 75 3.2 多任务和多线程 75 3.3 Win32内存管理 76 3.3.1 什么是线性内存模式 76 3.3.2 Win32系统是怎样管理内存的 76 3.4 Win32的错误处理 78 3.5 总结 78 第4章 应用程序框架和设计 79 4.1 理解Delphi环境和项目的体系结构 79 4.2 构成Delphi 5项目的文件 79 4.2.1 项目文件 80 4.2.2 单元文件 80 4.2.3 窗体文件 8
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值