DBGrid内使用CheckBox功能

   Delphi内DBGrid使用CheckBox功能一般有两种方法,最简单的就是使用第三方控件,如TDBGridEh,使用非常方便,唯一的缺点就是编译出的文件大,大概要大500KB那个样子。另外一种相对简单的方法就是使用DBCheckBox与DBGrid结合并使用绘制控件的方法实现,下面是使用后者实现的一个简单示例,不足之处请指教。

      使用DBCheckBox与DBGrid结合并使用绘制控件的方法实现可以封装为控件以便以后方便使用,但控件部署麻烦,个人使用的话修改麻烦,下面我们使用一个实用类进行了封装,这样修改代码也比较方便,便于自行扩展。具体如下:

效果见图:

(1)主要代码如下:

{*******************************************************}
{ Description : TDBGrid 扩展功能控制单元                        }
{ Creater : 张皓                                        }
{ Create Date : 2010-6-30 22:40:12                      }
{ Modifier :                                            }
{ Modify Remark :                                       }
{ Modify Date : 2010-7-7 16:00:00                                          }
{ Version : 1.0                                         }
{*******************************************************}

unit DBGridExControler;

interface

uses
  Classes, DBGrids, Grids, Types, Controls, DBCtrls, Windows, Messages,
  SysUtils, Forms, DB;

type
  TDBGridExControler = class(TComponent)
  private
    { Private declarations }
    FGrid:TDBGrid;
    FDBCheckBox:TDBCheckBox;
    FGridOnDrawColumnCell:TDrawColumnCellEvent;
    FGridOnEnter:TNotifyEvent;
    FGridOnColEnter:TNotifyEvent;
    FGridOnColExit:TNotifyEvent;
    FGridOnKeyPress:TKeyPressEvent;
    FGridOnMouseUp:TMouseEvent;

    FDataField:WideString;
    FValueChecked:string;
    FValueUnchecked:string;
    AllowEditing:Boolean;

    /// <summary>
    /// 判断是否是选中
    /// </summary>
    function AreChecked(AValue:string):Boolean;
    /// <summary>
    /// 设置事件
    /// </summary>
    procedure SetEvents();
    procedure SetDataField(AValue:WideString);
    procedure SetValueChecked(AValue:string);
    procedure SetValueUnChecked(AValue:string);
    procedure SetGrid(AValue:TDBGrid);

    procedure DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure Enter(Sender: TObject);
    procedure ColEnter(Sender: TObject);
    procedure ColExit(Sender: TObject);
    procedure KeyPress(Sender: TObject; var Key: Char);
    procedure MouseUp(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);

    procedure CheckBoxClick(Sender: TObject);
  public
    { Public declarations }
    property DataField:WideString read FDataField write SetDataField;
    property ValueChecked:string read FValueChecked write SetValueChecked;
    property ValueUnchecked:string read FValueUnChecked write SetValueUnChecked;
    property Grid:TDBGrid read FGrid write SetGrid;

    constructor Create(AOwner:TComponent);overload;
    constructor Create(AOwner:TComponent;AGrid:TDBGrid; ADataField:WideString;
      AValueChecked:string='True';AValueUnchecked:string='False');overload;

    procedure SetGridDrawColumnCellEvent(AValue:TDrawColumnCellEvent);
    procedure SetGridEnterEvent(AValue:TNotifyEvent);
    procedure SetGridColEnterEvent(AValue:TNotifyEvent);
    procedure SetGridColExitEvent(AValue:TNotifyEvent);
    procedure SetGridKeyPressEvent(AValue:TKeyPressEvent);
    procedure SetGridMouseUpEvent(AValue:TMouseEvent);
  end;

implementation

{$REGION '事件'}

function TDBGridExControler.AreChecked(AValue:string):Boolean;
begin
  Result := SameText(Trim(AValue),Trim(FValueChecked));
end;

