深入QuickReport(三)

本文介绍了QuickReport报表设计中的高级技巧,包括报表的连接及保存、自定义预览窗口、组件的动态设置等内容,帮助开发者深入掌握QuickReport的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

第三部分:报表中的其他问题

 

 

通过前两部分的学习,我想你对QuickRep已经有了一定的掌握,在这部分我们对报表设计中的其他一些问题做一下简单介绍,也许这些你并不常用,但同样这些内容对于我们学习QuickRep还是有很大益处的。

此部分内容都以例程的形式讲解,为了保持文章的完整性,例子的编号接上部分。

 

例五、报表的连接及保存

 

通过上面的例子,你也许会动手做了几个报表,有时你一定会想把其中的一些报表连接起来,组成一个综合报表,并作为整体来操作。在BCB中实现这一点并不难,我们这时要用到TQRCompositeReport组件。它提供了一个OnAddReprots事件,在创建报表时将触发这个事件,因此我们只要在这个事件中用Add方法将需要连接在一起的报表添加到该组件的事件中就可以了。下面给出一个示例程序段,这是把两个报表添加到综合报表中的,代码如下:

void __fastcall TForm1::QRCompositeReportAddReports(TObject *Sender)

{

((TQRCompositeReport*)Sender)->Reports->Add(Form2->QuickRep1);//添加第一个报表

((TQRCompositeReport*)Sender)->Reports->Add(Form3->QuickRep1);//添加第二个报表

}

做好的报表我们一定都想保存起来,保存的文件格式有:文本格式文件(TXT),组件TQRTextFilter;超文本格式文件(HTML/HTM),组件TQRHTMLFilder;逗号分隔文件(CSV),组件TQRCSVFilter;以及报表文件。保存前三种格式文件需要调用ExportToFilter方法,而直接保存报表组件,则只需用Save。这个例子中我们放了一个TSaveDialog对话框和QuickReport组件页中的TQRTextFilter、TQRHTMLFilder、TQRCSVFilter三个组件。完整的代码如下:

void __fastcall TForm1:: SaveReportClick(TObject *Sender)

{

        AnsiString FileExt;

        //  打开保存文件对话框获得文件名

        if(SaveDialog1->Execute())

        {

                //  获得文件后缀

                FileExt = AnsiUpperCase(ExtractFileExt(SaveDialog1->FileName));

                //  输出Html超文本文件

                if((FileExt == ".HTML") || (FileExt == ".HTM"))

                        QuickRep1->ExportToFilter(new TQRHTMLDocumentFilter(SaveDialog1->FileName));

                //  输出txt文本文件

                else if(FileExt == ".TXT")

                        QuickRep1->ExportToFilter(new TQRAsciiExportFilter(SaveDialog1->FileName));

                //  输出CSV文件

                else if(FileExt == ".CSV")

                        QuickRep1->ExportToFilter(new TQRCommaSeparatedFilter(SaveDialog1->FileName));

                //  输出报表文件

                else

                {

                        QuickRep1->QRPrinter->Save(SaveDialog1->FileName);

                }

        }

}

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

 

 

例六、自定义报表预览窗口

 

QuickReport的报表预览功能总是不能达到令人满意的效果,因此,我们有必要自定义快速报表的预览窗口,以达到完美的设计要求。

1)设置预览窗口

新建工程,在Form1窗体上添加一个ToolBar控件,并在其上添加以下按钮:“调入报表”、“打印”、“打印设置”、 “上一页” 、“下一页”、“放大”、“缩小”和“关闭”。在Form1窗体上添加一个StatusBar,双击该组件,在编辑器中插入三项,在第三个项中显示页面信息。在Form1窗体上添加一个TQRPreview控件,对齐方式设为alClient,Form1窗体的外观如图1所示:

 

 

再新建一个窗体,设其Name为Form2, 在该窗体上添加TQuickRep控件,设其Name为QuickRep1,其PrinterSetting中的Units属性设为mm(以毫米为计量单位),然后建立报表。

2)编程实现

(1)在Form2上选择QuickRep1,在其事件中选择OnPreview,输入以下代码:

#include <vcl.h>

#pragma hdrstop

 

#include "Unit2.h"

#include "Unit1.h"//调用Form1的内容

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

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm2 *Form2;

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

