[返回]
中国计算机报2001年第54期
DBGrid控件使用技巧
刘遵雄
C++ Builder是著名的快速可视化开发工具(RAD)之一,它和Delphi共用可视化类库VCL,由于其具有C++语言良好的可操作性,可以用来编写出高效率、高质量的应用程序代码,因而越来越受广大程序员的欢迎。
C++ Builder具有强大的数据操作能力,其集成开发环境(IDE)的控件板给用户提供了大量的数据访问控件,通过对有关数据库控件属性进行适当设置,合理地引用其方法来控制事件,能极大地方便数据库应用程序的创建。
C++ Builder控件板上提供了数据库应用程序开发中所要使用的控件,其中,数据访问页(Data
Aclearcase/" target="_blank" >ccess Page)控件板上的控件用于直接访问数据库中的数据库表,而数据控制页(Data
Control Page)控件板上的控件用来与用户交互、显示、修改数据库中的数据,DBGrid就是其中一种功能强大的数据控制控件,它用于全屏幕显示和编辑数据库表中的记录,表现为网格的形式。本文主要介绍DBGrid控件使用过程中的一些技巧。
实现动态数据排序
DBGrid控件不具备访问磁盘数据库的能力,它是必须通过DataSource控件来实现的。其属性DataSource指向某一DataSource控件,而DataSource控件的DataSet属性指向的数据集可以是TTable或TQuery控件。通过使用TQuery控件动态编程,我们可以实现程序运行时单击DBGrid控件的标题部分,数据即可按选定字段排序的功能。具体实现过程如下:
新建工程,在Form1上拖放TQuery、TDatasource 和 TDbGrid控件,Name属性分别是Query1、Datasource1和DbGrid1,然后将它们关联起来,Query1
的DatabaseName属性指向DBDEMOS,DbGrid1的Datasource属性设为Datasource1,Datasource1的Dataset属性值设为Query1。在Form1的CPP文件对应的头文件中声明AnsiString型变量QuerySQL,用于存放SQL语句内容。在Form1的OnActivate事件中检索数据,编写如下代码:
void __fastcall TForm1::FormActivate(TObject ?Sender)
{
QuerySQL = "SELECT ? FROM Customer.DB";
Query1->SQL->Add(QuerySQL);
Query1->Open();
}
使DbGrid1控件显示的数据排序的关键是在DbGrid1的OnTitleClick事件中编程改变Query1的SQL语句内容,程序如下:
void __fastcall TForm1::DBGrid1TitleClick(TColumn ?Column)
{
AnsiString str;
int i;
str= Column->FieldName ;
//获取鼠标点击数据栏的字段名称
Query1->DisableControls();
Query1->Close();
Query1->SQL->Clear();
Query1->SQL->Add(QuerySQL);
Query1->SQL->Add("ORDER BY "+str);
Query1->Open();
DBGrid1->Columns->RestoreDefaults();
//使鼠标点击的数据栏的标题改变颜色
for (int i = 0; i < i < Query1->FieldCount; i++)
{
//遍历Query1的字段,判断其是否是鼠标点击的字段
if (Query1->Fields->Fields[i]->FieldName ==str)
{
DBGrid1->Columns->Items[i]->Title->Font->Color= clRed;
DBGrid1->Columns->Items[i]->Title->Alignment= taCenter;//标题居中
} ;
};
Query1->EnableControls();
}
在数据栏中显示图像
使用DBGrid1控件来全屏显示编辑数据时,为了使界面生动活泼,我们希望能根据字段枚举数值(其取值通常为几个特定值)的不同显示不同的图像。
我们可以在DBGrid控件的OnDrawColumnCell事件中编写代码来增强DBGrid控件的显示效果,如果其DefaultDrawing属性为true,DBGrid控件在OnDrawColumnCell事件响应前按默认效果显示,然后以此为基础执行OnDrawColumnCell事件的代码。需要完全取代DBGrid控件的显示效果时,可将其DefaultDrawing属性设为false,并在OnDrawColumnCell事件中编写控制显示效果的脚本。如果希望某些列产生特定效果,可以在OnDrawColumnCell事件中调用DefaultDrawColumnCell方法,然后修正特定列的输出效果。以下示例是在DBGrid控件数据栏中显示图像效果的程序。
新建工程,在Form1上拖放TTable、TDatasource 、TDbGrid和TImageList控件,Name属性分别是Table1、Datasource1、DbGrid1和ImageList1,然后将它们关联起来,Table1
的DatabaseName属性指向DBDEMOS(该别名指代C++ Builder自带的例程数据库表)、TableName属性为Clients.dbf、Datasource1的Dataset属性值为Table1、DbGrid1的Datasource属性等于Datasource1。使用DbGrid1的列编辑器让DbGrid1仅显示Last_Name、First_Name、Risk_Level和
Occupation四个字段,再设置DbGrid1的DefaultDrawing属性为false,然后设置ImageList1存放向下、向上、向左的三种箭头图像。DBGrid1的On
DrawColumnCell事件代码如下:
void __fastcall TGridDrawForm::DBGrid1DrawColumnCell(TObject ?Sender,
const TRect &&Rect, int DataCol, TColumn ?Column,TGridDrawState
State)
{
if (DBGrid1->Columns->Items[DataCol]->FieldName ==
"RISK_LEVEL")
{
DBGrid1->Canvas->FillRect(Rect);
if (DBGrid1->Columns->Items[DataCol]->Field->AsString ==
"LOW")
{//字段值为“LOW”,绘制向下的箭头
ImageList1->Draw(DBGrid1->Canvas,Rect.Left+4,Rect.Top,0,True);
}
else if (DBGrid1->Columns->Items[DataCol]->Field->AsString ==
"MED")
{//字段值为“MED”,绘制向左的箭头
ImageList1->Draw(DBGrid1->Canvas,Rect.Left+4,Rect.Top,1,True);
}
else
{//否则绘制向上的箭头
ImageList1->Draw(DBGrid1->Canvas,Rect.Left+4,Rect.Top,2,True);
}
}
else
DBGrid1->DefaultDrawColumnCell(Rect,DataCol,Column,State);
}
当绘制DBGrid时,绘制屏幕上当前可见行的每个数据单元都调用上述事件过程。DataCol用于显示DBGrid的Columns属性的顺序。根据DataCol值可以确定将绘制的数据单元的栏目名称。此例中,如果栏目的字段不是“Risk_Level”则调用DefaultDrawColumnCell方法,使其成默认的显示效果。反之,则先调用FillRect方法清除背景,然后根据该字段值的不同,调用ImageList的Draw方法,实施对象是DBGrid控件的画布对象,Rect中参数Left和Top值决定了绘制坐标的位置,图像列表中不同的值决定了产生图像的不同。
将当前行以不同颜色显示
DBGrid控件中当前的数据通常是用蓝色背景显示的,有时我们为了达到提示及操作界面美化方面的要求,希望能将DBGrid控件显示的数据用不同的颜色背景显示,比如红色。我们只需将DBGrid控件的Option属性中的dgRowSelect值设为true,在DBGrid控件的OnDrawColumnCell事件中编写程序,根据某行是否有方格被选中或是否处于活动状态来改变DBGrid控件中画布Canvas的Brush对象的颜色值,然后调用DefaultDrawColumnCell方法。
以前面实现动态数据排序的程序为基础,在DBGrid1的OnDrawColumnCell事件中编写如下代码:
void __fastcall TForm1::DBGrid1DrawColumnCell(TObject ?Sender, const
TRect &&Rect, int DataCol, TColumn ?Column, TGridDrawState State)
{//如果某行有方格被选中,则置以红色背景,否则设成白色
if (State.Contains(gdFocused) || State.Contains(gdSelected))
{
DBGrid1->Canvas->Brush->Color=clRed;
}
else
{
DBGrid1->Canvas->Brush->Color= clWhite ;
};
DBGrid1->DefaultDrawColumnCell(Rect,DataCol,Column,State);
}
我们同样可以根据DBGrid控件显示的数据行某个字段值的不同,应用OnDrawColumnCell事件改变该行数据的字体颜色或背景颜色。
禁止控件自动添加空行
使用DBGrid控件全屏显示数据记录时,若DBGrid控件Option属性的dgEditting值设置是true,或者DBGrid控件的各个显示字段Column的ReadOnly属性值是false时,当达到最后一条记录行并继续敲击键盘下箭头键,DBGrid控件会增加新行,这样可能会引起数据输入问题,大部分时间我们并不希望如此。
为解决此问题,我们可以将DBGrid控件Option属性的dgEditting值设置为false,或者将DBGrid控件的显示字段Column的ReadOnly属性值设置为true,但是会产生DBGrid控件显示数据不可编辑的问题,我们可以用下面的两种方法来加以解决:
1.可以编辑DBGrid控件引用的DataSource控件对应的数据集Table的BeforeInsert事件,只需在其中写入Abort即可。代码如下:
void __fastcall TForm1::Query1BeforeInsert(TDataSet ?DataSet)
{
Abort;
}
2.通过DBGrid1的onKeydown事件判别是否按了“下箭头”键和Table1的记录是否为最末记录,人为地改变当前记录行,DBGrid控件显示数据的当前行与数据集的当前行是一致的。
void __fastcall TForm1::DBGrid2KeyDown(TObject ?Sender, WORD
&&Key,
TShiftState Shift)
{
if (Key = VK_DOWN)//判断按键是否为下箭头键
{//是,使Table1记录指针下移一条记录,再判断是否是表尾
Table1->DisableControls() ;
Table1->Next() ;
if (Table1->Eof)
{ Key = 0 ;}
//是表尾,赋Key值为0,不添加空行
else
{Table1->Prior();} ;
//将表的记录指针回移到原位置
Table1->EnableControls() ;
}
}
以上,笔者谈了DBGrid控件的几种使用技巧,其实程序开发中有许多技巧能够使应用程序更好地满足用户的需求,利用不同开发工具的程序开发人员可以互相借鉴,使开发的应用程序更加精致。