My question is how to set a column in dbgrid in Delphi 7 which will be with a checkbox items.
Thanks in advance.
If you're using the TClientDataset+TDatasetProvider+TDataset, you can manipulate the data array variant before it gets to the clientdataset and include an not updatable boolean field.
Once is done, all you need is to draw on the grid using the OnDrawColumnCell event. Here I doesn't used a CheckBox but just a bitmap (when user click it changes to selected/unselected).
Please excuse me for posting this as answer, I don't have the 50 reputation to add comments yet.
Mihai MATEI's answer is very close to the rare (as in really working) solution except for an use case where it bugs.
Whenever the users' first action on the grid is to click on the checkbox, the first click will work but the second will reveal the underlying DBGrid editor.
This happens because the "GridOriginalOptionsmechan" mechanism needs to be initialized. To do so, just add the following code in the grid's OnEnter event:
procedure TForm1.DBGrid1Enter(Sender: TObject);
begin
DBGrid1ColEnter(Sender);
end;
That's it!
The easiest and most complete method as tested by me is as follows:
In the private section of your unit, declare a global for retaining grid options. It will be used for restoring after temporary disabling text editing while entering the checkbox column - as this is maybe one of the little errors mentioned by Jordan Borisovin regarding the delphi.about.com article
private
GridOriginalOptions : TDBGridOptions;
In the OnCellClick event, if field is boolean, toggle and post change to database
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
if (Column.Field.DataType=ftBoolean) then
begin
Column.Grid.DataSource.DataSet.Edit;
Column.Field.Value:= not Column.Field.AsBoolean;
Column.Grid.DataSource.DataSet.Post;
end;
end;
Drawing the checkbox for boolean fields of the grid
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
CtrlState: array[Boolean] of integer = (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED) ;
begin
if (Column.Field.DataType=ftBoolean) then
begin
DBGrid1.Canvas.FillRect(Rect) ;
if (VarIsNull(Column.Field.Value)) then
DrawFrameControl(DBGrid1.Canvas.Handle,Rect, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_INACTIVE)
else
DrawFrameControl(DBGrid1.Canvas.Handle,Rect, DFC_BUTTON, CtrlState[Column.Field.AsBoolean]);
end;
end;
Now the new part, disable cell editing while in the boolean column. On the OnColEnter and OnColExit events:
procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
if Self.DBGrid1.SelectedField.DataType = ftBoolean then
begin
Self.GridOriginalOptions := Self.DBGrid1.Options;
Self.DBGrid1.Options := Self.DBGrid1.Options - [dgEditing];
end;
end;
procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
if Self.DBGrid1.SelectedField.DataType = ftBoolean then
Self.DBGrid1.Options := Self.GridOriginalOptions;
end;
Even more, handle space key for toggling the checkbox
procedure TForm1.DBGrid1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if ((Self.DBGrid1.SelectedField.DataType = ftBoolean) and (key = VK_SPACE)) then
begin
Self.DBGrid1.DataSource.DataSet.Edit;
Self.DBGrid1.SelectedField.Value:= not Self.DBGrid1.SelectedField.AsBoolean;
Self.DBGrid1.DataSource.DataSet.Post;
end;
end;
That's it!
OK I used this article for my problem. OK But the problem is that it wasn't working how it should. So I change my logic in the code. And implementing it by saving the selected rows from the dbgrid in a list.