DBGrid和DBGridEH


二、應用實例
    Enlib3.0組件包安裝成功后
A、定制標題行
 1、制作復雜標題行
    標題行可設為2行以上高度,並可以為多列創建一個共同的父標題行。為實現這個效果,需在各個列標題屬性中以“|”分隔父標題和子標題,如辦公用品包括代碼和名稱兩部分,具體屬性設置如下:

usemultititile=true;
titlelines=2
DBGridEh.Columns[0].Title.Caption := '辦公用品|代碼';
DBGridEh.Columns[1].Title.Caption := '辦公用品|名稱';

 2、標題行顯示圖片 
    實現圖2中的購買人標題行顯示效果。首先添加一個imagelist組件img1並在其中添加一組bmp,ico格式的圖片。然后將DBGridEh的TitleImages設置為img1.最后在需要顯示圖片的列標題的imageindex中設置需要顯示的img1中圖片的序號。按F9執行一下程序,是不是很酷!

 3、自動顯示標題行的升降排序標志符(▽降序△升序)並做相應排序
    DBGridEh組件可以在標題行單元格中顯示小三角形升、降排序標志符圖片,在運行時可點擊標題行,圖片自動切換並做相應排序。具體屬性設置如下:

OptionsEh=dghAutoSortMarking 
Column.Title.TitleButton=true 

SortMarkedColumns 為當前排序列可在運行時使用.
然后在該列的ontitleclick事件中添加代碼:
procedure TForm_Query.DBGridEh1TitleBtnClick(Sender: TObject; ACol: Integer; Column: TColumnEh);
var
  sortstring:string; //排序列
begin
  //進行排序
  with Column do
  begin
    if FieldName = '' then
      Exit;
    case Title.SortMarker of
      smNoneEh:
      begin
        Title.SortMarker := smDownEh;
        sortstring := Column.FieldName + ' ASC';
      end;
      smDownEh: sortstring := Column.FieldName + ' ASC';
      smUpEh: sortstring := Column.FieldName + ' DESC';
    end;
  //進行排序
    try
      dataset.Sort := sortstring //dataset為實際數據集變量名
    except
    end;
  end;
end;

切記lookup型字段不可做上述設置,否則系統會提示錯誤。
 
  
 
B、定制表格底部(footer)區域的匯總統計行
    DBGridEh 組件可以在表格底部顯示匯總行,如記錄數合計、列字段累加和等信息。在FooterRowCount中設置底部顯示的行數;然后在Footers 編輯器中添加一個或多個顯示列,顯示列可以是字段值累加和、記錄數合計、字段值或靜態文件等集合類型,可以在設計時在ValueType屬性中設置,也可在運行時通過設置Footers[i].ValueType指定其類型。其含義見下表:

    切記設置DBGridEh.SumList.Active 為 True,才會進行匯總統計運算。需注意的是,如顯示類型為不是當前列的累加和,則需在fieldname屬性中指定匯總列,其它類型則無此要求。 
 
 
 
C、定制表格數據單元外觀
 1、根據不同字段值顯示相應的小圖片
    如根據庫存材料的不同狀態在數據單元格中顯示相應圖片,具體設置如下:
    添加一個imagelist組件img1並在其中添加一組bmp,ico格式的圖片。然后將需要顯示圖片的列的imagelist屬性設置為img1;在keylist屬性中添加實際數據存儲值,一行為一個值,切記一定要與imagelist中圖片順序一一對應,否則會張冠李戴,面目全非。還可在picklist中添加提示信息,也要求是一行為一個值,並設tooltip為true,那么,運行時當鼠標移動到該數據單元格時在顯示圖片的同時還顯示提示信息,怎么樣,功能夠強大吧!可使用空格鍵或鼠標切換下一張圖片,圖片切換的同時也改變了實際存儲數據值。也可通過shift+空格或鼠標切換為上一張圖片。這樣就實現了上下兩個方向圖片切換。

 2、顯示檢查框(checkbox)外觀
    對於Boolean型字段值在dbgrideh組件中自動顯示為檢查框。通常情況下我們需將非Boolean型字段值也此外觀顯示,如性別字段為字符型,字段值為“男性”時為選中,“女性”時為未選中。需要在keylist編輯器中設置實際存儲數據值,第一行為選中時的值“1”,第二行為未選中的值“0”,第三行為其它值“2”,支持三態顯示。設checkbox屬性為True.

 3、顯示單、多列下拉列表
    根據單元格字段值顯示與其相關的其它表字段內容,如部門代碼字段顯示為部門名稱。首先需在當前表中新建立一個lookup型字段,設置好關聯表的字段和返回字段。多列下拉列表需在單列基礎上做進一步設置,在LookupDisplayFields中以“;”號將關聯表中多個字段分隔開,而且返回字段必須作為其中的第一項。具體設置如下:

dropdownshowtitles=true 
dropdownsizing=true
dropdownwidth=-1 

    例:當前表中只有部門代碼無部門名稱列,需與部門表建立關聯,當點擊單元格時以部門代碼、部門名稱兩列下拉列表形式顯示。

 4、顯示日歷下拉列表
    Date 和 DateTime類型字段值均可以此形式顯示。外觀與編輯框無異,當點擊該單元格時,右側會出現“▽”符號,點擊之即可出現日歷下拉列表。有時不希望出現日歷下拉列表,只需設置Column.ButtonStyle屬性為 cbsNone即可,此方法同樣適用於其它組件不以特殊外觀顯示的情況。

 5、3D或平面外觀效果
    設置OptionsEh屬性 中fixed, frozen, footer 和 data rows等屬性表格外觀為3D效果,設置flat為true則為平面外觀效果.

 6、鎖定多列不滾動
    當表格水平方向信息在一屏幕顯示不下時,此項功能非常有用。例如,工資表格中包含姓名、基本工資、績效工資等信息一屏幕顯示不下,需要通過移動水平滾動條顯示下一屏信息。如果不鎖定關鍵字段列如姓名,則移動到下一屏時就不知道此條記錄對應的姓名。因此,在實際應用中經常需鎖定多列不滾動。

    例:姓名字段為表格第二列,則設置FrozenCols=2.這樣當一屏幕顯示不下,通過移動水平滾動條顯示下一屏信息時,表格前兩列不滾動,作為參照列。

D、導入/導出數據
    導入/導出數據在實際處理過程中是比較煩瑣的。但是Enlib3.0提供了一系列函數讓你輕松實現此功能,而且支持的文件格式很多:Text, Csv, HTML, RTF, XLS 和內部數據格式。除此之外,還可對任意選擇的數據區域進行操作。函數如下:

Pascal: SaveDBGridEhToExportFile(TDBGridEhExportAsText,DBGridEh1,'c:\temp\file1.txt',False);

C++: SaveDBGridEhToExportFile(__classid(TDBGridEhExportAsText),DBGridEh1,"c:\\temp\\file1.txt",false);

說明:其中false參數表示導出的是選中的局部數據區域數據,true則為整個表格數據。

   例:將當前表格中數據導出為EXCEL等格式文件。
    在窗體中添加一個SaveDialog組件和“導出”按鈕B_exp,在“導出”按鈕的click事件中添加如下代碼:

procedure TForm1.B_expClick(Sender: TObject);
var 
  ExpClass:TDBGridEhExportClass;
  Ext:String;
begin
  SaveDialog1.FileName := 'file1';
  if (ActiveControl is TDBGridEh) then
    if SaveDialog1.Execute then
    begin
      case SaveDialog1.FilterIndex of
        1: begin ExpClass := TDBGridEhExportAsText; Ext := 'txt'; end;
        2: begin ExpClass := TDBGridEhExportAsCSV; Ext := 'csv'; end;
        3: begin ExpClass := TDBGridEhExportAsHTML; Ext := 'htm'; end;
        4: begin ExpClass := TDBGridEhExportAsRTF; Ext := 'rtf'; end;
        5: begin ExpClass := TDBGridEhExportAsXLS; Ext := 'xls'; end;
      else
        ExpClass := nil; Ext := '';
    end;
    if ExpClass <> nil then
    begin
      if UpperCase(Copy(SaveDialog1.FileName,Length(SaveDialog1.FileName)-2,3)) <> UpperCase(Ext) then
        SaveDialog1.FileName := SaveDialog1.FileName + '.' + Ext;
      SaveDBGridEhToExportFile(ExpClass,DBGridEh1,SaveDialog1.FileName,False);
      //其中false為局部數據
    end;
  end;
end;

E、將存在的DBGrid組件轉換為DBGridEh組件. 
    通過筆者上述介紹,想必你已經對Enlib組件包產生好感而且越越欲試了,那就趕快下載使用吧。但是,使用一段時間並且喜歡上它后,你又有新的問題產生了,那就是為了保持界面風格一致,能否將已經開發完成的應用程序中的DBGrid組件能否轉換為DBGridEh組件,進行一次徹底革命?答案是肯定的。盡管DBGridEh並不是繼承於CustomDBGrid組件, 但是DBGridEh和DBGrid它們之間有許多相同之處.因此可以相互轉換。

具體步驟如下:
 1、在Delphi IDE下打開TDBGrid組件.
 2、通過組合鍵Alt-F12將form 以文本方式顯示;
 3、將所有TDBGrid 對象名改變為 TDBGridEh對象名,如:DBGrid1: TDBGrid改為 DBGrid1: TDBGridEh;
 4、再次通過組合鍵Alt-F12將文本方式恢復為form 顯示;
 5、將form各相關事件中定義的所有TDBGrid改為TDBGrideh,如DBGrid1: TDBGrid改為DBGrid1: TDBGridEh;
 6、重新編譯應用程序。



DBGRIDEH 是Enlib 3.0組件包中的組件之一。Enlib 3.0組件包是一位俄國人為增強Borland系列開發工具功能而開發的第三方組件,它具有界面友好、功能強大、開發效率高、、快速制作預覽/打印簡單中國式報表等特點。因此,一推出即受到廣大Borland程序員的青睞。目前這個版本支持Borland Delphi versions 4,5,6&7 和 Borland C++ Builder versions 4 & 5 ,可極大地提高數據庫應用系統客戶端的性能。許多商品軟件如《速達2000》等都使用了該組件。下面本人將使用該組件在實際系統開發過程中的經驗總結如下。 

Enlib3.0組件包中最重要而且功能最強大的莫過於dbgrideh組件,本文介紹的所有實例均在Delphi 7開發環境下調試通過。

一、DBGridEh(增強型表格組件)功能詳解
DBGridEh組件無論在外觀上還是功能上都非常類似Borland開發工具中現有的dbgrid組件,它除了提供dbgrid組件的全部功能外,還增加了下列新功能:

● 任意選擇多行、列或矩形區域的數據.
● 為多列標題設定共同的父標題行.
● 表格底部(Footer) 區顯示求和、計數和其它統計信息.
● 自動調整組件寬度與客戶區域等寬.
● 設置標題行、數據行的高度.
● 超長的標題行、數據行文本自動折行處理.
● 標題行可作為按鈕使用,並可選擇是否顯示排序標志符(▽降序△升序).
● 點擊列標題可對當前列自動排序而無需編寫代碼.
● 能夠自動設置刪除超長文本顯示不下的多余部分,並以省略號(…)代替.
● 自動搜索字段(Lookup)數據單元格以單、多列字段下拉列表形式顯示.
● 自動搜索字段(Lookup)數據單元格可進行增量搜索.
● 可鎖定任意列數在屏幕水平方向不滾動.
● 日期時間控件DateTime picker 可支持TDateField and TDateTimeField兩種日期格式.
● 根據字段不同值顯示關聯的ImageList 對象圖片組中的圖片.
● 隱藏任意列.
● 顯示3D風格的數據區、表尾區和鎖定滾動列,制作3D外觀表格.
● 顯示Memo類型字段值.
● 除BOOLEAN型數據外,其它數據類型也可以檢查框( checkbox )形式顯示數據.
● 使用專門的函數和過程來存取以reg或ini文件格式保存的表格布局(包含各數據列表、數據列訪問順序、列寬、索引標識、行高等信息)文件。
● 通過設置數據單元格的hint和ToolTips屬性,當移動鼠標到該單元格時,可以顯示單元格容納不下的文本內容.
● 將組件中數據導入/導出到Text, Csv, HTML, RTF, XLS 和內部數據等多種格式的文件中.

DBGridEh組件主要屬性見下表(其它屬性參見dbgrid):

DBGridEh組件事件基本與DBGrid相同,在此不再贅述。



DBGridEH 所有列寬自動適應的實現
interface
THackDBGridEH = class(TCustomdbgrideh)
end;

procedure OptimizeGrid(AGrid: TCustomDbGridEh);

implementation
procedure OptimizeGrid(AGrid: TCustomDbGridEh);
var
i: integer;
begin
// 優化GRID的寬度
for i := 0 to TDBGridEh(AGrid).Columns.count - 1 do
THackDBGridEH(AGrid).OptimizeSelectedColsWidth(TDBGridEh(AGrid).Columns[i]);
end;



在dbgrideh中直接點擊title就可按點擊的那個字段排序的方法
第一種方法(未測試)
procedure TForm1.DBGridEh1TitleClick(Column: TColumnEh);
begin
//點擊GridEh標題排序
if (Column.Title.SortMarker = smNoneEh) or (Column.Title.SortMarker = smDownEh) then
  begin
   ADOQuery1.SORT := COLUMN.FIELDNAME;
   Column.Title.SortMarker := smUpEh
  end
else
  begin
   ADOQuery1.SORT := COLUMN.FIELDNAME + ' DESC';
   Column.Title.SortMarker := smDownEh
  end;
end; 

第二種方法(未測試)
procedure TPrintMai_frm.DBGridEh1TitleClick(Column: TColumnEh);
var
sortstring: string;
begin //進行排序
with Column do
begin
  if FieldName = '' then
   Exit;
  case Title.SortMarker of
   smNoneEh:
    begin
     Title.SortMarker := smDownEh;
     sortstring := Column.FieldName + ' ASC';
    end;
   smDownEh: sortstring := Column.FieldName + ' ASC';
   smUpEh: sortstring := Column.FieldName + ' DESC';
  end; //數據集排序。
  try
   DM.DataModule1.qry2.Sort := sortstring //dataset為實際數據集變量名
  except
  end;
end;
end; 






Delphi 7中的安裝方法

  1. 把 EhLib 中的 common 和 DataService 文件拷貝到 Delphi7 目錄中.
  2.在 TOOLS->Environment Options->Library->Library Path 中添入EHLIB路徑。
  3.打開新建文件夾中的 EHLIB70.DPK ,編譯一下,但不要安裝。
  4.打開Ehlib中的DclEhLib70.DPK,編譯,安裝 
  5. 在Delphi 7中打開DclEhLib70.dpk,編譯並安裝。
  6. 組件面板中出現一個EhLib的組件頁。
  7. 打開附帶的DEMOS,編譯並運行,測試安裝成功。



以下是EHLIB的導出代碼:(其實EHLIB的DEMO1中已有)

procedure TInvoiceManager.ppmSaveSelectionClick(Sender: TObject);
var ExpClass:TDBGridEhExportClass;
  Ext:String;
begin
 SaveDialog1.FileName := 'file1';
 if (ActiveControl is TDBGridEh) then
  if SaveDialog1.Execute then
  begin
   case SaveDialog1.FilterIndex of
    1: begin ExpClass := TDBGridEhExportAsText; Ext := 'txt'; end;
    2: begin ExpClass := TDBGridEhExportAsCSV; Ext := 'csv'; end;
    3: begin ExpClass := TDBGridEhExportAsHTML; Ext := 'htm'; end;
    4: begin ExpClass := TDBGridEhExportAsRTF; Ext := 'rtf'; end;
    5: begin ExpClass := TDBGridEhExportAsXLS; Ext := 'xls'; end;
   else
    ExpClass := nil; Ext := '';
   end;
   if ExpClass <> nil then
   begin
    if UpperCase(Copy(SaveDialog1.FileName,Length(SaveDialog1.FileName)-2,3)) <>
      UpperCase(Ext) then
     SaveDialog1.FileName := SaveDialog1.FileName + '.' + Ext;
    SaveDBGridEhToExportFile(ExpClass,TDBGridEh(ActiveControl),
       SaveDialog1.FileName,False);
   end;
  end;
end;



// 功能:設定 DbGridEh 合計行信息
// 參數: pDbGrid:TDBGridEh;
//     pcFields : string ; 字段列表,字段用逗號分隔
//     pvtType : TFooterValueType ; 統計類型 TFooterValueType = (fvtNon, fvtSum, fvtAvg, fvtCount, fvtFieldValue, fvtStaticText);
// 引用:
// 例如:DbGridEhFoot( DbGridEh1, &acute;Number,Sum&acute;, fvtSum ); 設定數量和金額字段為合計統計
//--------------------------------------------------------------------------------
Procedure DbGridEhFoot( pDbGrid:TDBGridEh; pcFields: string; pvtType : TFooterValueType );
var nFldLoop : integer ;
   cFieldName : string ;
   tmpFldList : TStrings ;
begin
  pDbGrid.FooterRowCount := 1;   // 指定網格尾部統計行行數
  pDbGrid.SumList.Active := true;  // 激活統計
  pDbGrid.FooterColor   := clBtnFace ;  // 指定統計行顏色
  tmpFldList := TStringList.Create ;
  StrToStringList( Uppercase(pcFields),&acute;,&acute;,tmpFldList );  // 將字符串轉換為串列表
  For nFldLoop := 0 to pDbGrid.Columns.Count -1 do
  begin
    cFieldName := pDbGrid.Columns[nFldLoop].FieldName ;  // 網格列字段名
    if tmpFldList.IndexOf( uppercase( cFieldName ) ) >= 0 then
    begin
     pDbGrid.Columns[nFldLoop].Footer.ValueType := pvtType ;  // 統計類型
    end;
  end ;
  tmpFldList.Free ;
