DBGrid 中的复选框

Posted

技术标签:

【中文标题】DBGrid 中的复选框【英文标题】:CheckBox in a DBGrid 【发布时间】:2012-01-26 14:43:36 【问题描述】:

我的问题是如何在 Delphi 7 的 dbgrid 中设置一个带有复选框项的列。

提前致谢。

【问题讨论】:

您好,您是否尝试过关注例如this教程? @TLama,如果您发表评论作为答案,我会投赞成票。 @TLama,完美的链接(不让它成为答案的好选择)。 PA,指向没有其他内容的外部站点的链接(或者如果外部链接不起作用,则内容将毫无意义)在这里不是可接受的答案。答案应该是独立的,并且在没有任何其他内容的情况下仍然有用。 TLama 做了一个完美的决定。仅外部链接的答案通常会很快被标记和删除。 是的,我找到了这个链接并尝试实现它。但是有一个更小的错误。所以我在源代码中改变了我的逻辑。但提前谢谢。您应该将其发布为答案,我将其设置为答案。 @Jordan 请不要。您最好自己给出答案,解释您遇到的错误并提供自己的解决方案。您可能会从中提取一些代表和/或徽章。 【参考方案1】:

我测试过的最简单最完整的方法如下:

在你的单元的私有部分,声明一个用于保留网格选项的全局。它将用于在进入复选框列时临时禁用文本编辑后恢复 - 因为这可能是 Jordan Borisovin 提到的关于 delphi.about.com 文章的小错误之一

private      
  GridOriginalOptions : TDBGridOptions;

在 OnCellClick 事件中,如果字段为布尔值,则切换并将更改发布到数据库

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;

为网格的布尔字段绘制复选框

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;

现在是新部分,在布尔列中禁用单元格编辑。关于 OnColEnter 和 OnColExit 事件:

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;

更重要的是,处理用于切换复选框的空格键

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;

就是这样!

【讨论】:

这是对我有用的答案。我发现的唯一问题是复选框字段是否是网格中的第一列。在这种情况下,GridOriginalOptions 不会被初始化。轻松修复,只需将 GridOriginalOptions := DBGrid1.Options 添加到表单的 Create 方法即可。【参考方案2】:

如果您使用的是 TClientDataset+TDatasetProvider+TDataset,您可以在数据数组变体到达客户端数据集之前对其进行操作,并包含一个不可更新的布尔字段。

完成后,您只需使用 OnDrawColumnCell 事件在网格上绘图。在这里,我没有使用 CheckBox,而只是使用位图(当用户单击它时,它会变为选中/未选中)。

【讨论】:

【参考方案3】:

请原谅我将此作为答案发布,我还没有 50 声望来添加 cmets。

Mihai MATEI 的答案非常接近罕见的(如在实际工作中)解决方案,除了它出现错误的用例。

当用户在网格上的第一个操作是单击复选框时,第一次单击将起作用,但第二次将显示底层 DBGrid 编辑器。

发生这种情况是因为需要初始化“GridOriginalOptionsmechan”机制。 为此,只需在网格的 OnEnter 事件中添加以下代码:

procedure TForm1.DBGrid1Enter(Sender: TObject);
begin
  DBGrid1ColEnter(Sender);
end;

就是这样!

【讨论】:

【参考方案4】:

好的 我用this 文章解决了我的问题。好的,但问题是它没有按应有的方式工作。所以我在代码中改变了我的逻辑。并通过将 dbgrid 中选定的行保存在列表中来实现它。

【讨论】:

恕我直言,这没有资格获得答案,而是对主要问题的编辑。也许您想在其中包含一些代码来启发您如何做事......

以上是关于DBGrid 中的复选框的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 TDBGrid 中的复选框来选择多条记录?

jquery easyui如何获取被选中的checkbox的id然后将其页面包括数据库数据删除,我的前台页面是这样写的

检查复选框数组中的复选框是不是被选中

Extjs-3.4 复选框组指定列中的复选框

使用c#一键检查复选框列表中的所有复选框

表单中的复选框验证