Jump to content
JohnLM

Add a Checkbox column to a DBGrid?

Recommended Posts

Posted (edited)

Specs:  Delphi XE7, VCL, Windows 7 - DBGrid and added a checkbox column to it

 

I've searched around the web for ideas and howtos.  Well, I came across a few resources and met with some success.  I've even added/included an additional feature to allow user (that's me) to add edit checkbox via keyboard space.  It works. 

 

https://www.thoughtco.com/place-a-checkbox-into-dbgrid-4077440

 

https://stackoverflow.com/questions/9019819/checkbox-in-a-dbgrid

 

I copy/pasted the code from the second link, then I added the code to allow checkbox column updates via the keyboard space (spacebar) from the first link, and ported to the code from the second link. I hope that made sense.  <-- My first "codesnippet" contribution to the community !!

 

However, there appears to be one small problem.  The checkbox column is showing the text:  True or False, whichever is set to., and you can see the outline of the column box when that field is entered into. 

 

Complete source code is included below.  Just add a (dbgrid, button, tfdmemtable, and datasource) to your forum, and be sure to double-click the event(s) for each of these Procedures in order to activate them.  You can click the ch field or hit the spacebar to update the checkbox field. 

 

Is there any way I can resolve this artifact?

 

1808772717_im-delphi-gridandcheckboxartifact.png.1d6ac817b95b50566eb56f2b04a9d90f.png

 

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf,
  FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async,
  FireDAC.Phys, FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef,
  FireDAC.Stan.ExprFuncs, Data.DB, FireDAC.Comp.Client, Vcl.Grids, Vcl.DBGrids,
  FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt,
  FireDAC.Comp.DataSet, FireDAC.VCLUI.Wait, FireDAC.Comp.UI;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    eb1: TEdit;
    conn: TFDConnection;
    btnInsert: TButton;
    DBGrid1: TDBGrid;
    ds: TDataSource;
    mytable: TFDMemTable;
    procedure Button1Click(Sender: TObject);
    procedure btnInsertClick(Sender: TObject);
    procedure dbgrid1CellClick(Column: TColumn);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure DBGrid1ColEnter(Sender: TObject);
    procedure DBGrid1ColExit(Sender: TObject);
    procedure DBGrid1KeyDown(Sender: TObject; var Key: Word;  Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
    procedure DBGrid1KeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
    GridOriginalOptions : TDBGridOptions;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnInsertClick(Sender: TObject);
begin
    myTable.FieldDefs.Clear;

    mytable.FieldDefs.Add('ch',  ftBoolean, 0,false);  // the checkbox 'ch' a boolean
    myTable.FieldDefs.Add('id',  ftAutoInc,  0,False);
    myTable.FieldDefs.Add('name',ftString,  20,False);
    myTable.CreateDataSet;

    myTable.Append;
    myTable.FieldByName('name').AsString := 'delphi';
    myTable.Post;
    mytable.Open;
end;

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;

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

// this portion of code snippet is my contribution to the community. I did not see this code anywhere. it does work. 
procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if (key = ' ') then begin
    self.DBGrid1.DataSource.DataSet.Edit;
    self.DBGrid1.SelectedField.Value := not self.DBGrid1.Fields[0].AsBoolean;
    self.DBGrid1.DataSource.DataSet.Post;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  GridOriginalOptions := DBGrid1.Options
end;

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
  if Self.DBGrid1.SelectedField.DataType = ftBoolean then
    Self.DBGrid1.Options := Self.GridOriginalOptions;
end;
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;

end.

 

 

Edited by JohnLM
edited word

Share this post


Link to post

Make sure that the DefaultDrawing property of the grid is False and add a DefaultDrawColumnCell(Rect, DataCol, Column, State); call in your OnDrawColumnCell event handler for the non-boolean field case:

 

Share this post


Link to post

setting DefaultDrawing property to False does help, but the second part causes additional artifacts and also does not show the cursor. 

 

I did try adding it into the section you mentioned but it gave me artifacts or missing data, etc.. 

 

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.DefaultDrawColumnCell(Rect, DataCol, Column, State);
    DBGrid1.Canvas.FillRect(Rect) ;

    if (VarIsNull(Column.Field.Value)) then //begin
      DrawFrameControl(DBGrid1.Canvas.Handle,Rect, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_INACTIVE)
      //dbgrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State); end
    else //begin
      DrawFrameControl(DBGrid1.Canvas.Handle,Rect, DFC_BUTTON, CtrlState[Column.Field.AsBoolean]);
      //dbgrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);end;
  end;
end;

 

Share this post


Link to post
Posted (edited)

You somehow misread my advice. The DefaultDrawColumnCell call should be in the non-boolean case, where all non-boolean fields are handled:

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
  else
    DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;

 

Edited by Uwe Raabe
  • Thanks 1

Share this post


Link to post
Posted (edited)

The artifact in the boolean checkbox column is now gone.

 

Thank you @Uwe Raabe for the help,  much appreciated. 

 

Edited by JohnLM

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×