end;



 
 
 
一、如何在程序中確定Ehlib定義的報表表頭顏色? 
在執行打印之前,加上下面的語句:
DBGridEh1.FixedColor:=clLime;//clLime可以換成你想要的顏色比如clRed是紅色等等
PrintDBgridEh1.Options:=[pghColored,pghFitingByColWidths];//方括號里的"pghColored"是必需的,其它的根據你的需要決定取舍

二、Ehlib中的PrintDBGridEh如何印頁碼,即第幾頁共幾頁
PrintDBGridEh.PageFooter.CenterText:='第&[Page]頁 共&[Pages]頁'
在對象管理器中的相關位置有設

三、本人剛學習使用ehlib包,現在要實現類似ehlib所帶demo1中一個功能:點擊dbgrid某列值
的下拉按紐(可以設置),彈出一個下拉列表(其內容是另一個dataset的)。我看demo1中
好象是使用了DBLookupComboboxEh,可我參看demo1怎么設置也不行,請指教。謝謝。

呵呵,這個效果沒有用DBLoookupComboBoxEh,它是利用查找字段實現的。
它在Query1中,對應VName字段,增加了一個叫VName1的查找字段,這個
字段從qrVendors查找相關的數據,再在DBGridEh1顯示VName1,這樣顯示
就是那種效果了。 

四、Ehlib 怎樣固定某幾列?
只要設置dbGridEh的FrozenCols屬性為幾列即可.
3 使用 TDBGridEh 組件
理解 TDBGridEh, TDataLink 以及 TDataSet. 
All below text in equal degrees pertains as to TDBGridEh component as to TDBGrid component.
A TDBGridEh control lets you view and edit records in a dataset in a tabular grid format.
TDBGridEh does not story data in in itself, it only show data from dataset via TDataLink object. Every database control have internal TDataLink object to interaction with dataset. You can connect TDBGridEh to dataset using DataSource property. If you already use TStringGrid component you can see that data shows in TStringGrid and in TDBGridEh very similarly, but mechanism that use to show data in TStringGrid and in TDBGridEh very different. In TStringGrid count of rows is equal of rows in array of strings while in TDBGridEh (and TDBGrid) count of rows always not more then count of visible rows and although vertical scrollbar can display thumb position regarding the count of record in dataset it take info not from grid but directly from dataset. TDataSet don't allows us to work with data as with array of data i.e. we can not quickly get value of the field from certain record, some types of dataset have not even such notion as record number (in such datasets we can only know that we inhere in the begin of dataset or in the end of its or somewhere between, in that case DBGrid shows vertical vertical scrollbar only in three positions). But to have possibility to draw several record simultaneously TDataLink object allows to have buffer of records (record buffer window) with quick readonly access. DBGrid use this possibility of datalink and set size of record buffer window equal of count of visible rows in grid. We can not control what record must be first in this buffer, DataLink itself scroll record buffer window then we navigate through the dataset and it control the scrolling of record buffer window as that the active record as always in record buffer window. It is a reason why the active record change position when users change thumb position of vertical scrollbar using mouse. 

TDBGridEh和縱向滾動條 
If you works with different type of dataset you can notice that for some type of dataset DBGrid show vertical scrollbar validly but for over vertical scrollbar have only three position independently of record count in dataset. To set vertical scrollbar accomodation DBGrid use RecordCount and RecNo property of DataSet component. But some dataset and even same dataset under some condition holds -1 in RecordCount and RecNo. DataSet function IsSequenced indicates whether the underlying database table uses record numbers to indicate the order of records. When IsSequenced returns True, applications can safely use the RecNo property to navigate to records in the dataset and DBGrid use RecNo property to show thumb position in vertical scrollbar. But when IsSequenced returns False DBGrid can not define current record position and show vertical scrollbar in three positions. DBGridEh component have possibility to show proportional scrollbar for no sequenced dataset. To do it need to activate SumList and create list of record bookmars. Set SumList.Active to True and SumList.VirtualRecords to True. SumList will run through dataset and create list of record bookmarks, if you use client/sever technology to access database SumList will force dataset to fetch all records, so it operation can take much time. Keep in mind that VirtualRecords will work only for full relationship bookmarks dataset, it means that DataSet.ComapreBookmark function has to return > 0 if bookmark1 > bookmark1 (i.e. record to which indicates bookmark1 have to be after record to which indicates bookmark1), = 0 if bookmark1 = bookmark1, < 0 if bookmark1 = bookmark1. TBDEDataSet in most cases support full relationship bookmarks.


定制網格標題 
復雜標題 
TDBGridEh 允許在多列上創建標題,例如: 

設置 DBGridEh.UseMultiTitle 屬性為 True 並且填充字段的標簽或列標題的標題,可以使用下面的規則:字段標簽中的文本部分或列標題必須由幾部分組成,並且用 "|" 分割,幾個列的每一個通用部分都設置為相同。其它字段或標題必須在相應的部分包含同樣的文本。 

例如:

Field1.DisplayLabel := 'Title1|SubTitle1';
Field2.DisplayLabel := 'Title1|SubTitle2';
或
DBGridEh.Columns[0].Title.Caption := 'Title1|SubTitle1';
DBGridEh.Columns[1].Title.Caption := 'Title1|SubTitle2'; 
按鈕式標題 
設置Column.Title.TitleButton 為 True可以強制標題單元為按鈕式。寫 OnTitleBtnClick事件來控制用戶單擊標題單元時的操作。 

在標題中顯示位圖 
To show bitmap in titles instead of caption use TitleImages property of TDBGridEh and ImageIndex property of TColumnTitleEh. 

自動用位置標識排序標題. 
TDBGridEh allows to show special sortmarking bitmaps (small triangles) in the right part of title cell. In order to automatically marking title by sortmarking bitmaps add dghAutoSortMarking to OptionsEh property. Add dghMultiSortMarking too in order to allow sortmarking several columns simultaneously. Set Column.Title.TitleButton to true for titles which will have possibility to change sortmarkers at run time. At runtime clicking on title will change sortmarking. Holding Ctrl key allows to mark several columns simultaneously. After user change sormarking grid call OnSortMarkingChanged event. You can write this event to change sorting and reopen in dataset. Use SortMarkedColumns property to access to sortmarked columns. 

標題屬性的默認值 
使用TDBGridEh.ColumnDefValues.Title來設置標題屬性的默認值。 

定制網格頁腳 
頁腳以及統計值 
TDBGridEh allows to show special row (footer) or rows at bottom part. Use FooterRowCount property to specify the number of footer rows in the grid. Use Footer or Footers property of TColumnEh object to specify information which need to show in footer cells. Footers property useful then you have more then one footer rows. Footers is a collection of TColumnFooterEh objects where information from i-th aliment of collection will be show in i-th cell of footer column. In footer cell, it is possible to show: Sum value for specified field, record count, value of a specified field or static text. Use property Footer.ValueType or Footers[i].ValueType to specify which type of value will be show in footer cell. If ValueType = fvtStaticText, then set the property Value to specify text which need to show. If ValueType = fvtFieldValue, then you need to set property FieldName to specify field, value of which need to show. To force grid to calculate total values need to activate SumList (DBGridEh.SumList.Active := True). Set ValueType to fvtSum and grid must to show sum value of the column field in the footer cell, you can also specify Column.Footer.FieldName to calculate total value of the other field. Set ValueType to fvtCount to force grid to show count of records in the footer cell.


定制網格數據單元 
在數據單元中顯示字段值為圖形。 
TDBGridEh allows to show bitmaps from TImageList component depending on field values. To show bitmaps depending on field values need: Fill list of field values to Column.KeyList property (every value in separate line) and set Column.ImageList property to ImageList control that has the bitmap in according index. Set Column.NotInKeyListIndex to index of bitmap that will be shown if field's value does not correspond to any value in KeyList (for instance you can set index of image for Null field value). At run time you are not allowed to edit bitmap in column cell. Use blank key and mouse click to set next value from Column.KeyList to the field; Shift-blank key and Shift-Mouse click to set previous value from Column.KeyList. Set Column.DblClickNextval to True have allows to change value on mouse double click. 

檢查框式的邏輯及非邏輯值
Grid automatically shows checkboxes for boolean field. To show checkboxes for non boolean fields fill first line of Column.KeyList property that corresponds to the checked state of the checkbox, second line - non checked state, and set Column.Checkboxes ptoperty to True. Line of KeyList can represent more than one value in a semicolon-delimited list of items. 

數據行高度 
使用 RowHeight 和 RowLines 屬性來指定數據行高。完整的數據行高 = 行線高度+行高。設置 RowSizingAllowed 為 True 以允許可以在運行是使用鼠標來改變行高。

設置Column.WordWrap為True可以使數據行中文本多行顯示。如果行高>文本行,它就換行。 

顯示備注字段 
設置 DrawMemoText to True來顯示文本式的備注字段。. 

定制單元格字體及顏色 
TDBGridEh 中的 Font 和 Color 屬性描述了數據網格中繪制單元格的字體和顏色。
TColumnEh 中的 Font 和 Color 屬性描述了指定列中繪制單元格的字體和顏色。 

事件定制單元格字體及顏色 
有幾個事件可以讓你能夠在繪制單元格前定制單元格字體和顏色。你可以寫TDBGridEh的OnDrawColumnCellEvent事件句柄來在控制在網格單元中繪制數據。你可以使用Canvas屬性的方法來繪制單元格。但是如果你只想改變字體或顏色的屬性,我建議你使用下面的事件。你可以寫TDBGridEh的OnGetCellParams事件來控制在繪制數據單元以前所指定的操作。你可以改變繪制字體及背景色。這個事件適合你在想改變整行的字體或顏色時使用。如果你想改變指定列中單元格的屬性,你可以使用TColumnEh.OnGetCellParams。寫這個事件用來控制在一列數據單元被重繪或編輯時的操作。在一列數據單元被重繪以前,你可以改變繪制字體,背景色,對齊方式,圖像索引,文本或檢查框。在編輯一列數據單元以前,你可以改變編輯字體,背景色,文本或只讀狀態。 

列屬性的默認值 

使用ColumnDefValues屬性來設置列屬性的默認值。新創建的列將從ColumnDefValues屬性中獲得屬性值,並且直到第一次為其指定值為止。


在網格的適當位置放置編輯器. 
在下拉列表中顯示幾個字段。 
在下拉列表中顯示幾個下拉字段,需要設置列的LookupDisplayFields屬性到字段的Semicolons屬性來分割多個字段名。命名為Column.Field.LookupResultField的屬性必須位於LookupDisplayFields列表中。多字段的下拉列表只能應用於下拉字段。 

顯示下拉方式的列 

你可以通過KeyList 和 PickList 屬性在相關的的字段中顯示其它文本。KeyList顯示包含在字段的值而非PickList索引所包含的值。 Column.NotInKeyListIndex to index of text from PickList that will be shown if field value do not contain in KeyList (for instance you can set index of text for Null field value). Set Column.DblClickNextval to True to change value on mouse double click. 

下拉式計算器 
對於 TDateField 和 TDateTimeField 字段,inplace 編輯器將顯示下拉按鈕以顯示顯示下拉計算器。設置 Column.ButtonStyle 為 cbsNone 以禁止顯示下拉按鈕。 

設置編輯器顏色和字體 
Inplace編輯器可以設置數據單元的顏色和字體。數據單元使用OnGetCellParams 事件來控制列的顏色和字體。 Inplace 編輯器在行高>一行的高度時自動設置為多行模式並且將列的屬性 WordWrap 設置為True.


自動填充網格列寬到網格客戶區 
設置AutoFitColWidths為True以自動重置列寬來設置網格的寬度等於客戶區寬度。 MinAutoFitWidth 屬性決定網格的最小寬度,列寬將會被重新計算。 
3D或平面外觀 
使用 OptionsEh 屬性來顯示/隱藏固定的3D框架,冷區,頁腳以及數據行。 

使用 Flat 屬性來設置用平面方式顯示數據網格。 

從多種格式導入/導出數據到TDBGridEh。 
EhLib 的函數集可以從DBGridEh導出數據到Text, Csv, HTML, RTF, XLS以及其內部格式。它可以保存數據到流(TStream對象)或文件。 

例子
Pascal: SaveDBGridEhToExportFile(TDBGridEhExportAsText,DBGridEh1,'c:\temp\file1.txt',False);
C++: SaveDBGridEhToExportFile(__classid(TDBGridEhExportAsText),DBGridEh1,"c:\\temp\\file1.txt",false); 

EhLib 的函數集可以從 Text以及其內部格式的數據導入到DBGridEh的數據集中。它可以從文件中讀取數據或讀取數據到流(TStream對象)。 

其它特性 
用lookup 編輯器,你可以在運行時清空(設置為Null) LookupKeyField 值。比如選擇整個文本然后按Delete鍵。 

冷區 
冷區是數據網格列集左邊顯示的不可滾動的區域。與固定列不同的是,冷區的列可以獲得編輯焦點。可以通過設置FrozenCols屬性來設置右邊不可滾動的列集。 

增量搜索 

TDBGridEh 允許用戶在網格列中實現特定的“增量”搜索。當用戶進入增量搜索時他可以顯示字符以及網格,並且在當前的列中查找文本。使用 dghIncSearch 和 dghPreferIncSearch的值(在OptionsEh 選項中) 在數據網格中操作增量搜索。 dghIncSearch 值允許在數據網格中進行增量搜索。運行時你能夠使用下面的鍵進行增量搜索:

Ctrl+F - 開始增量搜索。
Ctrl+Enter - 查找下一個匹配記錄。
Ctrl+Shift+Enter - 查找前一個匹配記錄。

如果OptionsEh選項中的 dghIncSearch 是只讀的,那么網絡將自動設置增量模式在第一次按鍵以及1.5秒后返回普通模式。 dghPreferIncSearch 值決定網格設置自動增量搜索模式在第一次按鍵時替代單元編輯。

水平或垂直滾動條 
使用 VertSctollbar, HorzSctollbar 屬性來顯示/隱藏以及跟蹤水平或垂直滾動條。 

多選 
TDBGridEh 允許在選定的區域上進行選擇記錄,列以及矩形區域等操作: 

允許多選會影響下面這些屬性: 

Options選項中的dgMultiSelect屬性 - 設置是否允許多選。 

Options選項中的dghClearSelection 屬性- 設置在用戶移到下一個單元時是否清除已選記錄。 

Options選項中的EditActions屬性 -設置用戶可以在已選記錄上執行哪些操作(比如,拷貝,剪切,刪除,粘貼,全選等)。 

Options選項中的AllowedSelections屬性-設置允許選定記錄的類型(比如,行,列,矩形區域等)。 

Options選項中的Selection屬性-設置一個當前的多選狀態,已選記錄,列或矩形區域以及存取它們的屬性和函數。 

從注冊表或ini文件中保存或恢復網格和列的層次。 
TDBGridEh 有一個常規設置來從注冊表或ini文件中保存和恢復網絡以及列的層次: 

RestoreColumnsLayout - 從注冊表中恢復列的次序,寬度,排序標志。 

RestoreColumnsLayoutIni - 從ini文件中恢復列的次序,寬度,排序標志。 

RestoreGridLayout - 從注冊表中恢復列的次序,寬度,可視,排序標志,排序索引或行高。 

RestoreGridLayoutIni - 從ini文件中恢復列的次序,寬度,可視,排序標志,排序索引或行高。 

SaveColumnsLayout - 保存列的次序,寬度,排序標志到注冊表中。 

SaveColumnsLayoutIni - 保存列的次序,寬度,排序標志到ini文件中。 

SaveGridLayout - 保存列的次序,寬度,可視,排序標志,排序索引或行高到注冊表中。 

SaveGridLayoutIni - 保存列的次序,寬度,可視,排序標志,排序索引或行高到ini文件中。 

當前版本的TDBGridEh不支持的特性: 
這個版本的TDBGridEh不支持下面的特性: 

TDBGridEh 不能設置每一個數據窗口中單獨行的行高。 

TDBGridEh 不能象TreeView那樣工作。它不能擁有節點和枝葉。 

TDBGridEh 不能橫向或縱向合並數據單元。 

將已存在的TDBGrid組件轉換為TDBGridEh組件: 

盡管TDBGridEh並不是從TCustomDBGrid組件繼承而來的,但是在TDBGridEh和TDBGrid中還是有一些相似的屬性。 

它允許僅用一點點代價來轉換已存在的TDBGrid組件到TDBGridEh。 

可以按照下面的提示來轉轉換已存在的TDBGrid組件到TDBGridEh: 

在Delphi的IDE中打開包含有TDBGrid組件的應用程序。 

設置視圖方式為文本方式(Alt-F12)。 

將所有的TDBGrid對象改名為TDBGridEh('比如,將object DBGrid1: TDBGrid'改為 'object DBGrid1: TDBGridEh')

重新編譯你的應用程序。 



5 使用 TDBSumList 組件
TDBSumList說明 
你可以使用TDBSumList在可視動態變化數據集中進行記錄統計。在你想查看的數據集中設置相關的數據字段,然后寫 SumListChanged 事件來指定在TDBSumList發生改變后所要做的操作。TDBSumList 的 SumCollection 屬性上一個 TDBSum 對象容器。每個 TDBSum 對象是一個可以指定集合值的元件。 FieldName 和 GroupOperation 決定了集合值的類型,SumValue 控制當前的集合值。

TDBSumList 被埋藏於 DBGridEh 組件中,因此所的下面有關TDBGridEh.SumList 的說明與TDBGirdEh的TDBGridEh.SumList 屬性的說明是一樣的。

如何工作以及為什么有時SumList的集合值計算不正確?
你知道 data-aware 控件與數據集是通過 TDataLink 對象相連接的。 TDataLink 不允許快速重新計算集合值。例如,當從數據集中刪除記錄時,數據集發送deDataSetChange事件給所有的TDataLink對象,在當前局部過濾發生改變時,同樣的事件也被發送了。因此當 TDataLink 接收到該事件時,它不得不在所有的數據集中重新計算集合值,甚至於僅從數據集中刪除一條記錄。在激活后, TDBSumList 重載了數據集的下列事件: OnAfterEdit, OnAfterInsert, OnAfterOpen, OnAfterPost, OnAfterScroll, OnBeforeDelete, OnAfterClose。這種方法避免了在所有的數據集中它。在不需要它時,又會出現其它的問題,比如: T
運行時指定這些事件。在指定上述事件之一以前,關閉 SumList。
在下面的情形下,SumList 發出存取錯誤信息。 SumList 試着向數據集返回事件,但數據集數據並未被刪除。在SumList(或網格)以及數據集放置在不同的窗體(數據模塊)這種情況下,可以顯示數據。在這種情況下,試着在從數據集或數據模塊中數據集數據被刪除時關閉SumList。
如果你使用SetRange或ApplyRange事件,SumList 將不能跟蹤數據集中發生的變化。但可以調用 SumList.RecalAll 方法。
在非BDE數據集的主/明細表中,SumList 不能跟蹤數據變化。在主數據集激活狀態數據集發生變化后,調用 SumList.RecalAll 方法。
在任何其它情況下,如果你發現了其它SumList的計算值不正確,你都可以調用 RecalAll方法。 
 

4 使用 TPrintDBGridEh 組件 
在 Delphi 的 IDE 組件面板中選擇 TPrintDBGridEh 並拖放其到 form 上。在 其 DBGridEh 屬性中設置為相應的 TDBGridEh 組件。使用 Print 以及 Preview 方法在打印機上打印網格或者在預覽窗體中預覽網格。 
網格前以網格后的 RTF 文本 
TPrintDBGridEh 允許在打印 / 打印預覽網格前或網格后的 RTF 文本。使用 AfterGridText 以及 BeforeGridText 屬性來指定文本。 你可以在打印 / 打印預覽時通過 BeforeGridText 和 AfterGridText 屬性來替換文本內容。 
當前版本的 TPrintDBGridEh 不支持的特性。 
這個版本不支持下面的特性: 
TPrintDBGridEh 不能在一頁中打印 / 打印預覽多個網格。 
問答列表 : 
問 : 怎樣進行橫向打印 / 打印預覽? 
答 : TPrintDBGridEh 並沒有專六的屬性來設置頁面特性。在調用打印或打印預覽方法前,你必須設置你將要執行打印的打印源( Orientation )。 
uses ......, PrViewEh, Printers. 
.............. 
procedure TForm1.bPreviewClick(Sender: TObject); 
begin 
PrinterPreview.Orientation := poLandscape; 
PrintDBGridEh1.Preview; 
end ;


DBGrid介紹:
在 Delphi 語言的數據庫編程中,DBGrid 是顯示數據的主要手段之一。但是 DBGrid 缺省的外觀未免顯得單調和缺乏創意。其實,我們完全可以在我們的程序中通過編程來達到美化DBGrid 外觀的目的。通過編程,我們可以改變 DBGrid 的表頭、網格、網格線的前景色和背景色,以及相關的字體的大小和風格。
   以下的示例程序演示了對 DBGrid 各屬性的設置,使 Delphi 顯示的表格就像網頁中的表格一樣漂亮美觀。
   示例程序的運行:
   在 Form1 上放置 DBGrid1、Query1、DataSource1 三個數據庫組件,設置相關的屬性,使 DBGrid1 能顯示表中的數據。然后,在 DBGrid1 的 onDrawColumnCell 事件中鍵入以下代碼,然后運行程序,就可以看到神奇的結果了。本代碼在 Windows98、Delphi5.0 環境下調試通過。
procedure TMainForm.DBGrid1DrawColumnCell(Sender: TObject;
 const Rect: TRect; DataCol: Integer; Column: TColumn;State: TGridDrawState);
var i :integer;
begin
 if gdSelected in State then Exit;
//定義表頭的字體和背景顏色:
   for i :=0 to (Sender as TDBGrid).Columns.Count-1 do
   begin
     (Sender as TDBGrid).Columns[i].Title.Font.Name :='宋體'; //字體
     (Sender as TDBGrid).Columns[i].Title.Font.Size :=9; //字體大小
     (Sender as TDBGrid).Columns[i].Title.Font.Color :=$000000ff; //字體顏色(紅色)
     (Sender as TDBGrid).Columns[i].Title.Color :=$0000ff00; //背景色(綠色)
   end;
//隔行改變網格背景色:
 if Query1.RecNo mod 2 = 0 then
   (Sender as TDBGrid).Canvas.Brush.Color := clInfoBk //定義背景顏色
 else
   (Sender as TDBGrid).Canvas.Brush.Color := RGB(191, 255, 223); //定義背景顏色
//定義網格線的顏色:
   DBGrid1.DefaultDrawColumnCell(Rect,DataCol,Column,State);
 with (Sender as TDBGrid).Canvas do //畫 cell 的邊框
 begin
   Pen.Color := $00ff0000; //定義畫筆顏色(藍色)
   MoveTo(Rect.Left, Rect.Bottom); //畫筆定位
   LineTo(Rect.Right, Rect.Bottom); //畫藍色的橫線
   Pen.Color := $0000ff00; //定義畫筆顏色(綠色)
   MoveTo(Rect.Right, Rect.Top); //畫筆定位
   LineTo(Rect.Right, Rect.Bottom); //畫綠色的豎線
 end;
end; 

 問題: Delphi5 - 隔行改變DBGrid網格顏色   在 Form1 上放置 DBGrid1、Query1、DataSource1 三個數據庫組件,設置相關的屬性,使 DBGrid1 能顯示表中的數據。然后,在 DBGrid1 的 onDrawColumnCell 事件中鍵入以下代碼,然后運行程序

代碼:
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);

var i:integer;
begin
 if gdSelected in State then Exit;  //隔行改變網格背景色: 
   if adoQuery1.RecNo mod 2 = 0 then
     (Sender as TDBGrid).Canvas.Brush.Color := clinfobk //定義背景顏色
 else
   (Sender as TDBGrid).Canvas.Brush.Color := RGB(191, 255, 223);  //定義背景顏色

 //定義網格線的顏色:
 DBGrid1.DefaultDrawColumnCell(Rect,DataCol,Column,State);
 with (Sender as TDBGrid).Canvas do //畫 cell 的邊框
 begin
   Pen.Color := $00ff0000; //定義畫筆顏色(藍色)
   MoveTo(Rect.Left, Rect.Bottom); //畫筆定位
   LineTo(Rect.Right, Rect.Bottom); //畫藍色的橫線
   Pen.Color := clbtnface; //定義畫筆顏色(蘭色)
   MoveTo(Rect.Right, Rect.Top); //畫筆定位
   LineTo(Rect.Right, Rect.Bottom); //畫綠色
 end;
end;

用BDE中的table1未能通過,顏色沒有隔行變化。  

 
 2003-11-11 17:12:09    在Delphi的DBGrid中插入其他可視組件   Delphi提供了功能強大的 DBGrid組件,以方便進行數據庫應用程序設計。但是如果我們僅僅利用DBGrid組件,每一個獲得焦點(Grid)只是一個簡單的文本編輯框,不方便用戶輸入數據。Delphi也提供了一些其他數據組件來方便用戶輸入,比如DBComboBox,DBCheckBox等組件,但這些組件卻沒有DBGrid功能強大。Delphi能不能象Visual Foxpro那樣讓DBGrid中獲得焦點網格可以是其它可視數據組件以方便用戶呢?其實我們可以通過在DBGrid中插入其他可視組件來實現這一點。

   Delphi對DBGrid處理的內部機制,就是在網格上浮動一個組件——DBEdit組件。你輸入數據的網格其實是浮動DBEdit組件,其他未獲得焦點地方不過是圖像罷了。所以,在DBGrid中插入其他可視組件就是在網格上浮動一個可視組件。因此任何組件,包括從簡單的DbCheckBox到復雜的對話框,都可以在DBGrid中插入。下面就是一個如何在DBGrid中插入DBComboBox組件的步驟,采用同樣的辦法可以插入其他組件。

 1、在Delphi 4.0中新建一個項目。

 2、分別拖動的Data Access組件板上DataSource、Table,Data Controls組件板上DBGrid,DBComboBox四個組件到Form1上。

 3、設置各個組件的屬性如下:

rcf1對象 屬性 設定植
Form1 Caption '在DBGrid中插入SpinEdit組件示例'
DataSource1 DataSet Table1
Table1 DatabaseName DBDEMOS
TableName 'teacher.DBF'
Active True
DBGrid1 DataSource DataSource1
DBComboBox1 DataField SEX
DataSource DataSource1
Visible False
Strings Items. '男'| '女'

注意:我在這里用了Teacher.dbf,那是反映教職工的性別,只能是“男”或者是“女”。

 4、DrawDataCell事件是繪制單元格,當獲得焦點網格所對應的字段與組合框所對應的字段一致時,移動組合框到獲得焦點的網格上,並且使組合框可視,從而達到在DBGrid指定列上顯示DBComboBox的功能。設置DBGrid1的OnDrawDataCell事件如下:

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState);
begin
 if (gdFocused in State) then
 begin
   if (Field.FieldName = DBComboBox1.DataField ) then
   begin
     DBComboBox1.Left := Rect.Left + DBGrid1.Left;
     DBComboBox1.Top := Rect.Top + DBGrid1.top;
     DBComboBox1.Width := Rect.Right - Rect.Left;
     DBComboBox1.Height := Rect.Bottom - Rect.Top;
     DBComboBox1.Visible := True;
   end;
 end;
end;

 5、DBGrid指定單元格未獲得焦點時不顯示DBComboBox,設置DBGrid1的OnColExit事件如下:
procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
 If DBGrid1.SelectedField.FieldName = DBComboBox1.DataField then
   begin
     DBComboBox1.Visible := false;
   end;
end;

 6、當DBGrid指定列獲得焦點時DrawDataCell事件只是繪制單元格,並顯示DBComboBox,但是DBComboBox並沒有獲得焦點,數據的輸入還是在單元格上進行。在DBGrid1的KeyPress事件中調用SendMessage這個 Windows API函數將數據輸入傳輸到DBComboBox上,從而達到在DBComboBox上進行數據輸入。因此還要設置KeyPress事件如下:

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
 if (key < > chr(9)) then
 begin
   if (DBGrid1.SelectedField.FieldName =DBComboBox1.DataField) then
   begin
     DBComboBox1.SetFocus;
     SendMessage(DBComboBox1.Handle,WM_Char,word(Key),0);
   end;
 end;
end;

   程序在中文Windows 98,Delphi 4.015 下調試通過。希望本文能使你可以更加方便快捷的開發數據庫應用程序。  

 
 2003-11-11 17:17:56    鎖定DBGrid左邊的列    我在使用 Delphi3 進行數據庫編程的時候,希望 DBGRID 構件在顯示數據的時候能象FoxPro 的 BROWSE 命令一樣,鎖定左邊指定的幾列不進行滾動,請問應用什么方法來實現?

   我們知道 Delphi 的 TStringGrid 有一個屬性 FixedCols 來指定不滾動的列。雖然TDBGrid 不能直接使用這一屬性,但通過強制類型轉換也可以首先這一功能,因為這兩個類都來自 TCustomGrid 類。下面我們以 Delphi 3.0的 Demos\Db\CtrlGrid 為例來說明具體的用法。在這個例子的 TFmCtrlGrid.FormShow 過程中加入如下一行: 

   TStringGrid(DbGrid1).FixedCols := 2; 

   運行該程序,在左右移動各列時,Symbol 列不會移動。除了這種方法,也可以采用下面的方法:首先在 Form 聲明部分加上

   type TMyGrid = Class(TDBGrid) end; 

   然后在 TFmCtrlGrid.FormShow 過程中加入: 

   TMyGrid(DbGrid1).FixedCols := 2; 

   兩者從形式上略有不同,但實質都是一樣的。我們這里設置 FixedCols 為 2,這是因為在 DBGrid 構件最左側有個指示列,如果你將 DBGrid 的 Options 屬性的 dgIndicator 設為False,則應設置 FixedCols 為1。  

 
 2003-11-11 17:21:36    使dbgrid的某幾筆資料變色   你可在 DBGrid 元件的 DrawDataCell 事件中依資料的條件性來改變格子或文字的顏色.
如 :

OnDrawDataCell(...)
begin
 with TDBGrid(Sender) do
 begin
   if (條件) then
     Canvas.TextOut(Rect.Left + 4
   Rect.Top + 2

'要顯示的文字如表格的資料');
end;

   而你會看到 DBGrid 的顯示資料怎麽有重疊的情況那是因為原本DBGrid要顯示的資料與 TextOut 所顯示的資料重疊
   解決方法 :
   在 Query 元件所加入的欄位(在元件上按右鍵會有 Add Fields...的選單)在不要顯示資料的欄位的 OnGetText 事件中有一參數設定為 False;

procedure TForm1.Query1Detail1GetText(Sender: TField; var Text: string;
DisplayText: Boolean);
begin
 // 決定在 DBGrid 得知表格資料時要不要顯示所得到的資料False -> 不顯示
 // 就可避免與 TextOut 的文字重疊了
 DisplayText : = False;
end;
end;

   如果用 Delphi 3 處理很簡單.例如:對表中某字段當其數值小於0時為紅字其他為黑字.
在 DBGrid.OnDrawColumnCell(...) 中:

begin
 if TableField.AsInteger < 0 then
   DBGrid.Canvas.Font.Color := clRed
 else
   DBGrid.Canvas.Font.Color := clBlack;
 DBGrid.DefaultDrawColumnCell(...);
end;

這樣對 Field 指定的格式仍舊生效不必重寫.  

 
 2003-11-11 17:25:29    實戰Delphi數據網格色彩特效   Delphi中的數據網格控件(TDbGrid)對於顯示和編輯數據庫中大量的數據起着十分重要的作用;然而,在使用數據網格控件的同時,也往往因為表格中大量的數據不易區分,而令操作者眼花繚亂。如何提高網格控件的易用性,克服它的此項不足呢?本文從改變數據網格的色彩配置角度,提出了一種解決辦法。

   以下為數據網格控件的6種特殊效果的實現方法,至於數據網格控件與數據集如何連接的方法從略。

1. 縱向斑馬線效果:實現網格的奇數列和偶數列分別以不同的顏色顯示以區別相鄰的數據列。
file://在DbGrid的DrawColumnCell事件中編寫如下代碼:

Case DataCol Mod 2 = 0 of
True: DbGrid1.Canvas.Brush.Color:= clBlue; file://偶數列用藍色
False: DbGrid1.Canvas.Brush.Color:= clAqua; file://奇數列用淺綠色
End;
DbGrid1.Canvas.Pen.Mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect
DataCol
Column
State);

2. 縱向斑馬線,同時以紅色突出顯示當前單元格效果:以突出顯示當前選中的字段。

file://將上述代碼修改為:
Case DataCol Mod 2 = 0 of
True: DbGrid1.Canvas.Brush.Color:= clBlue; file://偶數列用藍色
False: DbGrid1.Canvas.Brush.Color:= clAqua; file://奇數列用淺綠色
End;
If ((State = [gdSelected]) or (State=[gdSelectedgdFocused])) then
If Not DbGrid1.SelectedRows.CurrentRowSelected then
DbGrid1.Canvas.Brush.Color:=clRed; file://當前選中單元格顯示紅色
DbGrid1.Canvas.Pen.Mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect 
DataCol 
Column 
State);

上述兩種方法突出了列的顯示效果。

3.在數據網格中以紅色突出顯示當前選中的行。
   設置DbGrid控件的Options屬性中的dgRowSelect屬性為真,Color屬性為clAqua(背景色)
在DbGrid的DrawColumnCell事件中編寫如下代碼:

if ((State = [gdSelected]) or (State=[gdSelected gdFocused])) then
DbGrid1.Canvas.Brush.color:=clRed; file://當前行以紅色顯示,其它行使用背景的淺綠色
DbGrid1.Canvas.pen.mode:=pmmask;
DbGrid1.DefaultDrawColumnCell (Rect
DataCol
Column
State);

4.行突顯的斑馬線效果:既突出當前行,又區分不同的列(字段)。

file://其它屬性設置同3,將上述代碼修改為:
if ((State = [gdSelected]) or (State=[gdSelectedgdFocused])) then
begin
Case DataCol Mod 2 = 0 of
True : DbGrid1.Canvas.Brush.color:=clRed; file://當前選中行的偶數列顯示紅色
False: DbGrid1.Canvas.Brush.color:=clblue; file://當前選中行的奇數列顯示藍色
end;
DbGrid1.Canvas.pen.mode:=pmmask;
DbGrid1.DefaultDrawColumnCell (Rect
DataCol
Column
State);
end;

5.橫向斑馬線, 同時以紅色突顯當前行效果。