__fastcall TForm2::TForm2(TComponent* Owner)

        : TForm(Owner)

{

}

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

void __fastcall TForm2::QuickRepPreview(TObject *Sender)

{

    Form1->QRPreview1->QRPrinter=Form2->QuickRep1->QRPrinter;//最为关键的一步

}

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

 

(2)为Form1中的各功能按钮的OnClick事件添加如下代码:

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

#include "Unit2.h"//调用Form2的内容

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

#pragma package(smart_init)

#pragma resource "*.dfm"

 

TForm1 *Form1;

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

__fastcall TForm1::TForm1(TComponent* Owner)

        : TForm(Owner)

{

}

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

//调入报表

void __fastcall TForm1::QRLoadClick(TObject *Sender)

{

    Form2->QuickRep1->Prepare(); //不加入该句,下一句的共几页将不能正确出现

    StatusBar1->Panels->Items[2]->Text="第"+IntToStr(Form1->QRPreview1->PageNumber)+"页"+"共" + IntToStr(Form2->QuickRep1->PageNumber)+"页";

    Form2->QuickRep1->Preview();//显示页面的信息

}

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

//打印报表

void __fastcall TForm1::PrintClilck(TObject *Sender)

{

     Form2->QuickRep1->Print();

}

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

//打印设置

void __fastcall TForm1::PrintSetupClick(TObject *Sender)

{

Form2->QuickRep1->PrinterSetup();

Form2->QuickRep1->Print();//不加这句可只能设置,不能打印,在我的电脑上测试是这样的

}

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

//上一页

void __fastcall TForm1::PageUpClick(TObject *Sender)

{

    if(QRPreview1->PageNumber>1)

     QRPreview1->PageNumber--;

     StatusBar1->Panels->Items[2]->Text="第"+IntToStr(Form1->QRPreview1->PageNumber)+"页"+"共" +IntToStr(Form2->QuickRep1->PageNumber)+"页";

}

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

//下一页

void __fastcall TForm1::PageDownClick(TObject *Sender)

{

    if(QRPreview1->PageNumber < Form2->QuickRep1->PageNumber)

     QRPreview1->PageNumber++;

     StatusBar1->Panels->Items[2]->Text="第"+IntToStr(Form1->QRPreview1->PageNumber)+"页"+"共" +IntToStr(Form2->QuickRep1->PageNumber)+"页";

}

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

//报表放大

void __fastcall TForm1::ZoomInClick(TObject *Sender)

{

    if(QRPreview1->Zoom<200)

    QRPreview1->Zoom+=5;

}

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

//报表缩小

void __fastcall TForm1::ZoomOutClick(TObject *Sender)

{

       if(QRPreview1->Zoom>5)

       QRPreview1->Zoom-=5;

}

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

//程序关闭

void __fastcall TForm1::CloseClick(TObject *Sender)

{

         Close();

}

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

 

上面只是做了一个简单的设计,你完全可以把它做得功能更强大、外观更漂亮一些。

 

例七、QR组件的动态设置及探讨

BCB中提供了大量的VCL组件,有时难免要在程序中动态创建组件,VCL是用Object Pascal写的,所以VCL类的对象我们只能在堆中创建。
如创建一个TQRLable对象,我们可以这样来创建:
  TQRLable *MyQRLable= new TQRLable(From1);
  即写成如下程式:

类名  *对象名=new 类名(…);
  注意:()里面可以是你已创建的该类对象的父类名字、工程的名字、NULL或this。但最好是对象的父类名。
  例:动态生成TQRLable组件
  我们先在窗体(Form1)上,放上一个TQuickRep,并在其上放一个Band。在Form1窗体中按钮Button1的单击事件中写上如下代码:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   TQRLable *MyQRLable= new TQRLable(From1);
   MyQRLable ->Parent=Band1;//最为关键的一句,否则你将看不到什么,但编译却是正确的
   MyQRLable ->Top=10;
   MyQRLable ->Left=38;
   MyQRLable ->Height=25;
   MyQRLable ->Width=100;
   MyQRLable ->Caption="I'm MyQRLable!";
}
        通过这个例子我们应该清楚的看出动态创建QR组件的几个重要步骤:
  1)要一个空间(内存);// TQRLable *MyQRLable= new TQRLable(From1);
  2)指定其父组件,说直接了就是为我们要创建的这个对象指定一个容器;//     MyQRLable ->Parent=Band1; 
  3)指定组件要出现在父组件的哪个位置;// MyQRLable ->Top=10; MyQRLable ->Left=38; MyQRLable ->Height=25; MyQRLable ->Width=100; 
  4)其它重要属性。//   MyQRLable ->Caption="I'm MyQRLable!";
         注意上面的步骤不能任意安排,否则你的程序会出笑话的。
  在动态生成非宝兰VCL原有的组件时要加上对应的头文件。我们要动态生成报表组件时一定要加入: 
        #include  “Qrctrls.hpp”//若还有问题,你还要加入:
        #include “QuickRpt.hpp”
        另外由于BCB对内存管理或与系统、硬件的冲突,你的动态创建程序也许一点错误都没有,但就是编译不了;有时也许第一次通过了,第二次一样的程序却通过不了,出现这样那样的提示,最简单的办法就是注销一下系统,再试一下,多数就能解决了。

