给DBGrid加入排序功能
在实际数据库管理系统中,用户对表中数据的操作,最频繁的莫过于浏览查询了,而查询中若能提供为某字段建立的排序功能,则非常有利于用户对“关键数据”的了解。
Windows的用户都知道,在“我的电脑”或“资源管理器”中打开任一文件夹,若以“详细资料”方式查看,系统会显示出该文件夹下的子文件夹和文件相关信息,如:名称、类型 、大小、修改时间,用户只需要单击标题栏中的相应项,则系统自动按该项进行“升序”(或“降序”)的排列显示,这样用户便能轻松查看相应的文件夹或文件对象的内容。
受此启发,考虑能不能在显示数据的Grid表格中完成如此功能呢?答案是肯定的。下面以在Delphi中的实现方法为例,通过具体内容,介绍该功能的实现。
步骤如下:
一、先建立一数据表
该表以Delphi 中最常用的Paradox为类型,取名为Student,反映(在职)学生的基本情况。该表各字段定义如下:
--------------------------------------------
字段名 类型 大小
序号 Short型 / (Key*)
学号 Alpha型 6
出生日期 Date型 /
性别 Alpha型 2
婚否 Logical型 /
英语 Number型 /
高数 Number型 /
PASCAL Number型 /
备注 Memo型 20
-------------------------------------------
保存后,随意往表中输入3至5条记录内容。
注:①表中必须建立关键索引(为首字段建立)。此处为“序号”字段;
with table1 do
begin
close;
Exclusive := true;
DatabaseName := '';
TableName := '';
Open;
{建立主索引 }
AddIndex('','ID',[ixPrimary]);
{建立次索引 }
AddIndex('NameIndex','ID;Name',[]);
close;
end;
②该表中使用了Paradox常用的几种字段类型,但尚未全部包含。
二、建立项目,实现功能
1.新建一项目,并为表单添加相关控件,各控件主要属性如下表:
2.建立各Click的事件代码
Button1(打开表)的Click事件代码如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
Table1.Open; // 打开Table1关联的表Student
end;
Button2(关闭表单)的Click事件代码如下:
procedure TForm1.Button2Click(Sender: TObject);
begin
Application.Terminate;
end;
DBGrid1的TitleClick事件代码如下:
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
//注:本过程参数Column包含的信息量非常多
begin
MySort(DBGrid1,Column);
end; //调用字段排序
其中,MySort(DBGrid1,Column)为自定义的排序过程,具体代码见下述。
3.建立通用处理模块
为使该功能具有“通用性”,将其定义为一过程。
首先,预声明过程及建立两个全局私有变量:
...
Type
...
procedure MySort(DBGrid0:TDBGrid; Column: TColumn);//预声明过程
private
{ Private declarations }
psIndexName:string; //记录当前索引名称
plAscend:boolean; //记录当前索引名称的索引状态
public
{ Public declarations }
end;
...
其次,该过程完整代码如下:
procedure TForm1.MySort(DBGrid0:TDBGrid; Column: TColumn);
var
//本模块使用到的psIndexName, plAscend两个变量见上定义
mode:char; //记录是“升序”还是“降序”
ColName:string; //记录当前字段名
iCol:Integer; //记录当前列号
begin
with DBGrid0.DataSource.DataSet as TTable do //Table0
begin
//检测当前工作表是否已打开
if not Active
then begin
MessageBeep(0);
Application.MessageBox('工作表尚未打开!','停止',MB_OK+MB_ICONSTOP);
Abort
end;
//检测当前字段是否“能排序”。以下字段类型不能排序
case Column.Field.DataType of
ftBoolean,
ftBytes,
ftBlob, //Binary
ftMemo,
ftGraphic,
ftFmtMemo, //Formatted memo
ftParadoxOle: //OLE
begin
MessageBeep(0);
Application.MessageBox(Pchar('项目"'+Column.FieldName+'"'+'不能排序!'),'停止
',MB_OK+MB_ICONSTOP);
Abort
end;
end; //case
mode:='0';
iCol:=Column.Field.FieldNo-1;
try
ColName:=Column.fieldname;
if psIndexName=Column.fieldname
then begin //与原来同列
if plAscend //升序
then begin
mode:='2';
IndexName:=ColName+'2'; //应“降序”
end
else begin
mode:='1';
IndexName:=ColName+'1'; //应“升序”
end;
plAscend:=not plAscend;
end
else begin //新列
IndexName:=ColName+'2';
plAscend:=false;
psIndexName:=ColName;
end;
except
on EDatabaseError do //若未有索引,则重新建立
begin
Messagebeep(0);
//以下新建索引
IndexName:='';
Close;
Exclusive:=true;
if mode='1'
then AddIndex(ColName+'1',ColName,[ixCaseInsensitive],'')//
else //包括'0'
AddIndex(ColName+'2',ColName,[ixDescending,ixCaseInsensitive],'');
Exclusive:=false;
Open;
try //try 1
if mode<>'1'
then begin
mode:='2';//转换
plAscend:=false;
end
else plAscend:=true;
IndexName:=ColName+mode;
psIndexName:=ColName;
except
on EDBEngineError do
IndexName:='';
end //try 2
end
end;
First;
end; //with
DBGrid0.SelectedIndex:=iCol;
end;//End of MySort
本过程已对所有可能的错误进行了相应的检测及处理,代码是比较完整的。因此,把该过程放入你相应的单元中,对每一个DBGrid,只要传递不同的DBGrid及Column参数,就能实现对应数据表的自动排序处理,而事先只为某字段建立一关键索引即可,其它Secondery Indexes的建立均在程序中自动完成,但会为每一个建立了索引的字段生成了一些附加文件(如*.XG?,*YG?等)。当然若有必要,可以在表单关闭前将所有的附加文件删除。