file://其它屬性設置同3,將上述代碼修改為:
Case Table1.RecNo mod 2 = 0 of file://根據數據集的記錄號進行判斷
True : DbGrid1.Canvas.Brush.color:=clAqua; file://偶數行用淺綠色顯示
False: DbGrid1.Canvas.Brush.color:=clblue; file://奇數行用藍色表示
end;
if ((State = [gdSelected]) or (State=[gdSelectedgdFocused])) then file://選中行用紅色顯示
DbGrid1.Canvas.Brush.color:=clRed;
DbGrid1.Canvas.pen.mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect
DataCol
Column
State);

6.雙向斑馬線效果:即行間用不同色區分,同時,選中行以縱向斑馬線效果區分不同的列。

file://其它屬性設置同3,將上述代碼修改為:
Case Table1.RecNo mod 2 = 0 of file://根據數據集的記錄號進行判斷
True : DbGrid1.Canvas.Brush.color:=clAqua; file://偶數行用淺綠色顯示
False: DbGrid1.Canvas.Brush.color:= clblue; file://奇數行用藍色表示
end;
If ((State = [gdSelected]) or (State=[gdSelectedgdFocused])) then
Case DataCol mod 2 = 0 of
True : DbGrid1.Canvas.Brush.color:=clRed; file://當前選中行的偶數列用紅色
False: DbGrid1.Canvas.Brush.color:= clGreen; file://當前選中行的奇數列用綠色表示
end;
DbGrid1.Canvas.pen.mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect
DataCol
Column
State);

   上述6種方法分別就數據網格控件的列和行的色彩進行了設置,讀者可以根據自己的需要設置特效。該程序在Delphi5中測試通過。  

 
 2003-11-13 11:11:31    點擊DBGrid的Title對查詢結果排序 關鍵詞:DBGrid 排序  

   欲實現點擊DBGrid的Title對查詢結果排序,想作一個通用程序,不是一事一議,例如不能在SQL語句中增加Order by ...,因為SQL可能原來已經包含Order by ...,而且點擊另一個Title時又要另外排序,目的是想作到象資源管理器那樣隨心所欲。

procedure TFHkdata.SortQuery(Column:TColumn);
var
 SqlStr,myFieldName,TempStr: string;
 OrderPos: integer;
 SavedParams: TParams;
begin
 if not (Column.Field.FieldKind in [fkData,fkLookup]) then exit;
 if Column.Field.FieldKind =fkData then
   myFieldName := UpperCase(Column.Field.FieldName)
 else
   myFieldName := UpperCase(Column.Field.KeyFields);
 while Pos(myFieldName,';')<>0 do
 myFieldName := copy(myFieldName,1,Pos(myFieldName,';')-1)+ ',' + copy(myFieldName,Pos(myFieldName,';')+1,100);
 with TQuery(TDBGrid(Column.Grid).DataSource.DataSet) do
 begin
   SqlStr := UpperCase(Sql.Text);
   // if pos(myFieldName,SqlStr)=0 then exit;
   if ParamCount>0 then
   begin
     SavedParams := TParams.Create;
     SavedParams.Assign(Params);
   end;
   OrderPos := pos('ORDER',SqlStr);
   if (OrderPos=0) or (pos(myFieldName,copy(SqlStr,OrderPos,100))=0) then
     TempStr := ' Order By ' + myFieldName + ' Asc'
   else if pos('ASC',SqlStr)=0 then
     TempStr := ' Order By ' + myFieldName + ' Asc'
   else
     TempStr := ' Order By ' + myFieldName + ' Desc';
   if OrderPos<>0 then SqlStr := Copy(SqlStr,1,OrderPos-1);
   SqlStr := SqlStr + TempStr;
   Active := False;
   Sql.Clear;
   Sql.Text := SqlStr;
   if ParamCount>0 then
   begin
     Params.AssignValues(SavedParams);
     SavedParams.Free;
   end;
   Prepare;
   Open;
 end;
end;
 

 
 2003-11-13 11:13:57    去掉DbGrid的自動添加功能 
關鍵詞:DbGrid  

   移動到最后一條記錄時再按一下“下”就會追加一條記錄,如果去掉這項功能 
   procedure TForm1.DataSource1Change(Sender: TObject; Field: TField);
   begin
     if TDataSource(Sender).DataSet.Eof then TDataSource(Sender).DataSet.Cancel;
   end;


 

 
 2003-11-16 12:05:46    DBGrid不支持鼠標的上下移動的解決代碼(感謝 wangxian11 提供)自己捕捉WM_MOUSEWHEEL消息處理
private
 OldGridWnd : TWndMethod;
procedure NewGridWnd (var Message : TMessage);
public

procedure TForm1.NewGridWnd(var Message: TMessage);
var
 IsNeg : Boolean;
begin
 if Message.Msg = WM_MOUSEWHEEL then
 begin
   IsNeg := Short(Message.WParamHi) < 0;
   if IsNeg then
     DBGrid1.DataSource.DataSet.MoveBy(1)
   else
     DBGrid1.DataSource.DataSet.MoveBy(-1)
 end
 else
   OldGridWnd(Message);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 OldGridWnd := DBGrid1.WindowProc ;
 DBGrid1.WindowProc := NewGridWnd;
end;      

 
 2003-11-17 14:46:56    dbgrid中移動焦點到指定的行和列   dbgrid是從TCustomGrid繼承下來的,它有col與row屬性,只不過是protected的,不能直接訪問,要處理一下,可以這樣:

   TDrawGrid(dbgrid1).row:=row;
   TDrawGrid(dbgrid1).col:=col;
   dbgrid1.setfocus;
就可以看到效果了。

   1 這個方法是絕對有問題的,它會引起DBGrid內部的混亂,因為DBGrid無法定位當前紀錄,如果DBGrid只讀也就罷了(只讀還是會出向一些問題,比如原本只能單選的紀錄現在可以出現多選等等,你可以自己去試試),如果DBGrid可編輯那問題就可大了,因為當前紀錄的關系,你更改的數據字段很可能不是你想象中的
   2 我常用的解決辦法是將上程序改為(隨便設置col是安全的,沒有一點問題)

   Query1.first;
   TDrawGrid(dbgrid1).col:=1;
   dbgrid1.setfocus;

   這就讓焦點移到第一行第一列當中 

 
 2003-11-17 14:55:26    如何使DBGRID網格的顏色隨此格中的數據值的變化而變化?   在做界面的時候,有時候為了突出顯示數據的各個特性(如過大或者過小等),需要通過改變字體或者顏色,本文就是針對這個情況進行的說明。

   如何使DBGRID網格的顏色隨此格中的數據值的變化而變化。如<60的網格為紅色?
   Delphi中數據控制構件DBGrid是用來反映數據表的最重要、也是最常用的構件。在應用程序中,如果以彩色的方式來顯示DBGrid,將會增加其可視性,尤其在顯示一些重要的或者是需要警示的數據時,可以改變這些數據所在的行或列的前景和背景的顏色。
  DBGrid屬性DefaultDrawing是用來控制Cell(網格)的繪制。若DefaultDrawing的缺省設置為True,意思是Delphi使用DBGrid的缺省繪制方法來制作網格和其中所包含的數據,數據是按與特定列相連接的Tfield構件的DisplayFormat或EditFormat特性來繪制的;若將DBGrid的DefaultDrawing特性設置成False,Delphi就不繪制網格或其內容,必須自行在TDBGrid的OnDrawDataCell事件中提供自己的繪制例程(自畫功能)。
  在這里將用到DBGrid的一個重要屬性:畫布Canvas,很多構件都有這一屬性。Canvas代表了當前被顯示DBGrid的表面,你如果把另行定義的顯示內容和風格指定給DBGrid對象的Canvas,DBGrid對象會把Canvas屬性值在屏幕上顯示出來。具體應用時,涉及到Canvas的Brush屬性和FillRect方法及TextOut方法。Brush屬性規定了DBGrid.Canvas顯示的圖像、顏色、風格以及訪問Windows GDI 對象句柄,FillRect方法使用當前Brush屬性填充矩形區域,方法TextOut輸出Canvas的文本內容。

  以下用一個例子來詳細地說明如何顯示彩色的DBGrid。在例子中首先要有一個DBGrid構件,其次有一個用來產生彩色篩選條件的SpinEdit構件,另外還有ColorGrid構件供自由選擇數據單元的前景和背景的顏色。

  1.建立名為ColorDBGrid的Project,在其窗體Form1中依次放入所需構件,並設置屬性為相應值,具體如下所列:

   Table1 DatabaseName: DBDEMOS
    TableName: EMPLOYEE.DB
    Active: True;
  DataSource1 DataSet: Table1
  DBGrid1 DataSource1: DataSource1
    DefaultDrawing: False
  SpinEdit1 Increment:200
    Value: 20000
  ColorGrid1 GridOrdering: go16*1

  2.為DBGrid1構件OnDrawDataCell事件編寫響應程序:

//這里編寫的程序是<60的網格為紅色的情況,其他的可以照此類推
  procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;Field: TField; State: TGridDrawState);
  begin
   if Table1.Fieldbyname(′Salary′).value<=SpinEdit1.value then
    DBGrid1.Canvas.Brush.Color:=ColorGrid1.ForeGroundColor
   else
     DBGrid1.Canvas.Brush.Color:=ColorGrid1.BackGroundColor;
   DBGrid1.Canvas.FillRect(Rect);
   DBGrid1.Canvas.TextOut(Rect.left+2,Rect.top+2,Field.AsString);
  end;

  這個過程的作用是當SpinEdit1給定的條件得以滿足時,如′salary′變量低於或等於SpinEdit1.Value時,DBGrid1記錄以ColorGrid1的前景顏色來顯示,否則以ColorGrid1的背景顏色來顯示。然后調用DBGrid的Canvas的填充過程FillRect和文本輸出過程重新繪制DBGrid的畫面。

  3.為SpinEdit1構件的OnChange事件編寫響應代碼:

  procedure TForm1.SpinEdit1Change(Sender: TObject);
  begin
   DBGrid1.refresh;  //刷新是必須的,一定要刷新哦
  end;

  當SpinEdit1構件的值有所改變時,重新刷新DBGrid1。

  4.為ColorGrid1的OnChange事件編寫響應代碼:

  procedure TForm1.ColorGrid1Change(Sender: TObject);
  begin
   DBGrid1.refresh;    //刷新是必須的,一定要刷新哦
   end;

  當ColorGrid1的值有所改變時,即鼠標的右鍵或左鍵單擊ColorGrid1重新刷新DBGrid1。

  5.為Form1窗體(主窗體)的OnCreate事件編寫響應代碼:

  procedure TForm1.FormCreate(Sender: TObject);
  begin
   ColorGrid1.ForeGroundIndex:=9;
    ColorGrid1.BackGroundIndex:=15;
  end;

  在主窗創建時,將ColorGrid1的初值設定前景為灰色,背景為白色,也即DBGrid的字體顏色為灰色,背景顏色為白色。

  6.現在,可以對ColorDBGrid程序進行編譯和運行了。當用鼠標的左鍵或右鍵單擊ColorGrid1時,DBGrid的字體和背景顏色將隨之變化。

  在本文中,只是簡單展示了以彩色方式顯示DBGrid的原理,當然,還可以增加程序的復雜性,使其實用化。同樣道理,也可以將這個方法擴展到其他擁有Canvas屬性的構件中,讓應用程序的用戶界面更加友好。

   

 
 2003-11-17 14:58:08    判斷Grid是否有滾動條?這是一個小技巧,如果為了風格的統一的話,還是不要用了。:)

。。。

 if (GetWindowlong(Stringgrid1.Handle, GWL_STYLE) and WS_VSCROLL) <> 0 then
   ShowMessage('Vertical scrollbar is visible!');
 if (GetWindowlong(Stringgrid1.Handle, GWL_STYLE) and WS_HSCROLL) <> 0 then
   ShowMessage('Horizontal scrollbar is visible!');

。。。 

 
 2003-11-17 15:04:27    兩個Grid的同步滾動   在實際制作一個項目當中,有時候需要幾個grid一起同步滾動以減少用戶的操作量。希望下面那段代碼對您有一定的參考價值。

{1.}

unit SyncStringGrid;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,Dialogs, Grids;

type
 TSyncKind = (skBoth, skVScroll, skHScroll);
 TSyncStringGrid = class(TStringGrid)

private
 FInSync: Boolean;
 FsyncGrid: TSyncStringGrid;
 FSyncKind: TSyncKind;
{ Private declarations }
 procedure WMVScroll(var Msg: TMessage); message WM_VSCROLL;
 procedure WMHScroll(var Msg: TMessage); message WM_HSCROLL;

protected
{ Protected declarations }

public
{ Public declarations }
 procedure DoSync(Msg, wParam: Integer; lParam: Longint); virtual;

published
{ Published declarations }
 property SyncGrid: TSyncStringGrid read FSyncGrid write FSyncGrid;
 property SyncKind: TSyncKind read FSyncKind write FSyncKind default skBoth;
end;

procedure Register;

implementation

procedure Register;
begin
 RegisterComponents('Samples', [TSyncStringGrid]);
end;

procedure TSyncStringGrid.WMVScroll(var Msg: TMessage);
begin
 if not FInSync and Assigned(FSyncGrid) and (FSyncKind in [skBoth, skVScroll]) then
   FSyncGrid.DoSync(WM_VSCROLL, Msg.wParam, Msg.lParam);
 inherited;
end;

procedure TSyncStringGrid.WMHScroll(var Msg: TMessage);
begin
 if not FInSync and Assigned(FSyncGrid) and (FSyncKind in [skBoth, skHScroll]) then
   FSyncGrid.DoSync(WM_HSCROLL, Msg.wParam, Msg.lParam);
 inherited;
end;

procedure TSyncStringGrid.DoSync(Msg, wParam: Integer; lParam: Longint);
begin
 FInSync := True;
 Perform(Msg, wParam, lParam);
 FinSync := False;
end;

end.

{****************************************}

{2.}
private
 OldGridProc1, OldGridProc2: TWndMethod;
 procedure Grid1WindowProc(var Message: TMessage);
 procedure Grid2WindowProc(var Message: TMessage);

public
{...}

procedure TForm1.Grid1WindowProc(var Message: TMessage);

begin
 OldGridProc1(Message);
 if ((Message.Msg = WM_VSCROLL) or (Message.Msg = WM_HSCROLL) or Message.msg = WM_Mousewheel)) then
 begin
   OldGridProc2(Message);
 end;
end;

procedure TForm1.Grid2WindowProc(var Message: TMessage);
begin
 OldGridProc2(Message);
 if ((Message.Msg = WM_VSCROLL) or (Message.Msg = WM_HSCROLL) or (Message.msg = WM_Mousewheel)) then
 begin
   OldGridProc1(Message);
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 OldGridProc1 := StringGrid1.WindowProc;
 OldGridProc2 := StringGrid2.WindowProc;
 StringGrid1.WindowProc := Grid1WindowProc;
 StringGrid2.WindowProc := Grid2WindowProc;
end;
    

 
 2003-11-19 9:35:04    在Delphi中隨意控制DBGrid 每一行的顏色簡易方法   Delphi中使用 DBGrid 控件時,每一列都能按需要隨意地改變顏色,但要改變每一行的顏色卻很難,那么在不重新制作新控制件的情況下,有沒有好的辦法讓DBGrid按照用戶自己要求隨意改變每一行顏色的?答案是有,下面介紹一種簡單的方法。 

   要改變DBGrid每一行的顏色,只要在ONDrawColumnCell事件中設定要改變顏色的行的條件,
並指定DBGrid的Canvas.Brush.color屬性並且把Canvas.pen.mode屬性設成pmmask,再調用DBGrid 的DefaultDrawColumnCell方法即可。注意在改變這兩個屬性前要先保護好原來的 
Canvas.Brush.color 屬性的值,調節器用完成 DefaultDrawColumnCell 方法后要把原屬性值改
回,現以 Delphi\demos\db\clientmd 目錄下的演示程序 clintproj.dpr 為例子,做簡單說明,下面是對程序中的柵格 MemberGrid 的合條件的整行進行變色,變成黑體背景黃色的,其它不合條件的行的顏色為正常字體,白色背景,只在 DrawColumnCelL 事件中設條件其它的不變,如下: 

procedure TClientForm.MemberGridDrawColumnCell(Sender: TObject; const Rect: TRect; 
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var 
 oldcolor:tcolor;
 oldpm:tpenmode;
begin
 if DM.ProjectTEAM_LEADER.Value = DM.Emp_ProjEMP_NO.Value then  {設定變色的行的條件}
    MemberGrid.Canvas.Font.Style := [fsBold];
    MemberGrid.DefaultDrawColumnCell(Rect, DataCol, Column, State);
    {上面是演示程序的原內容,以下是增加部分}
 if DM.ProjectTEAM_LEADER.Value =DM.Emp_ProjEMP_NO.Value then {設定變色的行的條件}
 begin
    oldpm:= MemberGrid.Canvas.pen.mode;
    oldcolor:= MemberGrid.Canvas.Brush.color;
    MemberGrid.Canvas.Brush.color:=clyellow;
    MemberGrid.Canvas.pen.mode:=pmmask;
    MemberGrid.DefaultDrawColumnCell(Rect, DataCol, Column, State);
    MemberGrid.Canvas.Brush.color:=oldcolor;
    MemberGrid.Canvas.pen.mode:=oldpm;
 end;

end;

   感覺上這個方法和前面的幾個顏色控制方法的原理是一樣的,都是通過ONDrawColumnCell事件來實現變色醒目美化的功能。:) 

 
 2003-11-19 9:43:56    如何在DBGrid中能支持多項記錄的選擇   這份文檔來自國外,粗略看了一下,很有用,推薦給大家學習使用。
