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.