水晶报表的使用经验和资料总结
一. 前言
该文档就集团分析系统研发过程中水晶报表(Crystal Reports)的使用经验和值得注意的地方进行了总结和归纳,它不是水晶报表的使用手册,如果您要了解水晶报表使用的细节,那么您可以阅读《水晶报表中文手册》,或者使用水晶报表本身自带的联机帮助。本文乃经验之谈,错误之处在所难免,请不吝斧正。
二. 简介
Crystal Reports是世界领先的桌面及 Web 报表工具,可用于处理数据库,帮助用户分析和解释重要信息。使用 Crystal Reports 可以方便地创建简单报表,同时它也提供了创建复杂或专用的报表所需的整套工具。
Crystal Reports 几乎可以从任何数据源生成您需要的报表。内置报表专家在您生成报表和完成一般的报表任务过程中,会一步一步地指导您进行操作。报表专家通过公式、交叉表、子报表和设置条件格式帮助表现数据的实际意义,揭示可能被隐藏掉的重要关系。如果文字和数字确实不够充分,则用地理地图和图形进行形象的信息交流。
Crystal Reports 的灵活性并未停留在创建报表这一功能上,您可以用各种各样的格式发布报表,包括用 Microsoft 的 Word 和 Excel 发布、通过电子邮件甚至 Web 发布。高级的 Web 报表功能允许工作组中的其他成员在他们自己的 Web 浏览器中查看或更新共享报表。
通过将 Crystal Reports 的报表处理功能整合到自己的数据库应用程序中,应用程序和 Web 开发人员可以节省开发时间并满足用户的需求。Crystal Reports 支持大多数流行的开发语言,可以方便地在任何应用程序中添加报表。鉴于实际项目经验本文中仅结合C#语言进行归纳总结。
三. 安装
Crystal Reports 已经集成在Visual Studio.NET 2003中,因此它的安装非常简单方便,您只需要在安装Visual Studio.NET时勾选相应的选项即可,但必须提醒您,您必须注册,否则使用三十次以后Crystal Reports 将不能继续使用。目前网上可以搜索出大量注册码,但请您慎重使用。另外值得一提的是按照上面这种方式安装后,Crystal Reports的开发(程序代码部分)和设计(报表格式设计部分)都只能在Visual Studio.NET工具下进行。
其实Crystal Reports 也可以作为独立的模块进行安装,公司内部有人制作了相应版本的ISO安装文件《Crystal Reports 9.iso》,您可以使用FTP工具登陆192.168.2.7(user:fox123,password:fox123)在 /SoftRoot/C#/目录下便可找到,同时该目录下还有Visual Studio.NET2003的安装程序。在您得到该文件后便可以安装,需要提醒您由于Crystal Reports 目前已经发布了众多版本,集团分析系统研发人员在研发过程中发现Crystal Reports不同版本之间的兼容性并不是很好,如果安装过程中出错会给以后的使用造成巨大的麻烦,请务必注意。因此,在您安装之前请先确认您即将安装Crystal Reports的这台电脑上是否安装过其它版本的Crystal Reports工具,当然这也包括Visual Studio.NET中自带的Crystal Reports,如果有那么请您最好先将其删除,以除后患。这里的安装同样非常简单,您只需要双击安装文件,注意默认的典型安装中有些数据库驱动程序并没有安装,这其中就包括公司里一直使用的SYBASE数据库,因此您需要选择自定义安装,进行相应的选择。安装结束时请注册,注册码在安装程序文件夹下保存,可任选其一进行注册。注册后您可以使用Crystal Reports设计工具进行报表的设计,也可以使用Visual Studio.NET进行代码的设计两者可以分开独立进行。
四. 报表设计
用Crystal Reports 设计报表是件非常简单的事情,当然设计一张结构负责、外观清新爽朗的报表也是需要下一番功夫的。Crystal Reports 带有一个报表设计向导,该向导会指导您一步一步的完成从选择报表类型、定义数据源到选择报表呈现模版的全部过程。当然您也可以避开这些繁琐的环节直接创建空白报表进行自行设计。接下来我就报表设计过程中比较重要的环节以及一些比较特殊实用的技巧进行简单介绍。
u 数据源
Crystal Reports 的主要用途就是访问存储在数据库中的数据并生成有关该数据的报表。Crystal Reports 可以访问的数据分为五大类:
Ø 直接访问数据库文件:(dBASE、FoxPro、Clipper、Pervasive、Paradox、Microsoft Access)
Crystal Reports 可以直接访问绝大多数常用的 PC 数据库格式的文件。换句话说,程序具备直接打开 dBASE、FoxPro、Clipper、Pervasive、Paradox、Microsoft Access 及其他此类软件中设计的数据库文件和表所需的内置功能。安装 Crystal Reports 后即具备此功能。一旦将程序安装在系统中,就可以立即开始选择适当的文件以创建基于这些数据库之上的报表。这是一种连接速度最快的方式,但是如果直接通过 Crystal Reports 访问某个数据库,则报表只能使用这一种数据库类型。不创建新的报表,就无法切换到不同类型的数据库或表。
Ø ODBC 数据源:(Access,Excel,Infoxmix,OLE Db,Visual Foxpro,)
现在大多数常用的数据库管理系统都提供 ODBC 驱动程序,而且日益增多,因此 Crystal Reports 可以使用您拥有的任何数据类型。因为 ODBC 内置了很大的灵活性,所以可以在同一报表文件中使用不同的 ODBC 数据源。例如,可以使用 Oracle 数据源设计报表,以后当公司转换到 Microsoft SQL Server 时,则只需更改报表使用的 ODBC 数据源。通过 ODBC 将数据从数据库传递到应用程序涉及到很多层,因此出错几率变大,另外在能使用 ODBC 数据源之前,必须正确配置 ODBC 数据源并在 Odbc.ini 和 Odbcinst.ini 文件中设置它们。如果在一个系统上创建报表,而在另一个没有安装同一 ODBC 数据源的系统上打开此报表,则 Crystal Reports 无法连接到那些数据。
Ø OLE DB
OLE DB 是 Microsoft 开发的、在概念上类似于 ODBC 的数据库连接实体。OLE DB 是一种连接方法论,而不是一种数据库。与 ODBC 一样,它通过提供一个接口层,使得在其它数据库管理系统中创建的数据易于交换。OLE DB 要求使用 OLE DB 提供程序,此程序是相当于 ODBC 驱动程序的 OLE DB 程序 。 Crystal Reports 为 OLE DB 使用者提供 P2soledb.dll 文件,使得 OLE DB 可以与 OLE DB 提供程序通讯。
Ø Crystal SQL Designer 文件:(Crystal SQL Designer)
Crystal SQL Designer 是一个查询,它只是对数据库中一组特定数据的请求。数据被收集后,即存储为 Crystal SQL Designer 文件 (.QRY)。之后,可以象使用数据库表一样使用 Crystal SQL Designer 文件。从 SQL 数据库中收集的数据成为新的数据集,可以添加到报表中。但非常遗憾的告诉您,上面的安装文件安装后Crystal SQL Designer并没有被安装,所以此处点到为止。
Ø 字典
字典是结构化和简化的数据视图,可以为组织中使用 Crystal Reports 的某些人或所有人创建字典. 与某些强制用户通过数据分发元层访问数据的系统不同,字典是可选组件。用户仍然可以直接访问数据。字典只是提供完全的便利,没有任何限制。同样非常遗憾的告诉您,上面的安装文件安装后Crystal SQL Designer并没有被安装,所以此处点到为止。
在介绍完Crystal Reports 可以访问的五大类数据后,请允许我着重介绍一下SYBASE。在介绍Crystal Reports时,我曾经提过安装Crystal Reports时SYBASE的数据库驱动程序是需要手选的这个请大家注意,另外就是安装Crystal Reports这台电脑需要安装SYBASE客户端程序,同时设置正确的数据库连接。接下来我们就可以在Crystal Reports的数据库专家的创建新连接里找到SYBASE服务器这一项了,点击它后便可以进行水晶报表与指定的SYBASE数据库的连接设置了,输入正确的服务器名登陆名密码以及要访问的数据库,那么数据源便定义完毕。
接下来还要介绍一个很重的技巧—修改数据源。在一些特殊的情况下,比如我们定义好了报表的数据源,它是A服务器上的一个存储过程,但情况有变我们需要把数据源更改为另一个过程(此处仅借此情况为例,意指数据源的更改),但糟糕的是此时整个报表的所有字段的格式字体等都已经设置好,如果此刻要更改数据源怎么办?先说明一下想通过数据库专家重新选择新数据源是行不通的,您可以尝试.最糟糕的办法是重新做一张报表。其实Crystal Reports设置了一个这样的功能来完成这个任务,您可以点击菜单下的数据库->设置数据源位置来完成这个工作,非常简单方便,操作方法是先选中需要更新的旧的数据源描述然后选择新的数据源然后点更新即可,这个功能对不知道该操作的人来说是非常重要的,您不妨一试。
u 报表类型
我们在设计报表时,最好使用Crystal Reports的报表向导,它会按照不同类型的报表给以不同的指导,帮助您正确得设计出您想要的报表雏形,此处就不详细讲解报表的具体设计过程,下面仅针对于不同类别报表设计时的一些技巧予以提示共享.
Ø 交叉表
Crystal Reports把每个交叉表看作一个交叉表对象,所谓的交叉表对象很简单,它是由几部分组成的,包括:行,列,汇总字段,行总计,列总结以及总计.交叉表可以有多个行,多个列以及多个汇总字段, 如果需要您也可以在一个报表中插入多个“交叉表”对象,但“交叉表”对象必须插入报表页眉或报表页脚或者插入组页眉或组页脚中, 当然您可以将“交叉表”对象放在子报表中。当要引用来自其他报表中的结果时,这一点很有用.另外当交叉表的汇总字段有多个时,而且不同的汇总字段要按照不同的方法进行汇总,这时候交叉表对象的行总计和列总计以及总计就失去了作用,那么怎么办呢?我们可以直接在数据库中算好把他们呈现出来,而这里需要把交叉表本身的总计都隐藏掉,方法很简单右击交叉表对象选择交叉表专家,选择自定义样式标签,勾选抑制显示行总计,抑制显示列总计复选框即可,当然在此你也可以进行其它尝试,比如抑制显示空行抑制显示空列等等.其它的设置请参阅联机指南.
Ø 图表
Crystal Reports 使您可以在报表中包含复杂的、多彩的图表。任何时候都可以使用这些图表来增加报表的可用性. 您可以根据以下内容绘制图表: 汇总和小计字段, 详细资料、公式和运行总计字段, 交叉表汇总, OLAP 数据。通常在组级根据汇总和小计信息绘制图表。但是,根据所用数据类型,您可以为报表创建高级图表、交叉表图或 OLAP 网格图表
Ø 子报表
子报表是报表中的报表。创建子报表的过程与创建常规报表的过程相似。子报表有报表的大多数特性,包括它自己的记录选择条件。子报表与主报表之间的唯一区别是子报表多节报表是作为对象插入到主报表中;它不能独立存在(但可以将子报表另存为主报表),它可以放置在报表的任意一节内,整个子报表将在该节中打印, 它不能包含另一个子报表,也不要包含页眉或页脚节.使用子报表的情况很多比如: 将不相关的报表组合到单个报表中, 协调本无法链接的数据,在单个报表中显示相同数据的不同视图, 从在查阅字段上没有索引的字段中执行一对多查阅等等,您可以根据自己的实际需要进行设计
Ø 数据库专家
“数据库专家”提供了一个可在 Crystal Reports 中使用的所有数据源的集成树视图。使用“数据库专家”,您可以:
- 使用当前连接的数据源之一创建报表。
- 基于存储在 Crystal 储备库中的 SQL 命令创建报表。
- 基于数据源的自定义“收藏夹”列表(也由您在“数据库专家”中维护)创建报表。
- 基于最近访问过的数据源的列表(由“数据库专家”自动替您维护)创建报表。
- 通过连接到现有数据源(例如,位于本地的数据文件或已经建立的 ODBC 数据源)创建报表。
- 通过先创建新连接(例如,新的 ODBC 数据源或 OLE DB 文件数据链接)来创建报表。
- 查看有关某个数据库连接的信息,方法是右击该连接的图标,然后从快捷菜单中选择“属性”。
Ø 组专家
使用“组专家”可指定字段在报表中的分组方式。还可以使用该对话框重新定位组,以及编辑用于触发和对组进行排序的条件。值得一提的是如果需要将组数据保持在同一页,那么您可以在组专家下进行设置,使用组专家的选项您可以进行很多与分组相关的设置。
Ø 组排序专家
报表必须包含一个汇总值才能执行“组排序”。 使用“组排序专家”可标识最前或最后几组(例如,客户报表中客户最多/最少的省)。还可以标识最高或最低百分比。
Ø 选择专家
使用选择专家选择想包括在报表中的记录或组(如果不想全部包括在报表中),使用选择专家时,程序基于您在对话框中指定的设置自动生成记录或组选定公式,该专家使您得以设置相当复杂的选定条件,但若要对所生成的公式有更多的控制,请使用 “公式编辑器”对话框。
Ø 节专家
使用节专家格式化影响整个报表节的更改。可以插入、删除以及合并节,当然这些操作也可以通过鼠标直接完成。另外我们可以通过节专家对节属性进行设置,比如:抑制显示,延伸到后续节,新建节的位置,保持在一起等等,我们也可以通过设定不同的颜色标示不同的报表节,节专家在报表设计过程中会经常使用到
Ø 图表专家
使用图表专家你可以进行图表类型的选择,常用的条形图、折线图、面积图、饼图、圆环图以及甘特图等等。图表专家提供了四种布局,分别对应特定的数据集,它们是高级,组,交叉表以及OLAP. 当有多个图表值或在报表中没有分组和摘要字段时,请使用“高级”布局. 为了用“分组”布局创建图表,您必须至少有一个分组和用于该分组的摘要字段使用“交叉表”布局在交叉表对象上绘制图表。交叉表图表使用交叉表中的字段作为其条件和摘要字段. 使用 OLAP 布局在 OLAP 网格上绘制图表。OLAP 图表使用 OLAP 网格中的字段作为其条件和摘要字段
Ø 交叉表专家
从“插入”菜单中选择交叉表命令时,或者当选定一个现有交叉表,然后从“格式”或右击菜单中选择“交叉表专家”命令时,会出现该专家. “交叉表专家”中有三个选项卡:
“交叉表”选项卡包含创建交叉表所需的基本功能。可定义行、列以及汇总字段。也可直接从该选项卡创建组和公式. 使用“样式”选项卡可以选择交叉表或 OLAP 网格的预定义样式. 使用“自定义样式”选项卡可以用背景色、网格线和单元格边距格式化交叉表的网格
五. 程序
u 模式
Ø 拉模式(PULL)
在拉模型中,驱动程序将连接到数据库并根据需要将数据“拉”进来。使用这种模型时,与数据库的连接和为了获取数据而执行的 SQL 命令都同时由 Crystal Reports 本身处理,不需要开发人员编写代码。如果在运行时无须编写任何特殊代码,则使用拉模型。
图一:PULL模式
Ø 推模式(PUSH)
推模型需要开发人员编写代码以连接到数据库,执行 SQL 命令以创建与报表中的字段匹配的记录集或数据集,并且将该对象传递给报表。该方法使您可以将连接共享置入应用程序中,并在 Crystal Reports 收到数据之前先将数据筛选出来。在些这种情况下,通过使用连接共享以及限制记录集合的大小,可以使用报表性能最大化。
图二:PUSH模式
u 如何开始
Visual Studio.NET提供了两个控件来实现你对水晶报表的控制,它们是CrystalReportViewer控件和CrystalReportDocument控件.这里只简单演示如何在Asp.net中使用一个现成的水晶报表文件,其实水晶报表的主要功能
1) 从WebForm工具栏中拖动水晶报表查看器控件(Crystal Report Viewer)至.aspx页面中。
2) 调出水晶报表查看器控件的属性窗口
3) 点击[...]按钮查看"Data Binding"属性,并弹出了DataBinding窗口。
4) 从左边的"Bindable属性”区中选择“Report Source”
5) 选中"自定义绑定表达式"单选按钮,在右边的底部的窗口中指定.rpt文件的文件名和路径,例如:"C:\\ProgramFiles\\MicrosoftVisualStudio.NET\\CrystalReports\\Samples\\Reports\\General Business\\World Sales Report.rpt",然后确定
注意:文件"World Sales Report.rpt"文件是在VS.Net安装时创建的。如果你在安装过程中指定了其它目录,此时你最好确认一下路径的正确性。
6) 在Page_Load方法中调用DataBind方法。(代码为VB.Net)
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
DataBind()
End Sub
7) 保存并编译你的页面。 现在,你就有一个内嵌水晶报表的WebForm页面了。
u 相关问题汇总
下面详细讨论水晶报表在使用过程中肯定遇到的主要的问题以及解决办法。
Ø 报表打印
目前较低版本的Crystal Reports 不能实现网页直接打印,要实现网页打印我们只能采取其它的方式,目前主要有下面几种方法:
l 使用客户端浏览器打印
我们在IE浏览器下可以找到打印以及打印预览等所有有关打印的功能,但是这个打印会把网页上很多没用的东西一起打印出来,另外我们需要在我们自己编写的程序里控制这些功能,那么怎么办呢?我们需要使用一个ACTIVEX控件<OBJECT classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=0 id=WB width=0></OBJECT>这个Object 其实就是 IEWebBrowser 设定 Width 和 Height 以后,我们在界面上就看不到控件的形状了,然后,我们就可以使用这个object 实现我们选纸和预览的功能了.
WB.ExecWB(8,1) //打印设置
WB.ExecWB(7,1) //打印预览
WB.ExecWB(6,1) //打印
这里说明一点,要使用这个打印方法,我们必须另外设计一个页面,该页面上只有一个CrystalReportViewer控件,该控件用来呈现要打印的报表,而且我们必须通过设置CrystalReportViewer属性来控制该报表显示在一页上以及隐藏工具条等不需要打印的部分,经测试发现如果页数很多的报表不能使用该方法.
l 使用PDF
string Fname = null;//用来暂存水晶报表利用pdf文件进行打印时调用的临时文件
ExportOptions crExportOptions = new ExportOptions();
DiskFileDestinationOptions crDiskFileDestinationOptions = new DiskFileDestinationOptions();
Fname = "c:\\temp_cpt_print";
crDiskFileDestinationOptions.DiskFileName = Fname;
crExportOptions = crReportDocumentHere.ExportOptions;
crExportOptions.DestinationOptions = crDiskFileDestinationOptions;
crExportOptions.ExportDestinationType = ExportDestinationType.DiskFile;
crExportOptions.ExportFormatType = ExportFormatType.PortableDocFormat;
crReportDocumentHere.Export();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.WriteFile(Fname);
Response.Flush();
Response.Close();
System.IO.File.Delete(Fname);
l 导出打印
实际上就是将报表导出为某种类型文件然后进行打印,下面会详细介绍报表导出方法;
Ø 报表导出
水晶报表可以导出为WORD文档,PDF文档,EXECL文档, RichText文件以及相应得html文件,在到处过程中我们主要使用ReportDocument对象的Export()方法,具体代码请参考如下程序:
DiskFileDestinationOptions crDiskFileDestinationOptions=
new DiskFileDestinationOptions();
ExportOptions crExportOptions = crReportDocumentHere.ExportOptions;
stringExportPath= System.Configuration.ConfigurationSettings.AppSettings["Report_Export_Path"];
if(Directory.Exists(ExportPath)==false){
System.IO.Directory.CreateDirectory(ExportPath);
}
string sessionFile=ExportPath+Session.SessionID.ToString();
string extractName=string.Empty;
if (ExportFileType.SelectedItem.Text == "RichText文件 (RTF)")
{
//Export to RTF.
extractName=".rtf";
crDiskFileDestinationOptions.DiskFileName =sessionFile+extractName;
crExportOptions.ExportDestinationType = ExportDestinationType.DiskFile;
crExportOptions.ExportFormatType = ExportFormatType.RichText;
crExportOptions.DestinationOptions = crDiskFileDestinationOptions;
}
else if (ExportFileType.SelectedItem.Text == "PDF文件 (PDF)")
{
//Export to PDF
extractName=".pdf";
crDiskFileDestinationOptions.DiskFileName = sessionFile+extractName;
crExportOptions.DestinationOptions = crDiskFileDestinationOptions;
crExportOptions.ExportDestinationType = ExportDestinationType.DiskFile;
crExportOptions.ExportFormatType = ExportFormatType.PortableDocFormat;
}
else if (ExportFileType.SelectedItem.Text == "Word文件 (DOC)")
{
//Export to Word
extractName=".doc";
crDiskFileDestinationOptions.DiskFileName =sessionFile+extractName;
crExportOptions.ExportDestinationType = ExportDestinationType.DiskFile;
crExportOptions.ExportFormatType = ExportFormatType.WordForWindows;
crExportOptions.DestinationOptions = crDiskFileDestinationOptions;
}
else if (ExportFileType.SelectedItem.Text == "Excel文件 (XLS)")
{
//Export to Excel
extractName=".xls";
crDiskFileDestinationOptions.DiskFileName =sessionFile+extractName;
crExportOptions.ExportDestinationType = ExportDestinationType.DiskFile;
crExportOptions.ExportFormatType = ExportFormatType.Excel;
crExportOptions.DestinationOptions = crDiskFileDestinationOptions;
}
crReportDocumentHere.Export();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", @"attachment;filename="+HttpUtility.UrlEncode(crrntQuery.Title+extractName,System.Text.Encoding.UTF8));
Response.WriteFile(sessionFile+extractName);
Response.Flush();
Response.End();
System.IO.File.Delete(sessionFile+extractName);
我们发现使用9系列的水晶报表将报表导出为excel文件时,excel的表格线不能够自动导出生成,只能通过手工添加去处理,为了解决这个问题我们转么设计另一张导出报表已方便使用者添加格线,实属无奈之举.
Ø 参数传递
通过ReportDocument控件我们可以实现讲外部参数传入水晶报表中从而实现报表数据动态显示,具体实现请参考如下代码:
private void BuildReportViewerParameters(CrystalDecisions.Web.CrystalReportViewer rptViewer, Hashtable ParamTable)
{
//定义报表视图的参数的方法
ParameterFields ParamFields = new ParameterFields();
foreach (object key in ParamTable.Keys)
{
ParameterField ParamField = new ParameterField();
ParameterValues ParamValues = new ParameterValues();
ParameterDiscreteValue ParamValue = new ParameterDiscreteValue();
ParamValue.Value = ParamTable[key].ToString();
ParamValues.Add(ParamValue);
ParamField.ParameterFieldName = key.ToString();
ParamField.CurrentValues = ParamValues;
ParamFields.Add(ParamField);
}
rptViewer.ParameterFieldInfo = ParamFields;
}
private void BuildReportClassParameters(CrystalDecisions.CrystalReports.Engine.ReportClass rpt, Hashtable ParamTable)
{
//定义报表类的参数的方法
foreach (object key in ParamTable.Keys)
{
ParameterValues ParamValues = new ParameterValues();
ParameterDiscreteValue ParamValue = new ParameterDiscreteValue();
ParamValue.Value = ParamTable[key].ToString();
ParamValues.Add(ParamValue);
rpt.DataDefinition.ParameterFields[key.ToString()].ApplyCurrentValues(ParamValues);
}
}
protected void BuildReportParameters(CrystalDecisions.Web.CrystalReportViewer rpt,Hashtable ParamTable)
{
//定义报表参数的方法
ParameterFields ParamFields = new ParameterFields();
foreach(object key in ParamTable.Keys)
{
ParameterField ParamField;
ParameterValues ParamValues;
ParameterDiscreteValue ParamValue;
ParamField = new ParameterField();
ParamValues = new ParameterValues();
ParamValue = new ParameterDiscreteValue();
ParamValue.Value = (string)ParamTable[key];
ParamValues.Add(ParamValue);
ParamField.ParameterFieldName=(string)key;
ParamField.CurrentValues = ParamValues;
ParamFields.Add(ParamField);
}
rpt.ParameterFieldInfo = ParamFields;
}