【Question】: How to do multi-selecting records in TDBGrid?
   When you add [dgMultiSelect] to the Options property of a DBGrid, you give yourself the ability to select multiple records within the grid.
   The records you select are represented as bookmarks and are stored in the SelectedRows property.
   The SelectedRows property is an object of type TBookmarkList.  The properties and methods are described below.

// property SelectedRows: TBookmarkList read FBookmarks;

//   TBookmarkList = class
//   public
    {* The Clear method will free all the selected records within the DBGrid *}
    // procedure Clear;
    {* The Delete method will delete all the selected rows from the dataset *}
    // procedure Delete;
    {* The Find method determines whether a bookmark is in the selected list. *}
    // function  Find(const Item: TBookmarkStr;
    //      var Index: Integer): Boolean;
    {* The IndexOf method returns the index of the bookmark within the Items property. *}
    // function IndexOf(const Item: TBookmarkStr): Integer;
    {* The Refresh method returns a boolean value to notify whether any orphans were dropped (deleted) during the time the record has been selected in the grid.  The refresh method can be used to update the selected list to minimize the possibility of accessing a deleted record. *}
    // function  Refresh: Boolean;  True = orphans found
    {* The Count property returns the number of currently selected items in the DBGrid *}
    // property Count: Integer read GetCount;
    {* The CurrentRowSelected property returns a boolean value and determines whether the current row is selected or not. *}
    // property CurrentRowSelected: Boolean
    //      read GetCurrentRowSelected
    //      write SetCurrentRowSelected;
    {* The Items property is a TStringList of TBookmarkStr *}
    // property Items[Index: Integer]: TBookmarkStr
    //      read GetItem; default;
//  end;

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, DBGrids, DB, DBTables;

type
 TForm1 = class(TForm)
   Table1: TTable;
   DBGrid1: TDBGrid;
   Count: TButton;
   Selected: TButton;
   Clear: TButton;
   Delete: TButton;
   Select: TButton;
   GetBookMark: TButton;
   Find: TButton;
   FreeBookmark: TButton;
   DataSource1: TDataSource;
   procedure CountClick(Sender: TObject);
   procedure SelectedClick(Sender: TObject);
   procedure ClearClick(Sender: TObject);
   procedure DeleteClick(Sender: TObject);
   procedure SelectClick(Sender: TObject);
   procedure GetBookMarkClick(Sender: TObject);
   procedure FindClick(Sender: TObject);
   procedure FreeBookmarkClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
 Bookmark1: TBookmark;
 z: Integer;

implementation

{$R *.DFM}

//Example of the Count property
procedure TForm1.CountClick(Sender: TObject);
begin
 if DBgrid1.SelectedRows.Count > 0 then
 begin
   showmessage(inttostr(DBgrid1.SelectedRows.Count));
 end;
end;

//Example of the CurrentRowSelected property
procedure TForm1.SelectedClick(Sender: TObject);
begin
 if DBgrid1.SelectedRows.CurrentRowSelected then
   showmessage('Selected');
end;

//Example of the Clear Method
procedure TForm1.ClearClick(Sender: TObject);
begin
 dbgrid1.SelectedRows.Clear;
end;

//Example of the Delete Method
procedure TForm1.DeleteClick(Sender: TObject);
begin
 DBgrid1.SelectedRows.Delete;
end;

{*
  This example iterates through the selected rows of the grid and displays the second field of the dataset.
  The Method DisableControls is used so that the DBGrid will not update when the dataset is changed. The last position of the dataset is saved as a TBookmark.
  The IndexOf method is called to check whether or not the bookmark is still existent.
  The decision of using the IndexOf method rather than the Refresh method should be determined by the specific application.
*}

procedure TForm1.SelectClick(Sender: TObject);
var
 x: word;
 TempBookmark: TBookMark;
begin
 DBGrid1.Datasource.Dataset.DisableControls;
 with DBgrid1.SelectedRows do
 if Count > 0 then
 begin
   TempBookmark:= DBGrid1.Datasource.Dataset.GetBookmark;
   for x:= 0 to Count - 1 do
   begin
     if IndexOf(Items[x]) > -1 then
     begin
       DBGrid1.Datasource.Dataset.Bookmark:= Items[x];
       showmessage(DBGrid1.Datasource.Dataset.Fields[1].AsString);
     end;
   end;
 end;
 DBGrid1.Datasource.Dataset.GotoBookmark(TempBookmark);
 DBGrid1.Datasource.Dataset.FreeBookmark(TempBookmark);
 DBGrid1.Datasource.Dataset.EnableControls;
end;

{*
This example allows you to set a bookmark and  and then search for the bookmarked record within selected a record(s) within the DBGrid.
*}

//Sets a bookmark
procedure TForm1.GetBookMarkClick(Sender: TObject);
begin
 Bookmark1:= DBGrid1.Datasource.Dataset.GetBookmark;
end;

//Frees the bookmark
procedure TForm1.FreeBookmarkClick(Sender: TObject);
begin
 if assigned(Bookmark1) then
 begin
   DBGrid1.Datasource.Dataset.FreeBookmark(Bookmark1);
   Bookmark1:= nil;
 end;
end;

//Uses the Find method to locate the position of the bookmarked record within the selected list in the DBGrid
procedure TForm1.FindClick(Sender: TObject);
begin
 if assigned(Bookmark1) then
 begin
   if DBGrid1.SelectedRows.Find(TBookMarkStr(Bookmark1),z) then
     showmessage(inttostr(z));
 end;
end;

end. 

 
 2003-11-19 10:11:21    另外一種可以在在Delphi中隨意控制DBGrid 每一行顏色的方法   有個問題是在Delphi中使用DBGrid時,如何讓DBGrid中每一行顏色按照用戶自己的意願控
制。最初看到這個問題時,我們以為非常非常簡單,所以馬上動手准備解決它。結果卻發現不是
那么回事,傳統方法根本不能發揮作用。在電腦面前一直坐到凌晨4點,不斷地調試,幸運地是憑借平時積累的一點編程經驗,終於找到了開門的匙鑰。現將它充公,供大家享用。 

  1、 數據表的建立 
  在Delphi的工具菜單中選擇Database desktop,在數據庫DBDemos下建立一個名為
example.db的數據表。數據表的字段和內容如下: 
             
Name  Age  Wage
張山  25  500
王武  57  1060
李市  30  520
劉牛  28  390

   2、創建基於TDBGrid的TColoredDBGrid組件 
   在Delphi組件菜單中,選擇New Component,在彈出對話框中作以下設置: 

Ancestor Type  =   TDBGrid
Class  Name   =   TColoredDBGrid

   然后單擊OK按鈕,Delphi自動完成組件基本框架的定義。增添OnDRawColoredDBGrid事件並
使它出現在Object Inspector的Events中以便在應用程序中設定改變行顏色的條件。重載
DrawCell方法,只能自己繪制單元格。不能通過在OnDrawColumnCell來設置顏色,因為在
OnDrawColumnCell改變單元格的顏色會再次觸發OnDrawColumnCell。 
   下面就是所創建組件的源程序 。 

   3、建立應用程序進行驗證。 
   在Delphi文件菜單中選擇New建立新的應用程序工程Project1和主窗體Form1,設置Form1的
Caption屬性為“控制DBGrid行顏色的示例”。在主窗體上添加Data Source、Table、Button和
ColoredDBGrid組件。設置各組件的屬性如下: 

Table1.Database=’DBDemos’
Table1.Tablename=’example.db’
Datasource1.Dataset=Table1
ColoredDBGrid1.Datasource=DataSource1
Button1.Caption=’退出’

   在ColoredDBGrid1的onDRawColoredDBGrid事件中輸入下列代碼,設定由Wage(工資)來決
定在ColoredDBGrid1各行的顏色。 

procedure TForm1.ColoredDBGrid1 DRawColoredDBGrid (Sender: TObject;  Field: TField; var Color: TColor; var Font: TFont);
Var
   p : Integer;
begin
   p := Table1.FindField('wage').AsInteger;
 //取得當前記錄的Wage字段的值。
   if (p < 500) then begin                 
//程序將根據wage值設置各行的顏色。
     Color := clGreen;
     Font.Style := [fsItalic];      
//不僅可以改變顏色,還可以改變字體
   end;
   if(p >= 500) And (p < 800) then
     Color := clRed;
   if(p >=800) then begin
     Color := clMaroon;
     Font.Style := [fsBold];
   end;
end;
//用‘退出’按鈕結束程序運行。
procedure TForm1.Button1Click(Sender: TObject);
begin
   Close;
end; 

 
 2003-11-19 10:16:11    在一個Dbgrid中顯示多數據庫    在數據庫編程中,不必要也不可能將應用程序操作的所有數據庫字段放入一個數據庫文件中。正確的數據庫結構應是:將數據庫字段放入多個數據庫文件,相關的數據庫都包含一個唯一
的關鍵字段,在多數據庫結構里可以建立聯系。 
   例如:要編制一個人事管理程序,為簡化演示程序,只建立兩個數據庫,每個數據庫都只建
立兩個字段。 
   個人簡介 jianjie.dbf,由人事處維護;工資情況 gongzi.dbf,由財務處維護。 
   1.數據庫的建立 
   進入DataBase Desktop,建立數據庫結構如下:
   
   jianjie.dbf
   編號 字段名:bianhao size:4 type:number
   姓名 字段名:xingming size:10 type:character

   gongzi.dbf
   編號 字段名:bianhao size:4 type:number
   工資 字段名:gongzi size:4 Dec 2 type:number

   注意: 兩個數據庫的bianhao字段的size、type必須一致。實際上,兩數據庫文件可以分布
在網絡的不同計算機上,為便於演示,分別存為″c: \test\jianjie.dbf″和 ″c:\test
\gongzi.dbf″。 

   2.應用程序的編制 
   啟動Delphi, 新建一個工程,在窗體中加入Query控件Query1,databasename屬性設為c:
\test; 

   加入DataSource控件datasource1, DataSet屬性設為Query1; 加入DbGrid控件 dbgrid1,
DataSource屬性設為DataSource1,將Query1.sql屬性設為 

   SELECT DISTINCT A.bianhao,a.xingming, b.gongzi
   FROM ″jianjie.dbf″ A, ″gongzi.DBF″ b
   WHERE A.bianhao=b.bianhao

   再將Query1.enabled屬性設為True, 不用編譯, DbGrid1就會顯示: bianhao, 
xingming, gongzi三個字段。如果jianjie.dbf和gongzi.dbf中有記錄,則記錄會顯示出來。因
篇幅所限,此文只介紹了Dbgrid中顯示多個數據庫內容的一般方法,讀者可在此基礎上進行完
善,使該方法更好地適應您的需要。 
 

 
 2003-11-19 10:19:40    在 DBGrid 中如何讓回車變為光標右移動
在Form.OnKeyPress事件中寫如下代碼:

 if Key = #13 then 
 if ActiveControl = DBGrid1 then begin 
   TDBGrid(ActiveControl).SelectedIndex := TDBGrid(ActiveControl).SelectedIndex + 1; 
   Key := #0; 
end; 

有2點需要注意:
 1.當光標達到DBGird最右列的時候,再按回車,光標還會停留在原地。
 2.Key := #0 

 
 2003-11-19 10:25:07    從 DBGrid 中復制記錄procedure TForm1.DBGrid1DblClick(Sender: TObject);
var
  x : integer ;
  HadToOpen : boolean ;
begin
  with Sender as TDBGrid do begin
     HadToOpen := not tTarget.Active ;
     if HadToOpen then
        tTarget.Active := True ;
     tTarget.Append ;
     for x := 0 to FieldCount - 1 do
        case Fields[x].DataType of
           ftBoolean : tTarget.FieldByName(Fields[x].FieldName).AsBoolean := Fields[x].AsBoolean
           ftString : tTarget.FieldByName(Fields[x].FieldName).AsString := Fields[x].AsString
           ftFloat : tTarget.FieldByName(Fields[x].FieldName).AsFloat := Fields[x].AsFloat
           ftInteger : tTarget.FieldByName(Fields[x].FieldName).AsInteger := Fields[x].AsInteger
           ftDate : tTarget.FieldByName(Fields[x].FieldName).AsDateTime := Fields[x].AsDateTime ;
        end ;
     tTarget.Post ;
     if HadToOpen then
        tTarget.Active := False ;
  end ;
end; 

 
 2003-11-19 10:27:58    使用 DBGrid 的復選項(請參考如何在DBGrid中能支持多項記錄的選擇)procedure TForm1.SelectClick(Sender: TObject);
var
 x: word;
 TempBookmark: TBookMark;
begin
 DBGrid1.Datasource.Dataset.DisableControls;
 with DBgrid1.SelectedRows do
   if Count <> 0 then
   begin
     TempBookmark:= DBGrid1.Datasource.Dataset.GetBookmark;
     for x:= 0 to Count - 1 do
     begin
       if IndexOf(Items[x]) > -1 then
       begin
         DBGrid1.Datasource.Dataset.Bookmark:= Items[x];
         showmessage(DBGrid1.Datasource.Dataset.Fields[1].AsString);
       end;
     end;
   end;
 DBGrid1.Datasource.Dataset.GotoBookmark(TempBookmark);
 DBGrid1.Datasource.Dataset.FreeBookmark(TempBookmark);
 DBGrid1.Datasource.Dataset.EnableControls;
end;

 

 
 2003-11-19 10:32:27    在DBGrid上Drag & Drop(拖放)我們在做程序中發現,如果能夠讓用戶將一個Edit的內容直接拖放到一個DBGrid里,會顯得很方便,但在程序編制過程中發現,似乎拖放只能拖放到當前的記錄上,那假如要拖放到其他記錄又怎么辦呢,總不能讓用戶先選擇記錄,然后再拖放吧。
   后來,通過研究發現,當用鼠標點DBGrid時,DBGrid會自動將記錄指針移動到所點擊的記錄上,這就給了我一個思路,讓程序模擬在DBGrid上的一次點擊先讓光標移動到那條記錄上,然后就可以將拖放的數據寫入DBgrid里面了。
   通過事實證明這個思路是可行的。下面,我就告訴大家我的做法:
   1) 首先在Form上放一個DBGrid,並它能夠顯示記錄,(這比較簡單,就不用多說了)
   2) 在Form上放一個Edit
   3) 修改Edit的屬性,把DragMode改為dmAutoMatic, 讓用戶能夠拖放
   4) 在Dbgrid的DragOver事件中增加如下代碼: 讓它能夠接收 Drag & drop

procedure TForm1.DBGrid1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
 accept:=true;
end;

   5) 在Dbgrid的DragDrop事件中增加如下代碼: 讓它能夠自動跳到光標所指定的記錄上

procedure TForm1.DBGrid1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
 if Source<>Edit1 then exit;
 with Sender as TDbGrid do begin
   Perform(wm_LButtonDown,0,MakeLong(x,y));
   PerForm(WM_LButtonUp,  0,MakeLong(x,y));
   SelectedField.Dataset.edit;
   SelectedField.AsString:=Edit1.text;
 end;
end;

   至此,我們就實現了想要的功能,其中PerForm是TControl的一個通用方法目的是繞過Windows本身的消息循環,而將消息直接發給要發的Control,其具體使用方法請參考Delphi的幫助。 

 
 2003-11-19 10:39:19    如何使DBGrid的指針不移動?
【問題】:我用DBGRID顯示TABLE中的內容,現在我要從頭到尾讀一遍TABLE里的數據,用
Table1.First,Next來做會使DBGRID里面的指針也跟着跑,怎么才能使這時候DBGRID里面的指針不
動呢?

【答案】:使用如下代碼即可:

  with DataSet do
  try
   DisableControls;
    Do_something;
  finally
    EnableControls;
  end; 

 
 2003-11-19 10:42:14    如何動態更新DBGrid的顏色?(請同時參考“如何使DBGRID網格的顏色隨此格中的數據值的變化而變化?”)   DBGrid控件是一個有許多用戶接口的顯示數據庫的控件,以下的程序告訴您如何根據顯示的內容改變字體的顯示顏色。例如,如果一個城市的人口大於200萬,我們就讓它顯示為藍色。使用的控件事件為DBGrid.OnDrawColumeCell.

 procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect:TRect;DataCol: 
Integer; Column: TColumn; State: TGridDrawState);
 begin
   if Table1.FieldByName('Population').AsInteger > 20000000 then
     DBGrid1.Canvas.Font.Color := clBlue;
   DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
 end;

   上面的例子是簡單的,但是你可以根據自己的需要擴充,例如字體也變化等,甚至你可以調用畫圓的函數在數字上畫上一個紅色的圓圈。 

 
 2003-11-19 10:45:14    使用DBGrid顯示日期   在使用 DBGRID 控件時顯示 DATATIME 時其年份是為2位的,但我們在步入2000年后需要顯示的日期是4位,如:1998、2001。在數據庫中該字段只有在2000年后才會顯示4位,怎么辦呢? 下面我們就讓該字段在DBGRID控件中也顯示4位的日期格式: 雙擊 Table1 控件,就會出現 form1.table 窗體,擊右鍵,選 Add Fields...,選擇日期字段后按ok,窗體中就出現了數據庫的日期字段名,點日期的那個字段名,屬性框里就出現了該字段的信息,里面有一項 DispalyFormat,在該顯示格式里輸入 yyyy.mm.dd ,那么DBGRID控件就出現完整的日期了。 

 
 2003-11-19 10:48:37    在TDBGrid控件中實現拖放的另外一個思路(請同時參考在DBGrid上Drag & Drop(拖放))   在本unit中,自定義TMyCustomDBGrid=class(TCustomDBGrid),再如下引用:

   TMyCustomDBGrid(DBGrid1).MouseDown(...)
 或
   DBGrid1 as TMyCustomDBGrid).MouseDown(...)即可。 

 
 2003-11-19 10:56:11    在dbgrid表格中如何設置按回車鍵相當於單click?【例程】:
   在窗體form1中放入table1,datasource1,dbgrid1,設好聯連關系,使 dbgrid1 中能正確顯示出table1的數據。然后:
