delphi DBgrid应用全书

在一个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中显示多个数据库内容的一般方法,读者可在此基础上进行完
善,使该方法更好地适应您的需要。 
在 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 
从 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; 
使用 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;
在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的帮助。 

如何使DBGrid的指针不移动? 
【问题】:我用DBGRID显示TABLE中的内容,现在我要从头到尾读一遍TABLE里的数据,用
Table1.First,Next来做会使DBGRID里面的指针也跟着跑,怎么才能使这时候DBGRID里面的指针不
动呢?
【答案】:使用如下代码即可:
  with DataSet do
  try
    DisableControls;
    Do_something;
  finally
    EnableControls;
  end; 
如何动态更新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;
上面的例子是简单的,但是你可以根据自己的需要扩充,例如字体也变化等,甚至你可以调用画圆的函数在数字上画上一个红色的圆圈。 
使用DBGrid显示日期 
   在使用 DBGRID 控件时显示 DATATIME 时其年份是为2位的,但我们在步入2000年后需要显示的日期是4位,如:1998、2001。在数据库中该字段只有在2000年后才会显示4位,怎么办呢? 下面我们就让该字段在DBGRID控件中也显示4位的日期格式: 双击 Table1 控件,就会出现 form1.table 窗体,击右键,选 Add Fields...,选择日期字段后按ok,窗体中就出现了数据库的日期字段名,点日期的那个字段名,属性框里就出现了该字段的信息,里面有一项 DispalyFormat,在该显示格式里输入 yyyy.mm.dd ,那么DBGRID控件就出现完整的日期了。 
在TDBGrid控件中实现拖放的另外一个思路(请同时参考在DBGrid上Drag & Drop(拖放)) 
   在本unit中,自定义TMyCustomDBGrid=class(TCustomDBGrid),再如下引用:
TMyCustomDBGrid(DBGrid1).MouseDown(...)
  或
    DBGrid1 as TMyCustomDBGrid).MouseDown(...)即可。 
在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; 
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 属性设置的下拉列表设计较为简单。  
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下调试通过。 

猜你喜欢

转载自www.cnblogs.com/jijm123/p/12364615.html