既然这样的动态产生组件会出现很多不可遇见的问题 ,那我们还有没有更好的办法来实现类似的功能呢?有,答案是一定的。

我们可以在TQuickRep中把所有组件都放置好,各区段组件,可视化组件都放在应该放的位置上,只是一些特定的属性我们先不给出,而通过程序给出,这样就可以仿制动态创建组件的方法来动态产生报表。说简单了就是事先把组件都准备好了,用的时候拿出来,不用的,不给定关键属性,即用属性废掉它,让它根本就不起作用。

例:动态设置QRDBText的属性值

void __fastcall TForm1::Button1Click(TObject *Sender)

{

   QRDBText1->DataSet=Table1;

   QRDBText1->DataField="AREA";//改成双引号后,一切OKJ

   QuickRep1->Preview();

   Table1->Close();

}

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

void __fastcall TForm1::Button1Click(TObject *Sender)

{

   QRDBText1->DataSet=Table1;

   QRDBText1->DataField=Table1->Fields->Fields[3]->FieldName;

   QuickRep1->Preview();

}

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

注意:下面的程序是错误的

void __fastcall TForm1::Button1Click(TObject *Sender)

{

   QRDBText1->DataSet=Table1;

   QRDBText1->DataField=Table1->FieldValues["AREA"];//注意这将得不到你想得到的内容,因为他不是把字段名给了DataField

   QuickRep1->Preview();

}

 

单就一个QuickReport动态生成报表,我想不是三言两语就能说完的,单独成文也不为过,好在我也把动态生成报表的一些常见问题都说出来了,解决之道上面也提了,并且还给出了几个例子,通过这些介绍,你要是有精力的话一定会做出一个不出问题的动态生成报表系统。

 

以上程序均在XP系统、BCB6、EPSON C43UX下编译通过。

 

结束语:写到这里我相信多数的读者对QuickReport应该有了一个比较全面、深入的了解了。但当我仔细读了一遍这篇文章后,发现还有很多内容没有写出来,让我意识到想在一篇文章里把QuickReport全都写出来,还真有些困难,这样也好,留点以后再写,让不闲下来做什么呢J

其实说简单了,QuickReport并不难学,只是有时我们把她孤立起来看,而没有想到, 其实QuickReport就是那么回事,她在BCB上出现也不是一天两天了,现在的她可以说早已完全融入到VCL组件中去了。所以说,想真正学通QuickReport,关键还是取决于我们对VCL的掌握程度。

 

