摘要:Delphi的DBGrid控件使用靈活,應用廣泛,但沒有提供顯示記錄的序號,點擊列標題排序,對列寬度、順序等信息的保存與恢復功能,在實際應用中存在不便。該文闡述了DBGrid控件的內部實現(xiàn)機制,介紹了對DBGrid控件添加顯示序號,點擊列標題排序,保存與恢復列寬度、順序等信息的實現(xiàn)方法。
關鍵詞:Delphi;DBGrid控件;記錄;顯示序號;排序
中圖分類號:TP393文獻標識碼:A文章編號:1009-3044(2008)35-2406-05
The Development of Data Browsing Control Based on DBGrid
WANG Pei-rong
(College of Electronic Information and Automatization,Chongqing Institute of Technology,Chongqing 400050,China)
Abstract: DBGrid contril has been applied widely in Delphi for its flexible use,but this control does not provide these function such as displaying of record serial number,sorting of column title,saving and restoring of column width and column sequence.This paper describes the internal realization mechanism of DBGrid control,and introduces how to realize displaying of record serial number,sorting of column title and saving and restoring of column width and column sequence.
Key words: delphi; DBGrid control; record; displaying serial number; sorting
Delphi的DBGrid是顯示、編輯數(shù)據(jù)的控件,使用率相當高。在使用中,常常需要顯示記錄的序號,對表格中的記錄進行排序處理,以及對列寬度,列順序的保存與恢復,這通常都需要對DBGrid的具體事件進行特定編碼,才能滿足需要。
作者在開發(fā)一個考勤管理系統(tǒng)時,用戶就提出需要對表格中的記錄進行排序,能夠記住用戶上次對表格的列寬度、順序的調整,能夠顯示記錄序號。所以將這三個典型功能進行控件標準化,創(chuàng)建了一個新的基于DBGrid的控件,整合了上述功能,完全可以代替原有的DBGrid控件,使用起來相當方便。
1 方法
要在DBGrid中整合顯示序號,點擊列標題排序,保存列寬度等信息,最好的辦法就是定義一個從DBGrid繼承的新控件。點擊Delphi的Component菜單下的New Component,在彈出的窗口中按圖1進行設置,即可生成該新控件。
相對于DBGrid控件,本控件新增了標志排序狀態(tài)的屬性,用字符串ASCChar作為升序標志,用字符串DESCChar作為降序標志,用邏輯變量ShowRecNo作為顯示序號的控制屬性。新增方法SaveColumnsToIni,LoadColumnsFromIni分別用來保存和恢復上次列寬度,列順序等信息。
Delphi提供了DBGrid的源代碼,文件名為DBGrids.pas,該文件在Delphi6版本中存放在<安裝目錄>\\Source\\Vcl目錄下,在Delphi2005版本中存放在<安裝目錄>\\3.0\\source\\Win32\\db目錄下。打開Delphi的DBGrids.pas文件,拷貝TDBGrid類的定義內容到圖1生成的單元文件TSDBGrid.pas中,作為新控件類的定義。在TSDBGrid.pas文件的published部分增加屬性property ASCChar:string;property DESCChar:string;property ShowRecNo:Boolean;在public部分增加方法procedure SaveColumnsToIni(sect,name:string);procedure LoadColumnsFromIni(sect,name:string);之后按CTRL+SHIFT+C鍵,Delphi就會補充完整的定義框架。
1.1 顯示記錄序號
原有的DBGrid控件的第一列僅顯示記錄狀態(tài)標志,沒有顯示記錄序號,本文所述新控件將擴展該標志列,添加顯示序號功能。
DBGrid控件是從CustomDBGrid 繼承而來的,僅簡單公開一些屬性而已,所以新控件參照DBGrid,也從CustomDBGrid繼承。原有的DBGrid控件的第一列寬度是在SetColumnAttributes這個過程中實現(xiàn)的,現(xiàn)在重載這個方法,加大該列寬度,為顯示記錄序號留出位置,代碼如下。
procedure TTSDBGrid.SetColumnAttributes;
begin
inherited;
//如果要顯示標志列且顯示序號屬性為真
if(dgIndicator in Options) and FShowRecNothen
ColWidths[0] := IndicatorWidth*3;
//加大列寬度為原寬度的3倍
end;
DBGrid控件表格在屏幕上的顯示是在方法DrawCell中實現(xiàn)的,重載這個方法就能實現(xiàn)顯示記錄序號的功能,具體代碼如下。
procedure TTSDBGrid.DrawCell(ACol,ARow:Integer;ARect:TRect;
AState:TGridDrawState);
…
begin
inherited;
…
//如果是第一列且顯示序號屬性為真
if (gdFixed in AState) and (ACol<0)
and FShowRecNo then
begin
Canvas.Brush.Color:=FixedColor;
if Assigned(DataLink) and DataLink.Activethen
begin
if {(ARow <> DataLink.ActiveRecord) and}(Arow>=0) then
begin//畫第一列
Canvas.Font.Color:=clRed;
FRect:=ARect;
FRect.Top:=ARect.Top+1;
OldActive:=DataLink.ActiveRecord;
try
DataLink.ActiveRecord:=ARow;
Value:=IntToStr(DataLink.DataSet.RecNo);
//如果不能取到序號,則不顯示
if(DataLink.DataSet.RecNo<0) then Value:='';
finally
DataLink.ActiveRecord:=OldActive;
end;
//居中畫出記錄序號
DrawText(Canvas.Handle,PChar(Value),Length(Value),F(xiàn)Rect,DT_CENTER);
end;
end;
end
//處理列標題的排序標志
else if(ACol>=0) then
with Canvas do
begin
DrawColumn:=Columns[ACol];
if ARow<0 then
//調用局部過程,處理排序標志符號
DrawTitleCell(ACol,ARow+TitleOffset,DrawColumn,AState)
end;
end;
1.2 排序功能
列排序功能通過點擊列標題觸發(fā),在初始順序、升序、降序狀態(tài)間切換。重載TitleClick方法,在該方法中添加排序功能的代碼,代碼如下。
procedure TTSDBGrid.TitleClick(Column:TColumn);
var
s,cFieldName:string;
i:integer;
DataSet:TDataSet;
ASortCol:TSortCol;
begin
//如果是設計狀態(tài),不處理
if(csDesigning in ComponentState)
then exit;
//如果數(shù)據(jù)集無效,也不處理
if (Column.Grid.DataSource=nil)
or (Column.Grid.DataSource.DataSet=nil) or (not Column.Grid.DataSource.DataSet.Active) then exit;
DataSet:=Column.Grid.DataSource. DataSet;
//如果是關聯(lián)字段,計算字段,則選擇默認排序,否則表示需要排序的字段
if Column.Field.FieldKind=fkLookup
then
cFieldName:=Column.Field.KeyFields
else if Column.Field.FieldKind=fkCalculated then
cFieldName:=Column.Field.KeyFields
else
cFieldName:=Column.FieldName;
//如果是ADO記錄集類型
if DataSet is TCustomADODataSet then begin
//取出當前排序字段
s:=TCustomADODataSet(DataSet).Sort;
if s='' then begin
//為空表示沒有排序字段,將當前字段作為升序字段記下
s:=cFieldName;
ASortCol:=TSortCol.Create (Column. Index, SortASC);
end
else begin
//如果當前字段已經(jīng)在排序
if Pos(cFieldName,s)<>0 then begin
//查找當前是否是在降序中
i:=Pos('DESC',s);
//如果不是降序,就作為降序記下
if i<=0 then begin
s:=s+'DESC';
ASortCol:=TSortCol.Create (Column.Index,SortDESC);
end
else begin
//如果已經(jīng)是降序,就回到默認順序
s:='';
ASortCol:=TSortCol.Create(Column.Index,SortDefault);
end;
end
else begin
//當前字段不在排序狀態(tài),則作為升序記下
s:=cFieldName;
ASortCol:=TSortCol.Create (Column.Index,SortASC);
end;
end;
//保存排序狀態(tài),并排序
SortCol:=ASortCol;
ASortCol.Free;
TCustomADODataSet(DataSet).Sort:=s;
end
//處理TClientDataSet記錄集類型
else if DataSet is TClientDataSet then begin
…
end;
//可以繼續(xù)添加對其他數(shù)據(jù)集類型的支持
//…
//調用祖先的實現(xiàn),保留本事件的其他定制接口功能
inherited;
end;
將排序標志符號畫到標題列,在DrawCell中的子過程DrawTitleCell實現(xiàn),代碼如下。
procedure TTSDBGrid.DrawCell(ACol,ARow:Integer;ARect:TRect;
AState:TGridDrawState);
procedure DrawTitleCell(ACol,ARow:Integer;Column:TColumn;var AState:TGridDrawState);
…
begin
…
//列標題的矩形框計算
TextRect:=TitleRect;
TextRect.Left:=TextRect.Right-Canvas.TextWidth(ASCChar);
//用紅色字體畫排序標志
Canvas.Font.Color:=clRed;
//取出對應的排序狀態(tài)標志字符
Value:='';
if(Column.Index=SortCol.Col) then
if(SortCol.sortType=SortASC)
then Value:=ASCChar
else if(SortCol.sortType=SortDESC)
then Value:=DESCChar;
//畫出排序標志字符
DrawText(Canvas.Handle,PChar(Value),Length(Value),TextRect,DT_RIGHT);
end;
begin//主過程
…
DrawTitleCell(ACol,ARow+TitleOffset,DrawColumn,AState);
…
end;
1.3 列信息的保存與恢復
這個功能用來保存與恢復用戶在運行時對列進行順序,寬度等信息的調整,代碼如下。
procedure TTSDBGrid.SaveColumnsToIni (sect, name: string);
var
s:string;
i:integer;
ini:TIniFile;
begin
//將列信息保存到與應用程序名對應的.ini中,段名由sect參數(shù)指定,變量名由name參數(shù)指定
ini:=TIniFile.Create(ChangeFileExt (Application.ExeName,'.ini'));
try
for i:=0 to Columns.Count-1 do
begin
s:=s+Columns.Items[i]. FieldName +','+Columns.Items[i].Title. Caption+','+IntToStr(Columns. Items[i]. Width)+',';
end;
SetLength(s,Length(s)-1);
ini.WriteString(sect,name,s);
finally
ini.Free;
end;
end;
procedure TSDBGrid.LoadColumnsFromIni (sect, name: string );
var
ini:TIniFile;
s:string;
ls:TStringList;
i:integer;
begin
//將列信息從與應用程序名對應的.ini中恢復,段名由sect參數(shù)指定,變量名由name參數(shù)指定,應與保存時相一致
ls:=TStringList.Create;
ini:=TIniFile.Create( ChangeFileExt(
Application.ExeName,'.ini'));
try
s:=ini.ReadString(sect,name,'');
ls.CommaText:=s;
if(ls.Count=3*Columns.Count) then
for i:=0 to Columns.Count-1 do
begin
Columns.Items[i].FieldName:=ls.Strings[3*i];
Columns.Items[i].Title.Caption:=ls.Strings[3*i+1];
Columns.Items[i].Width:=StrToInt(ls.Strings[3*i+2]);
end;
finally
ini.Free;
ls.Free;
end;
end;
在窗體建立或釋放時調用一下保存與恢復過程即可,如下例所示。
procedure TForm1.FormCreate(Sender:TObject);
begin
//參數(shù)注意與保存時一致
TSDBGrid1.LoadColumnsFromIni
('表格信息','表格一');
end;
procedure TForm1.FormDestroy(Sender:TObject);
begin
//參數(shù)注意與恢復時一致
TSDBGrid1.SaveColumnsToIni
('表格信息','表格一');
end;
2 控件注冊
通過Delphi的Component菜單下的Install Component菜單進行控件注冊,Delphi將利用生成控件時自動生成的Register過程(過程代碼見本段后)注冊本控件。將控件注冊到控件面板上的TS Coms頁中,然后就可以象使用Delphi的標準控件一樣使用。具體注冊窗體見圖2。
procedure Register;
begin
RegisterComponents('TS Coms',[TTSDBGrid]);
end;
3 控件的使用例子
通過上述過程注冊控件后,新建一個工程文件Project1.dpr,在Form1中放入一個ADOConnection1控件,一個ADOTable1,一個DataSource1,一個本文所建立的控件TSDBGrid1(在面板的TS Coms頁中),如圖3。
設置ADOConnection1的LoginPrompt屬性為False,連接串ConnectionString指向數(shù)據(jù)庫:Provider=SQLOLEDB.1;Password=<你的數(shù)據(jù)庫密碼>;Persist Security Info=True;User ID=sa;Initial Catalog=<數(shù)據(jù)庫名>;Data Source=.。設置ADOTable1的Connection屬性為ADOConnection1,TableName屬性值為<要顯示的表名>,Active屬性為True。設置DataSource1的DataSet屬性為ADOTable1。設置TSDBGrid1的DataSource屬性為DataSource1,ShowRecNo屬性為True,并調整合適大小,得到圖3的設計結果。
編寫Form的OnCreate,OnDestroy事件代碼,如下:
procedure TForm1.FormCreate(Sender:TObject);
begin
//參數(shù)注意與保存時一致
TSDBGrid1.LoadColumnsFromIni
('表格信息','表格一');
end;
procedure TForm1.FormDestroy(Sender:TObject);
begin
//參數(shù)注意與恢復時一致
TSDBGrid1.SaveColumnsToIni
('表格信息','表格一');
end;
按F9運行,然后點擊列標題,觀察排序效果,調整表格列寬度,關閉程序,再次運行,列寬度即為上次調整后的寬度。本例子用ADOTable記錄集作為數(shù)據(jù)集,顯示了記錄序號,學號,姓名,性別,出生年月。點擊學號列標題進行升序操作,并在列標題上顯示升序符號,效果如圖4。
4 結論
該程序在WindowsXP,Delphi6,SQLServer2000下調試成功,經(jīng)比較分析,Delphi6以及Delphi 2005的DBGrids.pas代碼基本未變,所以本文所述內容在Delphi后續(xù)版本中也是適用的。
參考文獻:
[1] 黃雄波,胡永健.基于Delphi的動態(tài)模糊輸入系統(tǒng)的設計與實現(xiàn)[J].計算機應用與軟件,2008(3).
[2] 李文杰,李霄漢.在Delphi的DBGrid中添加可視組件的改進方法[J].電腦編程技巧與維護,2006(3).
[3] 杜瑾.Delphi中DBGrid控件的高級使用[J].電腦學習,2003(1).
[4] 敬喜,王昀.Delphi 7數(shù)據(jù)庫編程學習捷徑[M].北京科海電子出版社,2003.
[5] 唐世偉,高升,黃志清.改進Delphi的DBGrid實現(xiàn)表格式數(shù)據(jù)輸入[J].微型電腦應用,2001(5).