7

My question is how to set a column in dbgrid in Delphi 7 which will be with a checkbox items.

Thanks in advance.

menjaraz
  • 7,551
  • 4
  • 41
  • 81
Jordan Borisov
  • 1,603
  • 6
  • 34
  • 69
  • 12
    Hi there, have you tried to follow e.g. [`this`](http://delphi.about.com/od/usedbvcl/l/aa082003a.htm) tutorial ? – TLama Jan 26 '12 at 14:48
  • 2
    @TLama, if you post your comment as the answer, I'd vote up. – PA. Jan 26 '12 at 19:47
  • 2
    @TLama, perfect link (and good choice not to make it an answer). PA, a link to an external site with no other content (or content that would be meaningless if the external link doesn't work) is not an acceptable answer here. Answers should be stand-alone, and remain useful without any other content. TLama made a perfect decision. External-link-only answers are usually flagged and deleted pretty quickly. – Ken White Jan 27 '12 at 01:44
  • Yes I found this link and try to implemented it. But there is a littler errors. So I'd changed my logic in the source. But thanks in advance. You should post it like an answer and I'll set it as one. – Jordan Borisov Jan 27 '12 at 13:55
  • 1
    @Jordan Please no. You better give an answer yourself explaining the errors you encountered and providing your own solution. You might pull out some rep and/or badges out of it. – NGLN Jan 27 '12 at 16:49

4 Answers4

16

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!

Mihai MATEI
  • 486
  • 8
  • 16
  • This was the answer that worked for me. The only catch that I found was if the checkbox field was the first column in the grid. In that case GridOriginalOptions does not get initialized. Easy fix, just add GridOriginalOptions := DBGrid1.Options to the Create method of the form. – WeststarEric Nov 19 '20 at 20:42
2

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!

Community
  • 1
  • 1
Dario Fumagalli
  • 1,064
  • 1
  • 16
  • 23
2

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).

Fabricio Araujo
  • 3,810
  • 3
  • 28
  • 43
-2

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.

Jordan Borisov
  • 1,603
  • 6
  • 34
  • 69
  • 1
    IMHO, This don't qualify for an answer, but an edit on main question. Maybe there you want to include some code to enlighten on how are you doing things ... – Fabricio Araujo Feb 02 '12 at 16:35