procedure TDBGridExControler.DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
const IsChecked : array[Boolean] of Integer =
      (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
  DrawState: Integer;
  DrawRect: TRect;
  ChkLeft,ChkTop:Integer;
begin
  if (gdFocused in State) or (gdSelected in State) then
  begin
    if (Column.Field.FieldName = FDBCheckBox.DataField) then
    begin
      FDBCheckBox.Width := 13;
      FDBCheckBox.Height := 13;
      FDBCheckBox.Left := FGrid.Left + Rect.Left + (Rect.Right-Rect.Left- FDBCheckBox.Width) div 2 + 2;
      FDBCheckBox.Top := FGrid.Top +  Rect.Top + (Rect.Bottom-Rect.Top- FDBCheckBox.Height) div 2 + 2;
      FGrid.Canvas.FillRect(Rect);
      FDBCheckBox.Visible := True;
    end
  end
  else
  begin
    if (Column.Field.FieldName = FDBCheckBox.DataField) then
    begin
      DrawRect:=Rect;
      InflateRect(DrawRect,-1,-1);

      DrawState := ISChecked[AreChecked(Column.Field.AsString)];

      FGrid.Canvas.FillRect(Rect);
      DrawFrameControl(FGrid.Canvas.Handle, DrawRect, DFC_BUTTON, DrawState);
    end;
  end;

  if Assigned(FGridOnDrawColumnCell) then
    FGridOnDrawColumnCell(Sender,Rect,DataCol,Column,State);
end;

procedure TDBGridExControler.Enter(Sender: TObject);
begin
  if Assigned(FGridOnEnter) then
    FGridOnEnter(Sender);

  // 解决当Grid获取焦点且进入第一列时Grid的OnColEnter不执行的问题
  if FGrid.SelectedIndex = 0 then ColEnter(Sender);
end;

procedure TDBGridExControler.ColEnter(Sender: TObject);
begin
  if FGrid.SelectedField.FieldName = FDBCheckBox.DataField then
  begin
    AllowEditing:= dgEditing in FGrid.Options;
    if AllowEditing then
      FGrid.Options:=FGrid.Options-[dgEditing];
  end;

  if Assigned(FGridOnColEnter) then
    FGridOnColEnter(Sender);
end;

procedure TDBGridExControler.ColExit(Sender: TObject);
begin
  if FGrid.SelectedField.FieldName = FDBCheckBox.DataField then
  begin
    if AllowEditing and not (dgEditing in FGrid.Options) then
      FGrid.Options:=FGrid.Options+[dgEditing];
    FDBCheckBox.Visible := False;
  end;

  if Assigned(FGridOnColExit) then
    FGridOnColExit(Sender);
end;

procedure TDBGridExControler.KeyPress(Sender: TObject; var Key: Char);
begin
  if (key <> Chr(9)) then
  begin
    if (FGrid.SelectedField.FieldName = FDBCheckBox.DataField) then
    begin
      FDBCheckBox.SetFocus;
      SendMessage(FDBCheckBox.Handle, WM_Char, word(Key), 0);

      FGrid.DataSource.DataSet.Edit;
      if AreChecked(FGrid.SelectedField.AsString) then
        FGrid.SelectedField.AsString := FValueUnchecked
      else
        FGrid.SelectedField.AsString := FValueChecked;
      //FGrid.SelectedField.AsString := not  FGrid.SelectedField.AsBoolean;
      FGrid.DataSource.DataSet.Post;
    end;
  end;

  if Assigned(FGridOnKeyPress) then
    FGridOnKeyPress(Sender,Key);
end;

procedure TDBGridExControler.MouseUp(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
begin
  if (FGrid.SelectedField.FieldName = FDBCheckBox.DataField) or (dgRowSelect in FGrid.Options ) then
  begin
    // 在CheckBox范围内
    if (X+FGrid.Left>FDBCheckBox.Left) and (X+FGrid.Left <FDBCheckBox.Left+FDBCheckBox.Width) and
      (Y+FGrid.Top>FDBCheckBox.Top) and (Y+FGrid.Top <FDBCheckBox.Top+FDBCheckBox.Height) then
    begin
      FDBCheckBox.SetFocus;
      with FGrid.DataSource.DataSet  do
      begin
        Edit;
        if AreChecked(FieldByName(FDBCheckBox.DataField).AsString) then
          FieldByName(FDBCheckBox.DataField).AsString := FValueUnchecked
        else
          FieldByName(FDBCheckBox.DataField).AsString := FValueChecked;
        //Post;
      end;
//      FGrid.DataSource.DataSet.Edit;
//      FGrid.DataSource.DataSet.FieldByName(FDBCheckBox.DataField).AsBoolean :=
//        not  FGrid.DataSource.DataSet.FieldByName(FDBCheckBox.DataField).AsBoolean;
//      FGrid.DataSource.DataSet.Post;
    end;
  end;

  if Assigned(FGridOnMouseUp) then
    FGridOnMouseUp(Sender,Button,Shift,X,Y);
end;

procedure TDBGridExControler.CheckBoxClick(Sender: TObject);
begin
//  if TForm(FGrid.Owner).Showing then
//    if (FDBCheckBox.DataSource<>nil) and (FDBCheckBox.DataSource.DataSet<>nil) then
//      if (dsEdit=FDBCheckBox.DataSource.DataSet.State) or (dsInsert=FDBCheckBox.DataSource.DataSet.State) then
//        FDBCheckBox.DataSource.DataSet.Post;
end;

{$ENDREGION}

constructor TDBGridExControler.Create(AOwner:TComponent);
begin
  inherited;
  FGrid:=nil;
  FDBCheckBox:=nil;
  FDataField:='';
  FValueChecked:='True';
  FValueUnchecked:='False';
end;

constructor TDBGridExControler.Create(AOwner:TComponent;AGrid:TDBGrid;
  ADataField:WideString;AValueChecked:string='True';AValueUnchecked:string='False');
begin
  Create(AOwner);
  FGrid:=nil;
  FDBCheckBox:=nil;
  FGrid:=AGrid;
  FDataField:=ADataField;
  FValueChecked:=AValueChecked;
  FValueUnchecked:=AValueUnchecked;
  SetEvents();
end;

procedure TDBGridExControler.SetDataField(AValue:WideString);
begin
  FDataField:=AValue;
  if FDBCheckBox<>nil then
    FDBCheckBox.DataField:=FDataField;
end;

procedure TDBGridExControler.SetValueChecked(AValue:string);
begin
  FValueChecked:=AValue;
  if FDBCheckBox<>nil then
    FDBCheckBox.ValueChecked:=FValueChecked;
end;

procedure TDBGridExControler.SetValueUnChecked(AValue:string);
begin
  FValueUnchecked:=AValue;
  if FDBCheckBox<>nil then
    FDBCheckBox.ValueUnchecked:=FValueUnchecked;
end;

procedure TDBGridExControler.SetGrid(AValue:TDBGrid);
begin
  if FGrid<>AValue then
  begin
    FGrid:=AValue;
    SetEvents();
  end;
end;

procedure TDBGridExControler.SetGridDrawColumnCellEvent(AValue:TDrawColumnCellEvent);
begin
  FGridOnDrawColumnCell:=AValue;
  FGrid.OnDrawColumnCell:=Self.DrawColumnCell;
end;

procedure TDBGridExControler.SetGridEnterEvent(AValue:TNotifyEvent);
begin
  FGridOnEnter:=AValue;
  FGrid.OnEnter:=Self.Enter;
end;

procedure TDBGridExControler.SetGridColEnterEvent(AValue:TNotifyEvent);
begin
  FGridOnColEnter:=AValue;
  FGrid.OnColEnter:=Self.ColEnter;
end;

procedure TDBGridExControler.SetGridColExitEvent(AValue:TNotifyEvent);
begin
  FGridOnColExit:=AValue;
  FGrid.OnColExit:=Self.ColExit;
end;

procedure TDBGridExControler.SetGridKeyPressEvent(AValue:TKeyPressEvent);
begin
  FGridOnKeyPress:=AValue;
  FGrid.OnKeyPress:=Self.KeyPress;
end;

procedure TDBGridExControler.SetGridMouseUpEvent(AValue:TMouseEvent);
begin
  FGridOnMouseUp:=AValue;
  FGrid.OnMouseUp:=Self.MouseUp;
end;

/// <summary>
/// 设置事件
/// </summary>
procedure TDBGridExControler.SetEvents();
begin
  if FGrid<>nil then
  begin
    FGridOnDrawColumnCell:=FGrid.OnDrawColumnCell;
    FGridOnEnter:=FGrid.OnEnter;
    FGridOnColEnter:=FGrid.OnColEnter;
    FGridOnColExit:=FGrid.OnColExit;
    FGridOnKeyPress:=FGrid.OnKeyPress;
    FGridOnMouseUp:=FGrid.OnMouseUp;
    AllowEditing:= dgEditing in FGrid.Options;

    FGrid.OnDrawColumnCell:=Self.DrawColumnCell;
    FGrid.OnEnter:=Self.Enter;
    FGrid.OnColEnter:=Self.ColEnter;
    FGrid.OnColExit:=Self.ColExit;
    FGrid.OnKeyPress:=Self.KeyPress;
    FGrid.OnMouseUp:=Self.MouseUp;

    if FDBCheckBox=nil then
    begin
      FDBCheckBox:=TDBCheckBox.Create(Self);
      FDBCheckBox.OnClick:=Self.CheckBoxClick;
      FDBCheckBox.Visible:=False;
    end;
    FDBCheckBox.Parent:=FGrid.Parent;
    FDBCheckBox.DataSource:=FGrid.DataSource;
    FDBCheckBox.DataField:=FDataField;
    FDBCheckBox.ValueChecked:=ValueChecked;
    FDBCheckBox.ValueUnchecked:=ValueUnchecked;
  end;
end;

end.

 

(二)调用方法:

unit ExampleFrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DBGridExControler, DB, DBClient, Grids, DBGrids, StdCtrls, DBCtrls,
  ActnList;

type
  TForm2 = class(TForm)
    dbgrd1: TDBGrid;
    cds1: TClientDataSet;
    intgrfldcds1id: TIntegerField;
    strngfldcds1Name: TStringField;
    blnfldcds1checked: TBooleanField;
    ds1: TDataSource;
    dbgrd2: TDBGrid;
  private
    { Private declarations }
  public
    { Public declarations }
    DBGridExControler:TDBGridExControler;

    //DBGridExControler2:TDBGridExControler;
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin

  // 如有多个字段都显示CheckBox只需创建多个TDBGridExControler对象即可
  DBGridExControler:=TDBGridExControler.Create(Self,dbgrd1,'checked');

  //DBGridExControler2:=TDBGridExControler.Create(Self,dbgrd1,'id','1','0');

 

  with cds1 do
  begin
    Append;
    FieldByName('id').AsInteger:=1;
    FieldByName('name').AsString:='name1';
    FieldByName('checked').AsBoolean:=False;
    Post;

    Append;
    FieldByName('id').AsInteger:=2;
    FieldByName('name').AsString:='name2';
    FieldByName('checked').AsBoolean:=True;
    Post;

    Append;
    FieldByName('id').AsInteger:=3;
    FieldByName('name').AsString:='name3';
    FieldByName('checked').AsString:='False';
    Post;
  end;
end;

end.

posted on 2010-07-01 09:06  张皓  阅读(5144)  评论(0编辑  收藏  举报

导航