procedure TForm1.DBGrid1KeyPress(Sender: TObject;
var Key: Char);
begin
 with DBGrid1 do
   if Key=#13 then
     DBGrid1CellClick(Columns[SelectedIndex]);
end;

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
 with DBGrid1 do
   showmessage(format('row=%d',[SelectedIndex]));
end; 

 
 2003-11-19 11:07:55    Delphi 的 DBGrid 中的下拉列表和查找字段編程方法   數據網格是非常流行的數據輸入和顯示形式,像大家熟悉的Excel、VFP 中的功能強大的BROWS 等,為廣大程序員樂於采用。在用 Delphi 開發數據庫應用系統時,利用數據網格DBGrid 輸入數據時,有些字段只允許某幾個固定的字符串,像檔案案卷的保管期限,只有“永久”、“長期”和“短期”三種,可否從一個下拉列表中進行選擇,從而方便輸入和避免輸入錯誤呢?還有一些字段,例如職工信息庫中的單位編號(在另外的單位庫中保存着單位的詳細信息),在輸入和顯示職工數據時,能否不對單位編號進行操作,而代之於更加直觀的單位庫中的單位名稱呢?答案是肯定的,Delphi 的數據網格控件 DBGrid,支持下拉列表和查找字段的編程,而且,編程的過程都是可視化的,不需要寫一行語句。 

一、DBGrid 中的下拉列表
   在 DBGrid 網格中實現下拉列表,設置好 DBGrid 中該字段的 PickList 字符串列表、初始的序號值 DropDownRows 即可。以職工信息庫中的籍貫字段(字符串類型)為例,具體設計步驟如下: 
 1、在窗體上放置Table1、DataSource1、DBGrid1、DBNavigator1 等控件對象,按下表設置各個對象的屬性: 

---------------------------------------
對象       屬性         設定值
---------------------------------------
Table1       DataBase     sy1
            Table        zgk.dbf   //職工信息庫
DataSource1  DataSet      Table1
DbGrid1      DataSource   DataSource1
DBNavigator1 DataSource   Datasource1
-------------------------------------------
 2、雙擊Table1, 在彈出的Form1.Table1 窗口中,用右鍵彈出快捷菜單,單擊Add Fields 菜單項;選擇所有的字段后,按OK 按鈕。 

 3、修改第2 步新增字段的 DisplayLabel 屬性。以 Table1ZGBH 字段為例,在 Object Inspector 窗口中選擇 Table1ZGBH, 修改屬性 DisplayLabel= 職工編號,其余字段類似。 

 4、雙擊 DBGrid1, 在彈出的 Editing DBGrid1.Columns 窗口中,單擊 Add all Fields 按鈕,增加Table1 的所有字段。 

 5、在 Editing DBGrid1.Columns 窗口,選擇 jg 這一行,切換到 Object Inspector 窗口,修改它的 PickList.Strings 為“湖北枝江市(換行)北京市(換行)河南平頂山市(換行)浙江德清市” 

 6、在 Form1.Oncreate 事件中寫入語句: 

  Table1.Open; 

 7、F9 運行,用鼠標點擊某個記錄的籍貫字段,右邊即出現一個按鈕,點擊這個按鈕,可出現一個下拉列表,包含第5 步中輸入的四行字符串,可用鼠標進行選擇。當然也可以自行輸入一個並不屬下拉列表中的字符串。 

二、DBGrid 中的查找字段
   所謂查找字段 (LookUp Field),即 DBGrid 中的某個關鍵字段的數值來源於另外一個數據庫的相應字段。運用查找字段技術,不僅可以有效的避免輸入錯誤,而且 DBGrid 的顯示方式更為靈活,可以不顯示關鍵字段,而顯示源數據庫中相對應的另外一個字段的數據。 
---- 例如,我們在 DBGrid 中顯示和編輯職工信息,包括職工編號、職工姓名、籍貫、所在單位編號,而單位編號來源於另一個數據庫表格——單位庫,稱“單位編號”為關鍵字段。如果我們直接顯示和編輯單位編號的話,將會面對1、2、3 等非常不直觀的數字,編輯時極易出錯。但是如果顯示和編輯的是單位庫中對應的單位名稱話,將非常直觀。這就是DBGrid 的所支持的查找字段帶來的好處。 

   實現DBGrid 的查找字段同樣不需要任何語句,具體設計步驟如下: 
 1、在窗體上放置 Table1、Table2、DataSource1、DBGrid1、DBNavigator1 等控件對象,按下表設置各個對象的屬性: 

---------------------------------------
對象       屬性         設定值
---------------------------------------
Table1       DataBase     sy1
            Table        zgk.dbf   //職工信息庫
Table2       DataBase     sy1
            Table        dwk.dbf   //單位信息庫
DataSource1  DataSet      Table1
DbGrid1      DataSource   DataSource1
DBNavigator1 DataSource   Datasource1
------------------------------------------
 2、雙擊 Table1, 在彈出的 Form1.Table1 窗口中,用右鍵彈出快捷菜單,單擊 Add Fields 菜單項;選擇所有的字段后,按OK 按鈕。 

 3、修改第2 步新增字段的 DisplayLabel 屬性。以 Table1ZGBH 字段為例,在 Object Inspector 窗口中選擇 Table1ZGBH, 修改屬性 DisplayLabel= 職工編號,其余字段類似。 

 4、設置 Table1DWBH.Visible=False。 

 5、在 Form1.Table1 窗口,用右鍵彈出快捷菜單,單擊 New Field 菜單項,新增一個查找字段DWMC,在彈出的窗口設置相應的屬性, 按 OK 按鈕確認;在 Object Inspector 窗口,設置 Table1DWMC.DisplayLabel= 單位名稱。 

 6、在 Form1.Oncreate 事件中寫入語句: 

   Table1.Open; 

 7、按 F9 運行,當光標移至某個記錄的單位名稱字段時,用鼠標點擊該字段,即出現一個下拉列表,點擊右邊的下箭頭,可在下拉列表中進行選擇。在這里可以看出,下拉列表的內容來自於單位信息庫,並且不能輸入其他內容。 

三、DBGrid 中的下拉列表和查找字段的區別
   雖然 DBGrid 中的下拉列表和查找字段,都是以下拉列表的形式出現的,但兩者有很大的差別。 
 1、用 PickList 屬性設置的下拉列表,它的數據是手工輸入的,雖然也可以在程序中修改,但動態特性顯然不如直接由另外數據庫表格提取數據的查找字段。 

 2、用 PickList 屬性設置的下拉列表,允許輸入不屬於下拉列表中的數據,但查找字段中只能輸入源數據庫中關鍵字段中的數據,這樣更能保證數據的完整性。 

 3、用 PickList 屬性設置的下拉列表設計較為簡單。  

 
 2003-11-19 11:23:29    Delphi中定制DBGrid控件  在Delphi中,DBGrid控件是一個開發數據庫軟件不能不使用的控件,其功能非常強大,可以配合SQL語句實現幾乎所有數據報表的顯示,操作也非常簡單,屬性、過程、事件等都非常直觀,但是使用中,有時侯還是需要一些其他功能,例如打印、斑馬紋顯示、將DBGrid中的數據轉存到Excel97中等等。這就需要我們定制DBGrid,以更好的適應我們的實際需要定制DBGrid,實現了以上列舉的功能,對於打印功能則是在DBGrid的基礎上聯合QuickReport的功能,直接進行DBGrid的打印及預覽,用戶感覺不到QuickReport的存在,只需調用方法WpaperPreview即可;對於轉存數據到Excel也是一樣,不過這里使用的是自動化變量Excel而已。由於程序太長,不能詳細列舉,這里介紹一個完整的實現斑馬紋顯示的DBGrid,名字是NewDBGrid。根據這個小程序,讀者可以添加其他更好、更多、更實用的功能。 
  NewDBGrid的實現原理就是繼承DBGrid的所有功能,同時添加新的屬性:
      Wzebra,WfirstColor ,WsecondColor。
   當Wzebra的值為True時,顯示斑馬紋效果,其顯示的效果是單數行顏色為WfirstColor,雙數行顏色為WsecondColor。具體的見下面程序清單: 

unit NewDBGrid;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DB, Grids, DBGrids, Excel97;
type
 TDrawFieldCellEvent = procedure(Sender: TObject; Field: TField;
   var Color: TCOlor; var Font: TFont; Row: Longint) of object;
//新的數據控件由 TDBGrid 繼承而來
 TNewDBGrid = class(TDBGrid)

 private
//私有變量
   FWZebra: Boolean; //是否顯示斑馬顏色
   FWFirstColor: TColor; //單數行顏色
   FWSecondColor: TCOlor; //雙數行顏色
   FDrawFieldCellEvent: TDrawFieldCellEvent;
   procedure AutoInitialize; //自動初使化過程
   procedure AutoDestroy;
   function GetWFirstColor: TColor;
//FirstColor 的讀寫函數及過程
   procedure SetWFirstColor(Value: TColor);
   function GetWSecondColor: TCOlor;
   procedure SetWSecondColor(Value: TColor);
   function GetWZebra: Boolean;
   procedure SetWZebra(Value: Boolean);

 protected
   procedure Scroll(Distance: Integer); override;
//本控件的重點過程
   procedure DrawCell(Acol, ARow: Longint; ARect:
     TRect; AState: TGridDrawState); override;

 public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;

 published
   property WZebra: Boolean read GetWZebra write SetWZebra;
   property OnDblClick;
   property OnDragDrop;
   property OnKeyUp;
   property OnKeyDown;
   property OnKeyPress;
   property OnEnter;
   property OnExit;
   property OnDrawDataCell;
   property WFirstColor: TColor
     read GetWFirstColor write SetWFirstColor;
   property WSecondColor: TColor
     read GetWSecondColor write SetWSecondColor;
 end;

procedure Register;

implementation

procedure Register;
begin
 RegisterComponents('Data Controls', [TNewDBGrid]);
end;

procedure TNewDBGrid.AutoInitialize;
begin
 FWFirstColor := RGB(239, 254, 247);
 FWSecondColor := RGB(249, 244, 245);
{可以在次添加需要的其它控件及初使化參數}
end;

procedure TNewDBGrid.AutoDestroy;
begin
{在這里釋放自己添加參數等占用的系統資源}
end;

procedure TNewDBGrid.SetWZebra(Value: Boolean);
begin
 FWZebra := Value;
 Refresh;
end;

function TNewDBGrid.GetWZebra: Boolean;
begin
 Result := FWZebra;
end;

function TNewDBGrid.GetWFirstColor: TColor;
begin
 Result := FWFirstColor;
end;

procedure TNewDBGrid.SetWFirstColor(Value: TColor);
begin
 FWFirstColor := Value;
 Refresh;
end;

function TNewDBGrid.GetWSecondColor: TColor;
begin
 Result := FWSecondColor;
end;

procedure TNewDBGrid.SetWSecondColor(Value: TColor);
begin
 FWSecondColor := Value;
 Refresh;
end;

constructor TNewDBGrid.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);
 AutoInitialize;
end;

destructor TNewDBGrid.Destroy;
begin
 AutoDestroy;
 inherited Destroy;
end;
//實現斑馬效果

procedure TNewDBGrid.DrawCell(ACol, ARow:
 Longint; ARect: TRect; AState: TGridDrawState);
var
 OldActive: Integer;
 Highlight: Boolean;
 Value: string;
 DrawColumn: Tcolumn;
 cl: TColor;
 fn: TFont;
begin
{如果處於控件裝載狀態,則直接填充顏色后退出}
 if csLoading in ComponentState then
 begin
   Canvas.Brush.Color := Color;
   Canvas.FillRect(ARect);
   Exit;
 end;
 if (gdFixed in AState) and (ACol - IndicatorOffset < 0) then
 begin
   inherited DrawCell(ACol, ARow, ARect, AState);
   Exit;
 end;
{對於列標題,不用任何修飾}
 if (dgTitles in Options) and (ARow = 0) then
 begin
   inherited DrawCell(ACol, ARow, ARect, AState);
   Exit;
 end;
 if (dgTitles in Options) then Dec(ARow);
 Dec(ACol, IndicatorOffset);
 if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
   [dgRowLines, dgColLines]) then
 begin
{縮減ARect,以便填寫數據}
   InflateRect(ARect, -1, -1);
 end
 else
   with Canvas do
   begin
     DrawColumn := Columns[ACol];
     Font := DrawColumn.Font;
     Brush.Color := DrawColumn.Color;
     Font.Color := DrawColumn.Font.Color;
     if FWZebra then //如果屬性WZebra為True則顯示斑馬紋
       if Odd(ARow) then
         Brush.Color := FWSecondColor
       else
         Brush.Color := FWFirstColor;
     if (DataLink = nil) or not DataLink.Active then
       FillRect(ARect)
     else
     begin
       Value := '';
       OldActive := DataLink.ActiveRecord;
       try
         DataLink.ActiveRecord := ARow;
         if Assigned(DrawColumn.Field) then
         begin
           Value := DrawColumn.Field.DisplayText;
           if Assigned(FDrawFieldCellEvent) then
           begin
             cl := Brush.Color;
             fn := Font;
             FDrawFieldCellEvent(self, DrawColumn.Field, cl, fn, ARow);
             Brush.Color := cl;
             Font := fn;
           end;
         end;
         Highlight := HighlightCell(ACol, ARow, Value, AState);
         if Highlight and (not FWZebra) then
         begin
           Brush.Color := clHighlight;
           Font.Color := clHighlightText;
         end;
         if DefaultDrawing then
           DefaultDrawColumnCell(ARect, ACol, DrawColumn, AState);
         if Columns.State = csDefault then
           DrawDataCell(ARect, DrawColumn.Field, AState);
         DrawColumnCell(ARect, ACol, DrawColumn, AState);
       finally
         DataLink.Activerecord := OldActive;
       end;
       if DefaultDrawing and (gdSelected in AState) and
         ((dgAlwaysShowSelection in Options) or Focused)
         and not (csDesigning in Componentstate)
         and not (dgRowSelect in Options)
         and (ValidParentForm(self).ActiveControl = self) then
       begin
//顯示當前光標處為藍底黃字,同時加粗顯示
         Windows.DrawFocusRect(Handle, ARect);
         Canvas.Brush.COlor := clBlue;
         Canvas.FillRect(ARect);
         Canvas.Font.Color := clYellow;
         Canvas.Font.Style := [fsBold];
         DefaultDrawColumnCell(ARect, ACol, DrawColumn, AState);
       end;
     end;
   end;
 if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
   [dgRowLines, dgColLines]) then
 begin
   InflateRect(ARect, -2, -2);
   DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
   DrawEdge(Canvas.Handle, ARect, BDR_SUNKENINNER, BF_TOPLEFT);
 end;
end;
//如果移動光標等,則需要刷新顯示DBGrid

procedure TNewDBGrid.Scroll(Distance: Integer);
begin
 inherited Scroll(Distance);
 refresh;
end;

end.

以上程序在Win98 + Delphi 5下調試通過。 

 
 2003-11-19 11:27:19    在DBGrid控件中顯示圖形  如果在數據庫中設置了一個為BLOB類型的字段用於保存圖形,在使用DBGrid控件顯示時,在表格中顯示的是BLOB,而無法顯示出圖形,當然,有一些第三方控件可以顯示出圖形,但是要去找第三方控件不是一件容易的事,而且有些好用的都需要付費。能不能在DBGrid中顯示圖形呢?答案是肯定的。
  在DBGrid的OnDrawCell事件中加入如下代碼即可在DBGrid控件中顯示圖形。
var
 Bmp: TBitmap;
begin
 if (Column.Field.DataTyp = ftBLOB) or (Column.Field.DataTyp = ftGraphic) then
 begin
   Bmp:=TBitmap.Create;
   try
     Bmp.Assign(Column.Field);
     DBGrid1.Canvas.StretchDraw(Rect,Bmp);
     Bmp.Free;
   Except
     Bmp.Free;
   end;
 end;
end;
  按照類似的方法,就可以在DBGrid中顯示Memo類型的字段內容。
  另外,在往數據庫中保存圖形時,建議使用EMF圖元文件,這樣數據庫文件的大小不會變的十分驚人,我試過了,同樣是一幅400*300的圖形,如果用位圖,保存100多幅時,數據庫文件大小會達到近20MB,而使用EMF矢量圖形保存,保存800多幅時才260多KB,保存EMF矢量圖形的方法與保存位圖是差不多的,在DBGrid中顯示也差不多,只不過BLOB型字段內容不能直接Assign給EMF文件,要用MemoryStream來中轉。
 

 
 2003-11-19 11:31:15    如何偵測DBGrid目前的記錄與欄位資訊   請問用什麽方式可以抓到游標或滑鼠目前所在DBGrid的Record? 我的意思是,讓游標所在之record可以立即顯示在另外的edit 內

   如果您的問題是對應一組 Edit 元件的話, 建議采用 TDBEdit 或 TDBLabel, 可以不必再費心管記錄位置;
   如果是只有一個 EditBox, 內容要一直反應 DBGrid 的目前記錄的目前欄位, 那可以同時在 DataSource 的 OnDataChange 與 DbGrid 的 OnColEnter 這兩個事件中寫更新EditBox內容的程式.
   例如 DBGrid 的 OnColEnter 事件:

procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
 if DBGrid1.SelectedField <> nil then
   Edit1.Text := DBGrid1.SelectedField.AsString;
end;

   但只靠 OnColEnter 是不夠的, 因為, 在同一個 Column(同一個欄位)上下移動反白方格時, OnColEnter 是不會被觸發的, 所以, 可以再搭配 OnDataChange事件, 在 State 為 dsBrowse 時的 DataChange, 可以視同記錄位置的改變,以下的程式是呼叫 DBGrid 的 OnColEnter 事件處理程序:

procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
 if DataSource1.State = dsBrowse then
   DBGrid1ColEnter(Sender);
end; 

 
 2003-11-19 11:39:38    用DbGrid制作edit錄入時的下拉提示框在Delphi語言中提拱了不少數據輸入的方法,如可從數據庫中選擇或人工輸入的控件有:DBListBox、DBComboBox、DBLookupListBox、DBLookupComboBox等。但對於這樣一個例子:數據庫名為dm.db,其中有兩個字段: 
   代碼:Code 
   名稱:Name 
要求根據用戶輸入的代碼,去獲取該代碼對應的名稱。 

   一般的用戶並不知道代碼和名稱的對應關系,如讓用戶輸入代碼,選出對應的名稱,由於上述的控件不能使操作人員看到代碼和名稱的對應關系,如讓用戶根據代碼用下拉框去查找到對應的該條紀錄的名稱,將很難操作。 

   根據這種情況,我編制了下面程序,把DBGrid做為Edit的下拉列表框輔助操作,在DBGrid中直觀地顯示出代碼和名稱的對應關系,並且能夠根據用戶錄入代碼的變化情況,隨時更新DBGrid中的記錄指針,使用戶可以直觀方便地點取所需要的名字,而且DBGrid是依據用戶在Edit中輸入代碼時才顯現,跳出Edit框即消失。這種方法既為用戶錄入提供了方便,又不影響界面的整體美觀,效果不錯。現把該程序提供給大家,你們可根據自己的需要,對程序進行加工處理,應用於程序開發中,希望起到拋磚引玉的作用。 

【問題】:做這樣一個小程序:讓用戶輸入代碼,然后將名稱顯示在窗體上。 

1、首先我們可以建立一個Form,在此Form中增加控件: 

Table : Table1,設置其屬性對應代碼庫dm.db,並將Active置為True 
DataSource : DataSource1, 設置其屬性DataSet為Table1 
Edit : CodeEdit,NameEdit分別對應代碼輸入框和名稱顯示框 
DBGrid : DBGrid1, 設置其屬性DataSource為DataSource1 
並把CodeEdit的屬性Text的值置空,NameEdit的屬性Text的值置空。 

2、對照以下語句,修改CodeEdit的OnEnter、OnExit、OnKeyDown、OnKeyUp事件: 

 在CodeEdit的OnEnter事件如下: 
 procedure TForm1.CodeEditEnter(Sender: TObject); 
 begin 
   if CodeEdit.text<>'' then 
   begin 
     CodeEdit.SelStart:=length(CodeEdit.text); 
     Table1.locate('code', CodeEdit.text,[lopartialkey]); 
   End; 
 end; 

 CodeEdit的OnExit事件如下: 
 procedure TForm1.CodeEditExit(Sender: TObject); 
 begin 
 if activecontrol<>dbgrid1 then 
 begin 
   dbgrid1.Visible:=false; 
   Table1.Locate('code',codeedit.text,[lopartialkey]); 
   if Table1.Eof then 
   begin 
     dbgrid1.Visible:=true; 
     exit; 
   end; 
   if not Table1.Eof then 
   begin 
     codeedit.Text:=Table1.fieldbyname('code').asstring; 
     NameEdit.Text := Table1.fieldbyname('name').asstring; 
   end; 
 end; 
 end; 

CodeEdit的OnKeyDown事件如下: 
Procedure Tform1.CodeEditKeyDown(Sender: TObject;var Key: Word;Shift: TShiftState); 
var 
 i:integer; 
begin 
 if (Table1.RecordCount>0) then 
 begin 
   case key of 48..57: 
   begin 
     dbgrid1.Visible:=true; 
     Table1.Locate('code',CodeEdit.text,[lopartialkey]); 
   end; 
   vk_next: 
   if dbgrid1.Visible then 
   begin 
     i:=0; 
     while (not Table1.Eof) and (i<11) do 
     begin 
       Table1.Next; 
       i:=i+1; 
     end; 
     CodeEdit.Text:=Table1.fieldbyname('code').asstring; 
   End; 
   vk_prior: 
   if dbgrid1.Visible then 
   begin 
     i:=0; 
     while (not Table1.Bof) and (i<11) do 
     begin 
       Table1.prior; 
       i:=i+1; 
     end; 
     CodeEdit.Text:=Table1.fieldbyname('code').asstring; 
   end; 
   vk_down: 
   if dbgrid1.Visible then 
   begin 
     if not Table1.Eof then 
     begin 
       Table1.Next; 
       CodeEdit.Text:=Table1.fieldbyname('code').asstring; 
     end; 
   end; 
   vk_up: 
   if dbgrid1.Visible then 
   begin 
     if not Table1.Bof then 
     begin 
       Table1.Prior; 
       CodeEdit.Text:=Table1.fieldbyname('code').asstring; 
     end; 
   end; 
 end; 
 end 
 else 
   dbgrid1.Visible:=false; 
 CodeEdit.SelStart:=length(CodeEdit.text); 
end; 

CodeEdit的OnKeyUp事件如下: 
procedure Tform1.CodeEditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); 
begin 
 if (Table1.RecordCount>0) then 
 begin 
   if ((key>=48) and (key<=57)) then 
     Table1.Locate('code',codeedit.text,[lopartialkey]); 
   if (key=VK_back) and (codeedit.text<>'') then 
     Table1.Locate('code',codeedit.text,[lopartialkey]); 
   if (key=VK_BACK) and (codeedit.text='') then 
     Table1.First; 
   if (key=vk_down) or (key=vk_up) or (key=vk_prior) or (key=vk_next) then 
     if dbgrid1.Visible then 
       codeedit.Text:=Table1.fieldbyname('code').asstring; 
 end 
 else 
   dbgrid1.Visible:=false; 
   codeedit.SelStart:=length(codeedit.text);  
end; 

本程序在Windows98+Delphi4.0、5.0下均調試通過。  

 
 2003-11-19 11:49:55    Delphi的dbgrid中根據數據的屬性不同顯示不同的顏色(請同時參考如何動態更新DBGrid的顏色?/如何使DBGRID網格的顏色隨此格中的數據值的變化而變化?)

   在應用系統中,用戶常常要求把數據按不同的顏色顯示出來,只要你在 Dbgrid 的 DrawColumnCell 事件中加入以下代碼就可以了:
If Query.fieldbyname('字段名').values 滿足條件 then
 Begin
   Dbgrid.Canvas.Brush.Color := 顏色(如:clInfoBk) ;
   Dbgrid.DefaultDrawColumnCell( Rect, DataCol, Column, [gdFixed,gdFocused,gdSelected] );
 End ; 

 
 2003-11-19 12:00:18    給DBGrid加入排序功能(同時參考“點擊DBGrid的Title對查詢結果排序”)
   在實際數據庫管理系統中,用戶對表中數據的操作,最頻繁的莫過於瀏覽查詢了,而查詢中若能提供為某字段建立的排序功能,則非常有利於用戶對“關鍵數據”的了解。 

   Windows的用戶都知道,在“我的電腦”或“資源管理器”中打開任一文件夾,若以“詳細資料”方式查看,系統會顯示出該文件夾下的子文件夾和文件相關信息,如:名稱、類型 、大小、修改時間,用戶只需要單擊標題欄中的相應項,則系統自動按該項進行“升序”(或“降序”)的排列顯示,這樣用戶便能輕松查看相應的文件夾或文件對象的內容。 

   受此啟發,考慮能不能在顯示數據的Grid表格中完成如此功能呢?答案是肯定的。下面以在Delphi中的實現方法為例,通過具體內容,介紹該功能的實現。 
步驟如下: 

一、先建立一數據表 
   該表以Delphi 中最常用的Paradox為類型,取名為Student,反映(在職)學生的基本情況。該表各字段定義如下: 
-------------------------------------------- 
字段名    類型      大小 
序號     Short型     / (Key*) 
學號     Alpha型     6 
出生日期   Date型      / 
性別     Alpha型     2 
婚否     Logical型    / 
英語     Number型     / 
高數     Number型     / 
PASCAL    Number型     / 
備注     Memo型      20 
------------------------------------------- 
保存后,隨意往表中輸入3至5條記錄內容。 

注:①表中必須建立關鍵索引(為首字段建立)。此處為“序號”字段; 
   ②該表中使用了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?等)。當然若有必要,可以在表單關閉前將所有的附加文件刪除。 

  

 
 2003-11-19 12:16:05    將 DBGrid 中的內容輸出至 Excel 或 ClipBoard
 //注意:下面的方法必須包含 ComObj, Excel97 單元
 //----------------------------------------------------------- 
 // if toExcel = false, export dbgrid contents to the Clipboard 
 // if toExcel = true, export dbgrid to Microsoft Excel 
 procedure ExportDBGrid(toExcel: Boolean); 
 var 
   bm: TBookmark; 
   col, row: Integer; 
   sline: String; 
   mem: TMemo; 
   ExcelApp: Variant; 
 begin 
   Screen.Cursor := crHourglass; 
   DBGrid1.DataSource.DataSet.DisableControls; 
   bm := DBGrid1.DataSource.DataSet.GetBookmark; 
   DBGrid1.DataSource.DataSet.First; 
 
   // create the Excel object 
   if toExcel then 
   begin 
     ExcelApp := CreateOleObject('Excel.Application'); 
     ExcelApp.WorkBooks.Add(xlWBatWorkSheet); 
     ExcelApp.WorkBooks[1].WorkSheets[1].Name := 'Grid Data'; 
   end; 
 
   // First we send the data to a memo 
   // works faster than doing it directly to Excel 
   mem := TMemo.Create(Self); 
   mem.Visible := false; 
   mem.Parent := MainForm; 
   mem.Clear; 
   sline := ''; 
 
   // add the info for the column names 
   for col := 0 to DBGrid1.FieldCount-1 do 
     sline := sline + DBGrid1.Fields[col].DisplayLabel + #9; 
   mem.Lines.Add(sline); 
 
   // get the data into the memo 
   for row := 0 to DBGrid1.DataSource.DataSet.RecordCount-1 do 
   begin 
     sline := ''; 
     for col := 0 to DBGrid1.FieldCount-1 do 
       sline := sline + DBGrid1.Fields[col].AsString + #9; 
     mem.Lines.Add(sline); 
     DBGrid1.DataSource.DataSet.Next; 
   end; 
 
   // we copy the data to the clipboard 
   mem.SelectAll; 
   mem.CopyToClipboard; 
 
   // if needed, send it to Excel 
   // if not, we already have it in the clipboard 
   if toExcel then 
   begin 
     ExcelApp.Workbooks[1].WorkSheets['Grid Data'].Paste; 
     ExcelApp.Visible := true; 
   end; 
 
   FreeAndNil(mem); 
 //  FreeAndNil(ExcelApp); 
   DBGrid1.DataSource.DataSet.GotoBookmark(bm); 
   DBGrid1.DataSource.DataSet.FreeBookmark(bm); 
   DBGrid1.DataSource.DataSet.EnableControls; 
   Screen.Cursor := crDefault; 
 end;  

 
 2003-11-19 12:20:56    怎樣獲得DBGrid中的cell的坐標???//新建一個工程,在窗體上加一個StringGrid

//下面是unit1.pas

unit Unit1;

interface

uses
 Windows  Messages  SysUtils  Classes  Graphics  Controls  Forms  Dia

logs
 Grids;

type
 TForm1 = class(TForm)
   StringGrid1: TStringGrid;
   procedure FormCreate(Sender: TObject);
   procedure StringGrid1DblClick(Sender: TObject);
   procedure StringGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X  Y: Integer);
   procedure StringGrid1Click(Sender: TObject);

 private
   { Private declarations }

 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

const
 WeekDayName :Array[1..7] of String=('星期一' '星期二' '星期三' '星期四
' '星期五' '星期六' '星期日');

var
 X_Pos Y_Pos:integer;//鼠標在窗體的位置
 Col_Pos Row_Pos:integer;//單元位置

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
 i:integer;
begin
 Application.HintPause:=100;
 Font.Size :=10;
 Caption:='STring岩石程序';
 StringGrid1.ShowHint :=True;
 StringGrid1.ColCount :=8;
 StringGrid1.RowCount :=12;
 StringGrid1.Cells[0 0]:='第18周';
 for i:=1 to StringGrid1.ColCount -1  do
 StringGrid1.Cells[i 0]:=WeekDayName[i];
 for i:=1 to StringGrid1.RowCount -1 do
   StringGrid1.Cells[0 i]:=InttoStr(i+7)+':00';
 StringGrid1.Options :=StringGrid1.Options+[goTabs goROwSizing goColSizing]-[goEditing];
end;

procedure TForm1.StringGrid1DblClick(Sender: TObject);
var
 SchemeItem:String;
begin
 StringGrid1.MouseToCell(X_Pos Y_Pos Col_Pos Row_Pos) ;  //轉換到單位位置
 if (Col_Pos<0 )or (Row_Pos<0 ) then
   Exit;
 if (StringGrid1.Cells[Col_Pos Row_Pos]<>''  ) then //取消計划概要
 begin
   StringGrid1.Cells[Col_Pos Row_Pos]:='';
   Exit;
 end;
 SchemeItem:=InputBox('提示' '請輸入計划概要:' '會議');
 StringGrid1.Cells[Col_Pos Row_Pos]:=SchemeItem;
End;

procedure TForm1.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X  Y: Integer);
begin
 X_Pos:=x;
 Y_Pos:=y;
end;

procedure TForm1.StringGrid1Click(Sender: TObject);
begin
 StringGrid1.MouseToCell(X_Pos Y_Pos Col_Pos Row_Pos);//轉化到單元位置
 StringGrid1.Hint :=StringGrid1.Cells[Col_Pos Row_Pos];//暫時借用該特性顯示工作計划
end;

end. 

 
 2003-11-19 12:33:15    多層表頭的DBGrid(推薦大家學習,很有用)   TclientDataSet控件是在Delphi中設計多層分布式數據庫程序的核心控件,在Delphi3中它最早出現,在Delphi4和Delphi5中得到了進一步加強。TclientDataSet控件具有強大的功能,無論是單層、兩層C/S和多層結構都可以使用TclientDataSet控件。從borland公司的公布的資料看,它的功能還將得到不斷增強,本文主要介紹利用TclientDataSet控件的特色功能——抽象字段類型配合TDBGRID控件實現復雜題頭。

   在設計數據庫錄入界面時,經常需要實現一些復雜題頭,這通常需要利用第三方控件或進行特殊處理才能實現。而在Delphi中利用TClientDataSe的ADT(抽象字段類型)配合TDbgrid控件,可以非常容易地實現這種題頭。

   下面就以一個員工的工資信息表來說明具體步驟。
   假設某單位的工資信息表的結構如圖所示。
-----------------
             基本信息
