Put a TCheckBox inside a TStringGrid in Delphi

24,646

Solution 1

You should draw your own checkboxes, preferably using visual themes, if enabled. This is a simple sketch of how to do that:

const
  Checked: array[1..4] of boolean = (false, true, false, true);

procedure TForm4.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
const
  PADDING = 4;
var
  h: HTHEME;
  s: TSize;
  r: TRect;
begin
  if (ACol = 2) and (ARow >= 1) then
  begin
    FillRect(StringGrid1.Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH));
    s.cx := GetSystemMetrics(SM_CXMENUCHECK);
    s.cy := GetSystemMetrics(SM_CYMENUCHECK);
    if UseThemes then
    begin
      h := OpenThemeData(StringGrid1.Handle, 'BUTTON');
      if h <> 0 then
        try
          GetThemePartSize(h,
            StringGrid1.Canvas.Handle,
            BP_CHECKBOX,
            CBS_CHECKEDNORMAL,
            nil,
            TS_DRAW,
            s);
          r.Top := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
          r.Bottom := r.Top + s.cy;
          r.Left := Rect.Left + PADDING;
          r.Right := r.Left + s.cx;
          DrawThemeBackground(h,
            StringGrid1.Canvas.Handle,
            BP_CHECKBOX,
            IfThen(Checked[ARow], CBS_CHECKEDNORMAL, CBS_UNCHECKEDNORMAL),
            r,
            nil);
        finally
          CloseThemeData(h);
        end;
    end
    else
    begin
      r.Top := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
      r.Bottom := r.Top + s.cy;
      r.Left := Rect.Left + PADDING;
      r.Right := r.Left + s.cx;
      DrawFrameControl(StringGrid1.Canvas.Handle,
        r,
        DFC_BUTTON,
        IfThen(Checked[ARow], DFCS_CHECKED, DFCS_BUTTONCHECK));
    end;
    r := Classes.Rect(r.Right + PADDING, Rect.Top, Rect.Right, Rect.Bottom);
    DrawText(StringGrid1.Canvas.Handle,
      StringGrid1.Cells[ACol, ARow],
      length(StringGrid1.Cells[ACol, ARow]),
      r,
      DT_SINGLELINE or DT_VCENTER or DT_LEFT or DT_END_ELLIPSIS);
  end;
end;

Of course, in a real scenario, the Checked array is not a constant, and you might wish to save the s metrics and h theme handle between cell painting events. But the principle is here.

What is missing here is a function to alter the state of the checkboxes. You will probably want to toggle the state in an OnClick handler. If you are really serious, you'll also wish to respond to the motion of the mouse, and display the mouse hover effect on the checkboxes if themes are available.

EDIT by bluish: To toggle checkbox state, this answer explains how you can use Invalidate method.

Solution 2

Don't try to place an actual TCheckBox control inside a TStringGrid. Use the grid's OnDrawCell event with the Win32 API DrawFrameControl() function instead, to draw an image of a CheckBox control inside each cell as needed. You can use the OnClick/OnMouse... events with the grid's Objects[][] property to keep track of each cell's checked state as needed. I find this is a lot easier to manage, since TStringGrid was not designed to host real controls.

Solution 3

I use a virtual grid called ExGridView by Roman Mochalov, that supports checkboxes.

My own modified fork of GridView, ported for Unicode etc, named TExGridView, instead of TGridView, and with a demo of checkboxes is on bitbucket here as /wpostma/exgridview.

The ExGridView component has a Checkbox property in the property inspector which must be set true, Then you must set up your Column properties so that the Column has a checkbox type set to checkbox or radio button. Then you must implement the GetCheckState event callback. See the demo included on the bitbucket project.

The original source for this code was here but it's not buildable on recent versions. My bitbucket version is tested and working with Delphi 2007, 2009, and all versions up to date as of 2016 (Delphi 10 Seattle).

enter image description here

Share:
24,646

Related videos on Youtube

alexzm1
Author by

alexzm1

Updated on July 31, 2020

Comments

  • alexzm1
    alexzm1 over 3 years

    I want to put a TCheckBox inside a TStringGrid in Delphi in every cell of certain column. I'm using Delphi XE.

  • Warren  P
    Warren P about 13 years
    Andreas would you mind if I borrowed that code and put it into the JVCL String Grid? It would be a nice addition.
  • Andreas Rejbrand
    Andreas Rejbrand about 13 years
    @Warren P: Feel free to use the code as you wish. @Ken: Sorry, couldn't resist!
  • alexzm1
    alexzm1 about 13 years
    How could i add the CheckBox on a GridView from the ExGridView of Roman Mochalov???
  • alexzm1
    alexzm1 about 13 years
    thanks, it works, and it will be good to have this on the JVCL Grid
  • Zeina
    Zeina about 12 years
    @WarrenP I work with the TMS AdvStringGrid, but does it support the Grayed state of its checkboxes (I don't think so)? how can i manage my own gray checkbox? can i color it by some way?
  • Zeina
    Zeina about 12 years
    @AndreasRejbrand if we want to manage out own onclick, does it mean we want to repeat this procedure, or what? how can we check the status of the drawn theme? give me a hint please.
  • Warren  P
    Warren P almost 10 years
    Why not ask TMS? They support their stuff very well.
  • Michael Riley - AKA Gunny
    Michael Riley - AKA Gunny about 8 years
    @AndreasRejbrand Thank you for this awesome solution. ∞+1

Related