[返回]
中國計算機報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控件的幾種使用技巧,其實程序開發中有許多技巧能夠使應用程序更好地滿足用戶的需求,利用不同開發工具的程序開發人員可以互相借鑒,使開發的應用程序更加精致。
原文轉自:http://www.anti-gravitydesign.com