副标题#e#
在各类打点信息系统应用中,需要发生大量的报表,凡是的做法是由编程人员一个个手工建造,事情效率较低;别的,用户但愿可以或许将在应用措施里查询获得的功效生成报表以便打印。为了办理以上两种问题,本文操作动态生成技能实现了快速自动发生报表,答允用户手工对报表举办修饰,并将实现进程封装成一个类。
1.设计思路
利用过C++ Builder或Delphi的编程人员知道,有一个TDBGrid控件,它能以表格的形式显示和操纵用户查询的数据记录;而要建造一个可供打印的报表,则需要利用TQuickRep控件,在它上面增加TQRLabel、TQRDBText、TQRShape等控件,配置它们对应的数据集、数据字段等属性,然后编排它们的位置,以表格或其它名目显示出来供预览和打印,这是一个很繁琐的进程。有时,用户但愿能将查询出来的显示在TDBGrid控件的数据打印出来,凭据以往的做法,就需要由编程人员凭据TDBGrid的显示内容手工设计报表。在这里,本文操作动态生成技能,读出TDBGrid的有关显示信息,在TQuickRep控件里动态生成相应的TQRLabel、TQRDBText、TQRShape等控件,配置各字段的标题和数据以及表格支解条。这是完全可行的,因为在C++ Builder里所有的控件都可以由措施动态生成,不只仅是在设计阶段才发生的。别的,假如用户对发生的报表表格机关不太满足,本文提供了接口利用户可对报表举办手工调解,调解表格的高度、宽度等机关,实现用户对报表的必然水平的定制。
操作C++的封装性特点,将自动发生并定制报表的实现封装成一个新类TGridPrint,对外提供编程人员体贴的公用接口,屏蔽了内部信息和详细实现,浮现了面向工具的设计思想,为编程人员带来利便。编程人员还可以在它基本长进一步扩充成果。这样设计的新类减轻了编程人员的事情量,同时为用户提供了定制报表的接口,提高了报表的质量和用户参加的努力性。
#p#副标题#e#
2.实现进程
自动发生并定制报表的实现进程包罗自动发生和定制两部门。新类的界说和实现别离在GridPrint.h GridPrint.cpp文件里,另包括3个文件RepRst.h、RepRst.cpp、RepRst.dfm,它们是已发生的一个窗口FrmRepRst,在它内里已增加一个TQuickRep控件,它的属性Bands的各子属性的值全为true。
2.1 自动发生报表
先界说一个暗示表格某一列信息的布局,在报内外一列有牢靠标题和显示的数据文本两种信息,为了能画出表格,每一列牢靠标题栏和数据栏右边别离增加一个脱离条。在类TGridPrint的结构函数里,先按照传入的TQuickRep *pSrcQuickRep(报表指针),TDBGrid * pSrcDBGrid(数据表格指针),TQRBand *SrcTitleBand1(报表中的总标题栏指针), TQRBand *SrcColumnHeaderBand1(报表中的字段标题栏指针),TQRBand * SrcDetailBand1(报表中的数据栏指针)参数配置类的私有变量。再动态生成并配置总标题文本、字段标题栏矩形框、数据栏矩形框的属性。然后通过一个轮回,读出TDBGrid中各字段的标题和数据信息,动态生成报表中各字段的标题标签控件、数据文本控件以及对应的表格支解竖条控件。在类的析构函数里,删除所有由结构函数动态生成的工具。类的打印预览函数实现报表的打印预览成果。其它的函数说明略。
自动生成报表类的界说(GridPrint.h)
#include <DBGrids.hpp> //包括的相关头文件
#include <Db.hpp>
#include <Printers.hpp>
#include <QuickRpt.hpp>
#include <Qrctrls.hpp>
typedef struct tagFieldType{ //暗示表格某一列信息的布局
AnsiString sTitle; //字段标题名称
int iWidth; //表格单位的宽度
TQRLabel *pLabel; //字段标题控件
TQRDBText *pDBText; //显示的数据控件
TQRShape *pShapeTitle, *pShapeData; //字段标题和数据的表格脱离条
} NEWFIELDTYPE;
class TGridPrint{
public:
TGridPrint(TQuickRep *pSrcQuickRep,TDBGrid * pSrcDBGrid,TQRBand *SrcTitleBand1,
TQRBand *SrcColumnHeaderBand1,TQRBand * SrcDetailBand1); //结构函数
~TGridPrint(); //析构函数
void DoPreview(); //报表的打印预览
void SetPrntTitle(AnsiString sTitle); //手工配置表格的总标题
void SetColumnsWidth(int *ColumnsWidth); //手工配置表格各列宽度
void SetHeadRectHeight(int iHeight); //手工配置字段标题行的高度
void SetDetailRectHeight(int iHeight); //手工配置数据行的高度
private:
TDBGrid * pDBGrid; //将要显示的DBGrid
TDataSet * pDataSet; //DBGrid对应数据集
TQuickRep * pQuickRep; //报表控件
TQRBand * TitleBand1; //报表的总标题栏
TQRBand * ColumnHeaderBand1; //报表的字段标题栏
TQRBand * DetailBand1; //报表的数据栏
TQRLabel * pTitleLabel; //总标题控件
TQRShape * pHeadRect, * pDetailRect; //整个字段标题栏、数据栏的表格矩形控件
int iHeadRectHeight, iDetailRectHeight; //对应表格矩形框的高度,它们宽度沟通
int _iTotalWidth; //整个表格的总宽度
int _iIntClearance; //表格内部数据列到左表格的间隔
int _iFieldCount; //将要打印的字段数目
NEWFIELDTYPE _arrayFieldType[40]; //支持到40个字段的打印
void AutoAdjustColumnsWidth(); //措施自动调解各列宽度
};
类的主要公用要领的实现(GridPrint.cpp)
#p#分页标题#e#
TGridPrint::TGridPrint(TQuickRep * pSrcQuickRep,TDBGrid * pSrcDBGrid,TQRBand *SrcTitleBand1, TQRBand *SrcColumnHeaderBand1,TQRBand * SrcDetailBand1) //结构函数
{ int i,PreLeft;
pQuickRep = pSrcQuickRep; //按照传入参数配置私有变量
pDBGrid = pSrcDBGrid;
pDataSet = pDBGrid->DataSource->DataSet;
pQuickRep->DataSet = pDataSet;
TitleBand1 = SrcTitleBand1;
ColumnHeaderBand1 = SrcColumnHeaderBand1;
DetailBand1= SrcDetailBand1;
PTitleLabel = new TQRLabel(pQuickRep); //生成并配置总标题标签的属性
pTitleLabel->Parent = TitleBand1;
pTitleLabel->Caption = "报表标题";
pTitleLabel->Left= (TitleBand1->Width - pTitleLabel->Width)/2;
memset(_arrayFieldType,0,sizeof(NEWFIELDTYPE)*40);
_iTotalWidth=0; //计较出表格各列单位宽度和整个表格的总宽度
for(i=0; i< pDBGrid->FieldCount;i++)
{ _arrayFieldType[i].iWidth= pDBGrid->Columns->Items[i]->Width;
_iTotalWidth += _arrayFieldType[i].iWidth; }
if(_iTotalWidth > TitleBand1->Width)
{ //假如原DBGird各列宽度和大于总标题栏宽度,就调解各列宽度
_iTotalWidth= TitleBand1->Width;
AutoAdjustColumnsWidth(); }
PreLeft= ( TitleBand1->Width - _iTotalWidth)/2; //使整个表格居中
pHeadRect= new TQRShape(pSrcQuickRep); //生成并配置字段标题栏的矩形框
pHeadRect->Parent= ColumnHeaderBand1;
pHeadRect->Left = PreLeft; pHeadRect->Top = 0;
pHeadRect->Width = _iTotalWidth; pHeadRect->Height= pHeadRect->Parent->Height;
pDetailRect= new TQRShape(pSrcQuickRep); //生成配置数据行的矩形框
pDetailRect->Parent= DetailBand1;
pDetailRect->Left = PreLeft; pDetailRect->Top = -1;
pDetailRect->Width = _iTotalWidth; pDetailRect->Height= pDetailRect->Parent->Height+1 ;
_iIntClearance= 1;
_iFieldCount= pDBGrid->FieldCount; //配置表格总列数
for(i=0; i< _iFieldCount;i++) //动态生成各字段
{ //该字段的牢靠标题栏
_arrayFieldType[i].pLabel= new TQRLabel(pQuickRep); //标题控件
_arrayFieldType[i].pLabel->Parent= ColumnHeaderBand1;
//字段标题名称
_arrayFieldType[i].pLabel->Caption= pDBGrid->Columns->Items[i]->Title->Caption;
//字段标题的字体
_arrayFieldType[i].pLabel->Font= pDBGrid->Columns->Items[i]->Title->Font;
_arrayFieldType[i].pLabel->Alignment=
pDBGrid->Columns->Items[i]->Title->Alignment; //对齐方法
_arrayFieldType[i].pLabel->Left = PreLeft+_iIntClearance;
_arrayFieldType[i].pLabel->Width = _arrayFieldType[i].iWidth-2*_iIntClearance;
_arrayFieldType[i].pLabel->Height= _arrayFieldType[i].pLabel->Font->Height;
_arrayFieldType[i].pLabel->Top=
pHeadRect->Top+(pHeadRect->Height+_arrayFieldType[i].pLabel->Height)/2;
_arrayFieldType[i].pShapeTitle= new TQRShape(pQuickRep); //该字段右边的脱离竖条
_arrayFieldType[i].pShapeTitle->Parent= ColumnHeaderBand1;
_arrayFieldType[i].pShapeTitle->Left = PreLeft + _arrayFieldType[i].iWidth;
_arrayFieldType[i].pShapeTitle->Top = 0;
_arrayFieldType[i].pShapeTitle->Width= 1;
if( i == pDBGrid->FieldCount-1) //最后一列的脱离竖条宽度为0
_arrayFieldType[i].pShapeTitle->Width= 0;
_arrayFieldType[i].pShapeTitle->Height=_arrayFieldType[i].pShapeTitle->Parent->Height;
//显示的数据栏
_arrayFieldType[i].pDBText= new TQRDBText(pQuickRep); //该字段对应的文本控件
_arrayFieldType[i].pDBText->Parent = DetailBand1;
_arrayFieldType[i].pDBText->DataSet = pDataSet; //数据集
_arrayFieldType[i].pDBText->DataField = pDBGrid->Columns->Items[i]->FieldName; //字段名
_arrayFieldType[i].pDBText->Font = pDBGrid->Columns->Items[i]->Font; //字体
_arrayFieldType[i].pDBText->Alignment= pDBGrid->Columns->Items[i]->Alignment; //对齐方法
_arrayFieldType[i].pDBText->Left = PreLeft+_iIntClearance;
_arrayFieldType[i].pDBText->Width = _arrayFieldType[i].iWidth-2*_iIntClearance;
_arrayFieldType[i].pDBText->Height= _arrayFieldType[i].pDBText->Font->Height;
_arrayFieldType[i].pDBText->Top=
pDetailRect->Top+(pDetailRect->Height+_arrayFieldType[i].pDBText->Height)/2;
_arrayFieldType[i].pShapeData= new TQRShape(pQuickRep); //该数据右边的脱离竖条
_arrayFieldType[i].pShapeData->Parent= DetailBand1;
_arrayFieldType[i].pShapeData->Left = PreLeft+_arrayFieldType[i].iWidth;
_arrayFieldType[i].pShapeData->Top = 0;
_arrayFieldType[i].pShapeData->Width= 1;
if( i== pDBGrid->FieldCount-1) //最后一列的脱离竖条宽度为0
_arrayFieldType[i].pShapeData->Width= 0;
_arrayFieldType[i].pShapeData->Height=_arrayFieldType[i].pShapeData->Parent->Height;
PreLeft= _arrayFieldType[i].pShapeTitle->Left; //下列字段的左位置
}
}
TGridPrint::~TGridPrint() //析构函数
{ delete pTitleLabel; delete pHeadRect; delete pDetailRect;
for(int i=0; i< pDBGrid->FieldCount;i++)
{ delete _arrayFieldType[i].pDBText; delete _arrayFieldType[i].pShapeData;
delete _arrayFieldType[i].pLabel; delete _arrayFieldType[i].pShapeTitle;
} }
void TGridPrint::DoPreview() //打印预览函数
{ pQuickRep->Preview(); }
2.2 定制报表
#p#分页标题#e#
类的民众接口提供有4个函数SetPrntTitle、SetColumnsWidth、SetHeadRectHeight、SetDetailRectHeight,别离是手工配置表格的总标题、表格各列宽度、字段标题行的高度和数据行的高度。编程人员可本身设计相关界面,供用户来对报表的机关做进一步的批改,满意用户的要求,提高了报表的质量和用户参加的努力性。实际上,这样做将编程人员在报表设计阶段的事情转交给用户来做,制止了本来设计好不能改变的问题。
2.3 挪用要领
完成类TGridPrint的设计后,编程人员可以在需要的处所很利便地挪用它。挪用前留意包括两个头文件。挪用时,需将下面结构函数里的DBGrid1换成措施界面上实际利用的TDBGrid控件名字,其它不消窜改。
#include "GridPrint.h"
#include "RepRst.h"
TFrmRepRst *pFrmRepRst= new TFrmRepRst(NULL);
TGridPrint *pGridPrint= new TGridPrint(pFrmRepRst->QuickRep1, DBGrid1, pFrmRepRst->TitleBand1, pFrmRepRst->ColumnHeaderBand1, pFrmRepRst->DetailBand1);
pGridPrint->DoPreview();
delete pGridPrint; delete pFrmRepRst;
3.竣事语
在前人设计的基本上,按照任务的需要,回收面向工具的设计要领,可设计出实现方针的新类,并能被担任和扩充。本文只针对数据表格TDBGrid控件设计的,起抛砖引玉的浸染,读者可在上述思路的基本上,针对其它名目标报表,举办自动生成报表的设计。