在 Delphi 中将 TCheckBox 放入 TStringGrid 中

发布于 2024-10-21 16:43:45 字数 98 浏览 1 评论 0原文

我想在 Delphi 中的特定列的每个单元格中的 TStringGrid 中放置一个 TCheckBox 。我正在使用德尔福XE。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

才能让你更想念 2024-10-28 16:43:45

您应该绘制自己的复选框,最好使用视觉主题(如果启用)。这是如何执行此操作的简单草图:

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;

当然,在实际场景中,Checked 数组不是常量,您可能希望保存 s 指标和单元格绘制事件之间的 h 主题句柄。但原理就在这里。


这里缺少的是改变复选框状态的函数。您可能希望在 OnClick 处理程序中切换状态。如果您真的很认真,您还希望响应鼠标的运动,并在主题可用时在复选框上显示鼠标悬停效果。

bluish 编辑:要切换复选框状态此答案解释了如何使用无效 方法。

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.

萌能量女王 2024-10-28 16:43:45

不要尝试将实际的 TCheckBox 控件放置在 TStringGrid 内。使用网格的 OnDrawCell 事件和 Win32 API DrawFrameControl() 函数,根据需要在每个单元格内绘制 CheckBox 控件的图像。您可以将 OnClick/OnMouse... 事件与网格的 Objects[][] 属性结合使用,以根据需要跟踪每个单元格的选中状态。我发现这更容易管理,因为 TStringGrid 并不是为托管真正的控件而设计的。

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.

2024-10-28 16:43:45

我使用由 Roman Mochalov 编写的名为 ExGridView 的虚拟网格,它支持复选框。

我自己修改的 GridView 分支,针对 Unicode 等进行了移植,名为 TExGridView,而不是 TGridView,并且带有复选框演示,位于 bitbucket 此处为/wpostma/exgridview。

ExGridView 组件在属性检查器中有一个 Checkbox 属性,必须将其设置为 true,然后您必须设置 Column 属性,以便 Column 的复选框类型设置为复选框或单选按钮。然后您必须实现 GetCheckState 事件回调。请参阅 bitbucket 项目中包含的演示。

此代码的原始来源是此处,但它无法在最近的版本上构建版本。我的 bitbucket 版本已经过测试,可与 Delphi 2007、2009 以及截至 2016 年最新的所有版本(Delphi 10 西雅图)一起使用。

在此处输入图像描述

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文