-----------------

 性別  |  年齡  |  籍貫  |  職稱

   首先生成一個新的 Application,在窗體上添加一個 TClientDataSet 構件和 TDataSource 構件,其 name 屬性分別為 ClientDataSet1 和 DataSource1 ,並把 DataSource1 的 DataSource 屬性設置為 ClientDataSet1 上;添加一個 TDBGRID 和 TdbNavigator 控件,命名為 DBGRID1 和 DbNavigator1,其 Datasource1 屬性設置為 ClientDataSet1。

   然后建立 TclientDataSet 的字段定義。這里只介紹如何定義抽象字段:將基本信息和工資作為兩個抽象字段,如圖3所示,將兩個字段分別命名為 INFO 和 Salary。

   然后依次建立 INFO 字段和 SALARY 的子字段,單擊對象觀察器的 ChildDefs,進入子字段編輯器,依次輸入該字段的子字段。然后調用 TclientDataSet 的快捷菜單(鼠標點擊 TclientDataSet 控件,然后右擊鼠標) CreateDataSet 建立 CDS 數據表,並保存文件。最后建立 TClientDataSet 的永久字段,TclientDataSet 的快捷菜單,選擇ADD All Fields。

   至此有關 ClientDataSet 的設置完畢。
   在設置完 ClientDataSet 之后,需要設置DBGRID的顯示屬性。主要就是設置 Colums 的有關屬性(略)。編譯運行即可出現如圖2所示的運行界面。然后添加一個 Tdbnavigator 控件,將其 DataSource 屬性設置為 Datasource1。這些與普通的基於BDE的數據庫應用是一樣的,不多敘述。 

 
 2003-11-19 13:33:24    在 dbgrid 中實現 copy、paste 功能  工具條上的Cut、Copy和Paste加速按鈕,對於使用Windows下編輯器的人來說,恐怕都是非常熟悉而且不可缺少的。Delphi中的有些控件,如:TDBEdit、TDBImage、TDBMemo、TEdit等,具有CutToClipboard、CopyToClipboard和PasteFromClipboard方法,在這些控件上,利用這幾個方法,只要通過簡單的編程,就可以實現上述加速按鈕。但TDBGrid控件卻不提供上述方法,無法直接實現這幾種功能。而在單機的數據庫應用程序中,TDBGrid卻經常被用來進行數據(包括數字和文字)的輸入,沒有Copy和Paste功能,使用起來深感不便。筆者在編程過程中,利用中間控件進行“過渡”,間接地實現了這幾種功能。

  【主要思路】:既然TDBGrid控件無法直接實現Copy和Paste編輯功能,則可以將TDBGrid控件中需要進行這幾種編輯的字段(Field)的內容,轉移到具備這幾種功能的控件(以TDBEdit為例)中去,編輯完畢后,再傳回到TDBGrid中。

  【具體方法】:在已設計好的包含有TDBGrid控件(設名為DBGrid1)的窗體中,增加一個TDBEdit(設名為DBEdit1)控件,其DataSources屬性設為與DBGrid1的DataSources屬性相同,對DBGrid1控件的OnColEnter事件編程,使DBEdit1的DataField屬性值等於DBGrid1控件的被選擇字段的字段名。再在窗體中增加兩個快速按鈕:Copy和Paste,圖形可選Delphi子目錄下ImagesιButtons子目錄里的Copy.bmp和Paste.bmp。
   對Copy快速按鈕的OnClick事件編程:
  DBEdit1.CopyToClipboard;

  對Paste快速按鈕的OnClick事件編程:
  DBEdit1.PasteFromClipboard;
  DBGrid1.SelectedField.AsString:=DBEdit1.Text;

  此時,如果DBGrid1中的某一單元Cell數字需要粘貼另一單元Cell2的部分或全部內容,用鼠標單擊選擇Cell2,此時DBEdit1所顯示的內容與Cell2的內容相同。在DBEdit1中用鼠標拖曳選擇部分或全部內容,單擊Copy快速按鈕;再用鼠標單擊選擇Cell,此時DBEdit1所顯示的內容與Cell相同,在DBEdit中欲粘貼剛才所選內容的位置插入光標,單擊Paste快速按鈕,則剛才所選內容插入到光標位置,Cell的內容也隨之改變成插入后的內容,由此完成了一次Copy—Paste操作。

  用這種方法實現Copy—Paste操作,比正常的操作多了一次鼠標的鍵擊、兩次鼠標的移動。在重復輸入的內容不多,且操作者鍵盤輸入很快很熟練的情況下,這種實現Copy—Paste的方法,意義似乎不大。但如果應用程序的使用者是那些並沒有掌握某種快速文字輸入技巧、很有可能還在使用拼音輸入法的人,如果使用者對正常的Copy—Paste方法本來就不熟練(則感覺不到這種方法的不合常規),且又非常地善於在一長串的同音字里翻來翻去地尋找的話,這還是一種不錯的方法。如果哪位讀者有能在TDBGrid中實現常規Copy—Paste操作的方法,請不吝賜教。

  以下是有關的程序代碼:
  procedure TUnitDetail.DBGrid1ColEnter(Sender:TObject);
  begin
   case DBGrid1.SelectedIndex of
    0:DBEdit1.DataField:='UnitNum';
     1:DBEdit1.DataField:='UnitName';
    2:DBEdit1.DataField:='Header';
    3:DBEdit1.DataField:='Address';
    4:DBEdit1.DataField:='Tel';
   end;
  end;

  
  procedure TUnitDetail.SBCopyClick(Sender:TObject);
  begin
    DBEdit1.CopyToClipboard;
  end;

  procedureTUnitDetail.SBPasteClick(Sender:TObject);
  begin
    DBEdit1.PasteFromClipboard;
    DBGrid1.SelectedField.AsString:=DBEdit1.text;
  end;  

 
 2003-11-19 13:34:33    禁止在DBGrid中按delete刪除記錄procedure TForm1.DBGrid1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 
begin 
 if (ssctrl in shift) and (key=vk_delete) then key:=0; 
end; 

 
 2003-11-19 13:39:54    給 DBGrid 添加搜索功能下面給出一個完整的例子,要注意的是:一開始需要將查詢的字段全部加入TDBGrid中,否則會有訪問沖突的。

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Db, DBTables, Grids, DBGrids, StdCtrls, ExtCtrls, DBCtrls;

type
 TTFm_Main = class(TForm)
   qry_Data: TQuery;
   Ds_Data: TDataSource;
   Ed_Search: TEdit; //附加一個TEdit框.
   dbg_Data: TDBGrid;
   Database1: TDatabase; //數據庫構件,試驗時可任意設定。
   DBNavigator1: TDBNavigator;
   procedure dbg_DataTitleClick(Column: TColumn);
   procedure FormCreate(Sender: TObject);
   procedure Ed_SearchChange(Sender: TObject);

 private
 { Private declarations }
   FQueryStatement: string; // SQL 查詢語句。
   FALphaNumericKeyPress: TKeyPressEvent;

 public
 { Public declarations }
   property QueryStatement: string read FQueryStatement;
   procedure FloatOnKeyPress(Sender: TObject; var Key: Char);
 end;

var
 TFm_Main: TTFm_Main;

implementation

{$R *.DFM}

procedure TTFm_Main.dbg_DataTitleClick(Column: TColumn);
var
 vi_Counter: Integer;
 vs_Field: string;
begin
 with dbg_Data do
 begin

 //First, deselect all the Grid Columns
   for vi_Counter := 0 to Columns.Count - 1 do
     Columns[vi_Counter].Color := clWindow;

 //Next "Select" the column the user has Clicked on
   Column.Color := clTeal;

 //Get the FieldName of the Selected Column
   vs_Field := Column.FieldName;

 //Order the Grid Data by the Selected column
   with qry_Data do
   begin
     DisableControls;
     Close;
     SQL.Clear;
     SQL.Text := QueryStatement + ' ORDER BY ' + vs_Field;
     Open;
     EnableControls;
   end;
 //Get the DataType of the selected Field and change the Edit event

 //OnKeyPress to the proper method Pointer
   case Column.Field.DataType of
     ftFloat: Ed_Search.OnKeyPress := FloatOnKeyPress;
   else
     Ed_Search.OnKeyPress := FALphaNumericKeyPress;
   end;
 end;
end;

procedure TTFm_Main.FloatOnKeyPress(Sender: TObject; var Key: Char);
begin
 if not (Key in ['0'..'9', #13, #8, #10, #46]) then
   Key := #0;
end;

procedure TTFm_Main.FormCreate(Sender: TObject);
begin

 //Keep a pointer for the default event Handler
 FALphaNumericKeyPress := Ed_Search.OnKeyPress;

 //Set the original Query SQL Statement
 FQueryStatement := 'SELECT * FROM your_table_name';

 //Select the first Grid Column
 dbg_DataTitleClick(dbg_Data.Columns[0]);
end;

procedure TTFm_Main.Ed_SearchChange(Sender: TObject);
var
 vi_counter: Integer;
 vs_Field: string;
begin
 try
   with dbg_Data do
   begin

 //First determine wich is the Selected Column
     for vi_Counter := 0 to Columns.Count - 1 do
       if Columns[vi_Counter].Color = clTeal then
       begin
         vs_Field := Columns[vi_Counter].FieldName;
         Break;
       end;

 //Locate the Value in the Query
     with qry_Data do
       case Columns[vi_Counter].Field.DataType of
         ftFloat: Locate(vs_Field, StrToFloat(Ed_Search.Text),
             [loCaseInsensitive, loPartialKey]);
       else
         Locate(vs_Field, Ed_Search.Text, [loCaseInsensitive, loPartialKey]);
       end;
   end;
 except
 end;
end;

end. 

 
 2003-11-19 13:53:23    數據網格自動適應寬度///////源代碼開始
uses
 Math;

function DBGridRecordSize(mColumn: TColumn): Boolean;
{ 返回記錄數據網格列顯示最大寬度是否成功 }
begin
 Result := False;
 if not Assigned(mColumn.Field) then Exit;
 mColumn.Field.Tag := Max(mColumn.Field.Tag,
   TDBGrid(mColumn.Grid).Canvas.TextWidth(mColumn.Field.DisplayText));
 Result := True;
end; { DBGridRecordSize }

function DBGridAutoSize(mDBGrid: TDBGrid; mOffset: Integer = 5): Boolean;
{ 返回數據網格自動適應寬度是否成功 }
var
 I: Integer;
begin
 Result := False;
 if not Assigned(mDBGrid) then Exit;
 if not Assigned(mDBGrid.DataSource) then Exit;
 if not Assigned(mDBGrid.DataSource.DataSet) then Exit;
 if not mDBGrid.DataSource.DataSet.Active then Exit;
 for I := 0 to mDBGrid.Columns.Count - 1 do begin
   if not mDBGrid.Columns[I].Visible then Continue;
   if Assigned(mDBGrid.Columns[I].Field) then
     mDBGrid.Columns[I].Width := Max(mDBGrid.Columns[I].Field.Tag,
       mDBGrid.Canvas.TextWidth(mDBGrid.Columns[I].Title.Caption)) + mOffset
   else mDBGrid.Columns[I].Width :=
     mDBGrid.Canvas.TextWidth(mDBGrid.Columns[I].Title.Caption) + mOffset;
   mDBGrid.Refresh;
 end;
 Result := True;
end; { DBGridAutoSize }
///////源代碼結束

///////使用示例開始
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
 DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
 DBGridRecordSize(Column);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 DBGridAutoSize(DBGrid1);
end;
///////使用示例結束 

 
 2003-11-19 13:55:47    移除DBGrid的垂直滾動條(參考“判斷Grid是否有滾動條?”)type
 TNoVertScrollDBGrid = class(TDBGrid)
 protected
   procedure Paint; override;
 end;

procedure Register;

implementation

procedure TNoVertScrollDBGrid.Paint;

begin
 SetScrollRange(Self.Handle, SB_VERT, 0, 0, False);
 inherited Paint;
end;

procedure Register;
begin
 RegisterComponents('Data Controls', [TNoVertScrollDBGrid]);
end;

end. 

 
 2003-11-19 14:00:48    DBGrid拖放的例子(請同時參考“在TDBGrid控件中實現拖放的另外一個思路/在DBGrid上Drag & Drop(拖放)”)unit GridU1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
 Dialogs, Db, DBTables, Grids, DBGrids, StdCtrls;

type
 TForm1 = class(TForm)
   MyDBGrid1: TDBGrid;
   Table1: TTable;
   DataSource1: TDataSource;
   Table2: TTable;
   DataSource2: TDataSource;
   MyDBGrid2: TDBGrid;
   procedure MyDBGrid1MouseDown(Sender: TObject;
     Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
   procedure MyDBGrid1DragOver(Sender, Source: TObject;
     X, Y: Integer; State: TDragState; var Accept: Boolean);
   procedure MyDBGrid1DragDrop(Sender, Source: TObject;
     X, Y: Integer);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}

var
 SGC : TGridCoord;

procedure TForm1.MyDBGrid1MouseDown(Sender: TObject;
 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
 DG : TDBGrid;
begin
 DG := Sender as TDBGrid;
 SGC := DG.MouseCoord(X,Y);
 if (SGC.X > 0) and (SGC.Y > 0) then
   (Sender as TDBGrid).BeginDrag(False);
end;

procedure TForm1.MyDBGrid1DragOver(Sender, Source: TObject; 
 X, Y: Integer; State: TDragState; var Accept: Boolean);
var
 GC : TGridCoord;
begin
 GC := (Sender as TDBGrid).MouseCoord(X,Y);
 Accept := Source is TDBGrid and (GC.X > 0) and (GC.Y > 0);
end;

procedure TForm1.MyDBGrid1DragDrop(Sender, Source: TObject;
 X, Y: Integer);
var
 DG     : TDBGrid;
 GC     : TGridCoord;
 CurRow : Integer;
begin
 DG := Sender as TDBGrid;
 GC := DG.MouseCoord(X,Y);
 with DG.DataSource.DataSet do begin
   with (Source as TDBGrid).DataSource.DataSet do
     Caption := 'You dragged "'+Fields[SGC.X-1].AsString+'"';
   DisableControls;
   CurRow := DG.Row;
   MoveBy(GC.Y-CurRow);
   Caption := Caption+' to "'+Fields[GC.X-1].AsString+'"';
   MoveBy(CurRow-GC.Y);
   EnableControls;
 end;
end;

end. 

 
 2003-11-24 11:03:41    解決dbgrid上下移動的另外一種辦法不用重新寫控件,也不用改控件!直接將光色代碼部分加到你的窗體單無中就行.
type
【 TDBGrid = class(DBGrids.TDBGrid)
private
 FOldGridWnd : TWndMethod;
 procedure NewGridWnd (var Message : TMessage);
public
 constructor Create(AOwner: TComponent); override;
end;】
TXXXForm = class(TForm)
 ......
end;
{ TDBGrid }


【constructor TDBGrid.Create(AOwner: TComponent);
begin
inherited;
Self.FOldGridWnd := Self.WindowProc;
Self.WindowProc :=  NewGridWnd;
end;

procedure TDBGrid.NewGridWnd(var Message: TMessage);
var
IsNeg : Boolean;
begin

if Message.Msg = WM_MOUSEWHEEL then
begin
 IsNeg := Short(Message.WParamHi) < 0;
 if IsNeg then
  self.DataSource.DataSet.MoveBy(1)
 else
  self.DataSource.DataSet.MoveBy(-1)
end
else Self.FOldGridWnd(Message);

end;
】


TDBGrid = class(DBGrids.TDBGrid)
....
end;
一定要放在最前面,也可以將【】紅色部分代碼寫一共用單無中,
然後uses publicunit;
再加上這一句:
TDBGrid = Class(publicunit.TDBGrid); 
TXXFrom =Class(TForm)   

 
 2003-11-25 17:29:59    修改過的Grids,可以支持鼠標滾輪翻頁的功能。   拷貝到/delphi/source/vcl目錄下就能使用。不過我用的是D7,低版本的朋友還是先看看再使用,以防不測。 

修改過的Grids,可以支持鼠標滾輪翻頁的功能。
 
 2003-12-1 10:29:21    可以支持鼠標滾輪翻頁的功能的Grids   詳細說明見內。 

可以支持鼠標滾輪翻頁的功能的Grids

原樣打印DBGrid:
uses
.....printers

procedure Tform.Button1Click(Sender: TObject);
 const
LeftBlank=1; //定義頁邊距,單位厘米
RightBlank=1;
TopBlank=1;
BottomBlank=1;
var
pointX,PointY:integer;
PointScale,PrintStep,printW:integer;
s:string;
x,y,z:integer;
i,j:integer;
begin
if mainfrm.printersetupdialog1.execute=true then
begin //獲取當前打印機的分辨率
  PointX:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/2.54);
  pointY:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSY)/2.54);   //根據打印機和屏幕的分辨率計算出從屏幕轉換到打印機的比例 
  PointScale:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/Screen.PixelsPerInch+0.5); //橫向打印
  //printer.Orientation:=poportrait;  //poLandscape;  //打印的字體和大小
  printer.Canvas.Font.Name:='宋體';
  printer.canvas.Font.Size:=11;
  //根據字體的大小確定每行的高度
  s:='各車間勞保到期情況';
  PrintStep:=printer.canvas.TextHeight(s)+16;
  printW:=printer.canvas.textwidth(s);
  //打印的起點位置
  x:=PointX*LeftBlank;
  z:=pointX*leftblank;
  y:=PointY*TopBlank;
  j:=1;
  //DataSource1是DBGrid1所連接的數據源
  if ((DataSource1.DataSet).Active=true) and ((DataSource1.DataSet).RecordCount>0) then
     begin
       DataSource1.dataSet.disableControls;
       printer.BeginDoc;
         for i:=0 to DBGrid1.FieldCount-1 do
         z:=z+DBGrid1.Columns.Items[i].Width*PointScale;
       (DataSource1.DataSet).First;
       while not (DataSource1.DataSet).Eof do
           begin //打印DBGrid中的所有列
             for i:=0 to DBGrid1.FieldCount-1 do
               begin //假如所要 打印的列超出了打印范圍,則忽略該列
                 if (x+DBGrid1.Columns.Items[i].Width*PointScale)<=(Printer.PageWidth-PointX*RightBlank) then
                    begin //畫表格線 每頁的第一行打印表頭
                      Printer.Canvas.Rectangle(x,y,x+DBGrid1.Columns.Items[i].Width*PointScale,y+PrintStep);
                      if y=PointY*TopBlank then
                         begin
                           printer.canvas.Font.Size:=14;
                           printer.canvas.textout(trunc((z-printw) div 2),1,flatcombobox1.text+'車間勞保發放明細表');
                           printer.canvas.Font.Size:=11;
                           Printer.Canvas.TextOut(x+8,y+8,DBGrid1.Columns[i].Title.Caption);
                         end
                     else
                            Printer.Canvas.TextOut(x+8,y+8,DBGrid1.Fields[i].asString);
                     end; //計算下一列的橫坐標
                   x:=x+DBGrid1.Columns.Items[i].Width*PointScale;
                end;
            if not (y=PointY*TopBlank) then
               (DataSource1.DataSet).next;
            x:=PointX*LeftBlank;
            y:=y+PrintStep; //換頁
            if ((y+PrintStep)>(Printer.PageHeight-PointY*BottomBlank))
              or ((DataSource1.DataSet).eof) then
              begin
                printer.canvas.TextOut(trunc(z/2),y+printstep,'第'+inttostr(j)+'頁');
                Printer.NewPage;
                y:=PointY*TopBlank;
                j:=j+1;
              end;
          end;
            printer.EndDoc;
            (DataSource1.DataSet).First;
            DataSource1.dataset.EnableControls;
            Application.MessageBox('正在打印,請等待。','提示:',32);
     end;
end;

end;  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM