简体   繁体   English

将一个TCheckBox放在Delphi中的TStringGrid中

[英]Put a TCheckBox inside a TStringGrid in Delphi

I want to put a TCheckBox inside a TStringGrid in Delphi in every cell of certain column. 我想在特定列的每个单元格中将一个TCheckBox放在Delphi的TStringGrid中。 I'm using Delphi XE. 我正在使用Delphi XE。

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. 当然,在实际场景中, Checked数组不是常量,您可能希望在单元格绘制事件之间保存s度量和h主题句柄。 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. 您可能希望在OnClick处理程序中切换状态。 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. EDIT by bluish: 要切换复选框状态此答案解释了如何使用Invalidate方法。

Don't try to place an actual TCheckBox control inside a TStringGrid . 不要尝试将实际的TCheckBox控件放在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. 使用网格的OnDrawCell事件和Win32 API DrawFrameControl()函数,根据需要在每个单元格内绘制CheckBox控件的图像。 You can use the OnClick/OnMouse... events with the grid's Objects[][] property to keep track of each cell's checked state as needed. 您可以将OnClick/OnMouse...事件与网格的Objects[][]属性一起使用,以根据需要跟踪每个单元格的已检查状态。 I find this is a lot easier to manage, since TStringGrid was not designed to host real controls. 我发现这很容易管理,因为TStringGrid不是为托管实际控件而设计的。

I use a virtual grid called ExGridView by Roman Mochalov, that supports checkboxes. 我使用Roman Mochalov称为ExGridView的虚拟网格,它支持复选框。

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. 我自己修改的GridView的分支,移植到Unicode等,名为TExGridView,而不是TGridView,并带有复选框演示在bitbucket 这里作为/ 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. ExGridView组件在属性检查器中具有Checkbox属性,必须将其设置为true,然后必须设置Column属性,以便Column的复选框类型设置为复选框或单选按钮。 Then you must implement the GetCheckState event callback. 然后,您必须实现GetCheckState事件回调。 See the demo included on the bitbucket project. 请参阅bitbucket项目中包含的演示。

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). 我的bitbucket版本经过测试并与Delphi 2007,2009一起使用,所有版本都是截至2016年(Delphi 10 Seattle)。

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM