前言 Crystal Report的功能性自不必说,虽说有时做一些比较有中国特色的报表有些困难,但是功能上应该还是挺强的。Crystal Report在VS/VS.NET中应用的文章已经很多了,RDC在VB中的效果也是相当不错,在VS.NET中甚至集成了Crystal Report,虽然不是全功能版,但是做一般的报表,应该是没有问题的,尤其在.net中做的报表,可以以WEB的方式呈现给User,也是相当不错的。但是有关在Delphi中使用Crystal Report的文章却很少,也许是Delphi中报表工具都是被QReport,FastReport,Rava,Report machine等这些工具霸占着。其实这些工具也是相当不错的,只是如果原本就对Crystal Report就比较熟悉的Delphi程序员来说,在Delphi中尝试来使用一下水晶报表也还是不错的,Business Object有发布VCL Component For CR ,虽然有些Bug,但是应该还是不错了。 使用步骤 1) 下载CrystalVCL:可以去BO的网站下载,下载网址: http://www.businessobjects.com/products/reporting/crystalreports/vcl/download.asp。目前官方网站有提供三个版本的VCL.CR9/CR10/CR XI,不过没有比较新版本的CR XI Release 2及2008的。有一点不爽的是在下载的时候要求提供注册号,正版的用户应该没有问题,不过其他的非官方网站应该也有提供下载。CR9的VCL有相当多的Bug,需要自己去修改它的pas文件源代码。CR10未测试,以下的资料是CR XI的。比较好的一点是此VCL有提供源码,如果发现有Bug,可以自己作修改。可能是开发此控件的人delphi功力还不够,呵呵!还有一种是直接使用Crystal Report的ActiveX,不过不建议使用这种方法。 2) 安装VCL:安装VCL的过程非常简单,一般在下载的文件里面都有Readme的说明,按照步骤来做就好了。简单来说,就是首先在Delphi的library path里面增加CRVCL的路径,然后在Delphi里面打开dcl7cr11这个package(不同版本的VCL文件名称会有不同),Compile后install就可以了。安装完后,会在Data Access中产生两个控件:Crpe跟CrpeDS。Crpe封装了CR的大部分功能,CrpeDS是将Delphi的DataSet传递给Crpe来进行报表的显示,主要用于Push模式,如果是pull模式,则Crpe就足够了下面会详细说明。 3) Pull模式编程:所谓Pull模式,简单来说就是rpt文件中会自动从datasource中抓取数据,Crpe就把数据认证信息跟参数等信息传递过去就可以了。(CR可以连接大部分的数据源,这点不用担心,甚至于非传统的数据库,比如Windows server的AD信息跟Outlook的信息等)。报表要提前设计好,报表的设计方法,这里不再赘述,有兴趣的可以加我QQ交流经验。也可以参考相关的书籍或者CR的在线帮助。以下的代码供参考: Screen.Cursor:=crHourGlass; Crpe1.Clear; Crpe1.ReportName:='Test.rpt'; Crpe1.Connect.ServerName:='localhost'; Crpe1.Connect.UserID:='sa'; Crpe1.Connect.Password:='sa'; Crpe1.Connect.DatabaseName:='Test'; Crpe1.Connect.Propagate:=True; Crpe1.DiscardSavedData; Crpe1.ProgressDialog:=True; Crpe1.Output:=ToWindow; Crpe1.WindowButtonBar.GroupTree:=True; Crpe1.WindowButtonBar.ZoomCtl:=True; Crpe1.WindowButtonBar.PrintSetupBtn:=True; Crpe1.WindowState:=wsMaximized; Crpe1.WindowStyle.Title:='测试水晶报表预览窗口'; Crpe1.WindowEvents:=True; ……………………………… //Crpe1.wOnExportBtnClick:=CrpewOnExportBtnClick; Crpe1.ParamFields[0].CurrentValue:='1'; Crpe1.Execute; Screen.Cursor:=crDefault; 4) Push模式编程:所谓Push模式,简单来说就是DataSet由前端组织,然后将Data Push给CR,而不是由CR直接连接数据库来抓取数据,此方法比较灵活,可以使用Delphi中功能丰富的dataset控件来组织、过滤数据,delphi中的dataset控件,比如Table、Query、DataSet等都是可以的,甚至于内存表也没有问题,比如ClientData,或者是第三方的内存表控件都可以,这就大大增加了报表的自由度,可以将Delphi强大的数据存取功能跟CR的功能组合起来使用。这里面有一个问题就是,没有了数据源,在设计报表的时候数据库的连接要如何选择?这里提供一个方法:你可以使用一个“仅字段定义”文件即可。文件大概类似如下的模样: f01 String 10 f03 String 40 f40 date f50 number fcuser string 10 保存为.ttx为扩展名的文本文件即可,ttx中的每一行就代表了每一个字段名称、长度、类型,此文件可以在CR的开发环境中产生,也可以自已使用notepad来制作。然后在CR的新建连接中选择“仅字段定义”即可,指定为刚才产生的文件,如果以后有修改此ttx文件,直接在CR的菜单中选在验证数据库即可添加或者删除字段。参考代码如下: AdoQuery1.Active:=False; AdoQuery1.SQL.Clear; AdoQuery1.SQL.Add(Edit1.Text); Try AdoQuery1.Active:=True; Except ShowMessage('打开数据集失败,请确认输入的SQL语法是否正确!'); Exit; end; Screen.Cursor:=crHourGlass; Crpe2.Clear; Crpe2.ReportName:='Test_TTX.rpt'; Crpe2.DiscardSavedData; Crpe2.ProgressDialog:=True; Crpe2.Output:=ToWindow; Crpe2.WindowButtonBar.GroupTree:=True; Crpe2.WindowButtonBar.ZoomCtl:=True; Crpe2.WindowButtonBar.PrintSetupBtn:=True; Crpe2.WindowState:=wsMaximized; Crpe2.WindowStyle.Title:='测试水晶报表预览窗口'; Crpe2.WindowEvents:=True; //Crpe2.wOnExportBtnClick:=CrpewOnExportBtnClick; ……………………………………………. Crpe2.Tables[0].DataPointer := CrpeDS2.DataPointer; Crpe2.ParamFields[0].CurrentValue:='2'; Crpe2.Execute; Screen.Cursor:=crDefault; 主要的代码就两句: Crpe2.Tables[0].DataPointer := CrpeDS2.DataPointer; Crpe2.Execute; 前提是CrpeDS的Dataset控件的属性要设置为你所要使用数据来源控件,此示例代码中是:AdoQuery1 。如果要使用内存表,可以参考如下的代码: Screen.Cursor:=crHourGlass; ClientDataSet1.Close; With ClientDataSet1.FieldDefs do Begin Clear; Add('f01',ftString,5,False); Add('f02',ftString,40,False); Add('f03',ftString,40,False); Add('f04',ftString,20,False); Add('f05',ftString,40,False); End; ClientDataSet1.CreateDataSet; ClientDataset1.Open; AdoDataSet1.First; While not AdoDataSet1.Eof do Begin ClientDataSet1.Append; ClientDataSet1.FieldByName('f01').AsString := AdoDataSet1.FieldByName('f01').AsString; ClientDataSet1.FieldByName('f02').AsString := AdoDataSet1.FieldByName('f02').AsString; ClientDataSet1.FieldByName('f03').AsString := AdoDataSet1.FieldByName('f03').AsString; ClientDataSet1.FieldByName('f04').AsString := AdoDataSet1.FieldByName('f04').AsString; ClientDataSet1.FieldByName('f05').AsString := AdoDataSet1.FieldByName('f05').AsString; ClientDataSet1.Post; AdoDataSet1.Next; End; AdoDataSet1.Close; Crpe4.Clear; Crpe4.ReportName:='Test_TTX.rpt'; Crpe4.DiscardSavedData; Crpe4.ProgressDialog:=True; Crpe4.Output:=ToWindow; Crpe4.WindowButtonBar.GroupTree:=True; Crpe4.WindowButtonBar.ZoomCtl:=True; Crpe4.WindowButtonBar.PrintSetupBtn:=True; Crpe4.WindowState:=wsMaximized; Crpe4.WindowStyle.Title:='测试水晶报表预览窗口'; Crpe4.WindowEvents:=True; //Crpe4.wOnExportBtnClick:=CrpewOnExportBtnClick; ……………………………………….. CrpeDS4.DataSet:=ClientDataSet1; Crpe4.Tables[0].DataPointer := CrpeDS4.DataPointer; Crpe4.ParamFields[0].CurrentValue:='2'; Crpe4.Execute; Screen.Cursor:=crDefault; 内存表的数据可以来源于xml等,即可以不使用数据库引擎,在发布程序的时候比较方便,不用将数据引擎打包发布。 5) 程序分发:程序发布可以去官方网站下载合并模块Merge Modules,此模块很容易在网上找到。然后使用wise或者installshield等打包工具将此合并模块加入程序包的project中并做一些简单的设置即可,installshield等工具中甚至集成了CR的Merge Modules,直接选择对应的版本即可。 后记 以上代码是在delphi7+SQL Server+WindowsXP Professional中测试通过,水晶报表还是挺不错的报表工具,有兴趣的不妨一试。不过对于自定义纸张的报表,CR一直没有很好的解决方案,确实遗憾。