一、 简单了解各控件功能   以下是各控件最简单的使用功能,其他功能依具体的实现而介绍。  TquickRep:带有坐标,作为其他报表控件(如TQRBand)的容器,它的Band属性可以自动添加各种类型的TQRBand.   TQRLabel:打印静态的文本(即不是根据数据库值来改变的),作用象Tlabel , Caption的内容就打印出来的内容。   TQRDBText:打印数据库字段值,一个值一行。作用象TDBText.把它的DataSet , DataField分别赋予Table1,Company时,将打印Table1所指向的表的Company字段的内容。   TQRSysData:打印系统信息如时间,页码,报表头等。   TQRMemo:非常象TQRLabel,只是它可以打印多行,也是打印静态数据。   TQRRichText:打印RichText格式,能够连接到一个Form上的RichEdit控件并打印它的内容,不过必须是32位版本的。   TQRShape:打印方框、圆和垂直、水平线。   TQRImage:打印静态的图片,包括(BMP,WMF,ICON).   TQRDBImage:从数据库接收图片。   TQRBand:用来确定报表的不同位置应该显示什么内容,它上面可以放控件(参见二)。   TQRGoups:Groups可以不限级别的组操作。当你连接了几个datasets到报表时可以通过Groups成组的对dataset进行操作。   二、 报表的控件摆放循序   出现在所有页上的标题(PageHeader)   标题(只有首页才有)(Title)   所有列的标题(ColumnHeader)   记录的内容,一个字段一列(Detail)   摘要(最后一页才有)(Summary)   出现在所有页上的页脚(PageFooter)   这些根据设置不同的Band(不是控件,一种类型而已,在其上面可以放其他控件)来定位。总共有六种Band。   、 一个简单的例子   这个例子制作打印一张表的部分字段名及该字段数据内容的报表。   建立一个新project   放一个TTable到Form上,DatabaseName设为BCDEMOS,TableName指向Customer表,Active设为true.   放一个TquickRep控件在Form上,DataSet属性为Table1.(即要显示上边Table1所指向的表的内)。   展开TquickRep的Bands属性,设HasDetail为true,这时自动增加个detail band(一个TQRBand控件,故也可以直接放一个TQRBand控件,BandType属性设为detail就行了)。   放一个TQRDBText控件在detail band上面,设DataSet指向Table1,DataField指向Company。第四步是设置在报表的什么位置显示什么类型的数据,而TQRDBText则具体实现。   选TquickRep控件,按右键,选择”Preview”预览,应该看到表Customer的字段Company的所有字段值。  到这一个简单的例子就OK了,程序实现预览及利用TQRuickRep自带的打印功能只须在Form中加一个按钮,它的OnClick事件为:QuickRep1->Preview();  四、一个使用TQRGoups、TQRExpr控件的报表   该报表先列出州名,接着列出该州的所有公司及公司总数,一个州列完后空一行(groups中断),列出新的州名,接着列新州下的所有公司,没有填州名的公司统一列在Unknown state下面。  建立一个新project。   放一个Tquery在Tquickrep上,其SQL属性为:select * from customer order by State,Company;(即根据州、公司排序),DatabaseName为BCDMome,Active为true.   放一个TquickRep控件在Form1上,DataSet为Tquery1.   放一个TQRGroups控件在TquickRep上,这时默认为group header。(任何时候当group中断或更高级别的group中断,这个header都将打印出来,如果有表达式,根据表达式的值显示内容。)接着添加一个group footer band,添加时,放一个TQRBand控件在报表上,连接TQRGroups的FooterBand属性到这个QRBand,这时这个新建的TQRBand就成为Group Footer. (TQRGroup的一个重要特性是表达式,任何时候当表达式的值变时Group都将中断,如表达式是按省列出城市名,当前列出广东省,当属于该省的城市列完后,表达式值改变,这时Group中断,接着显示其他省的城市名。)TQRGroups的Expression属性设为Query1.State(根据不同的州来中断)。   放一个TQRBand控件在报表上,BandType为rbDetail.   放一个TQRExpr控件在group header上面,其Expression属性为:if(State<>’’,State,’Unknown state’),即如果公司的州没填,就归入Unknown state,否则归入State.   放个TQRDBText在Detail上,他们的DataSet都指向Query1,DataField分别指向Company,Contact,Phone.   在放一个TQRExpr控件在group Footer上面,Expression为’Customers in’+State+’:’+Str(Count) 作用是在每个州的公司列完后显示该州总共有多少个公司。   按右键选预览,应该看到不同的州名及其公司和公司公司总数。  五、QuickReport 条件式列印   可以直接在 TQuickReport 的 OnFilter 事件中写明条件判断,OnFilter事件的引数中有一个以 var 宣告的 PrintRecord 布林型态变数,将这个变数设为 True(预设值), 该笔记录便会印出;反之, 设为False,就不印出这笔记录. procedure TForm1.QuickReport1Filter(var PrintRecord: Boolean); begin PrintRecord := False; if YourTable.FieldByName(‘WantedField‘).AsInteger <= 100 then Exit; if YourTable.FieldByName(‘WantedField‘).AsInteger >= 150 then Exit; PrintRecord := True;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值