DBGrid中的复选框

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

12
你好,你尝试过按照这个教程(this)的步骤进行操作吗?教程链接为:http://delphi.about.com/od/usedbvcl/l/aa082003a.htm - TLama
2
@TLama,如果您将您的评论发布为答案,我会投赞成票。 - PA.
2
@TLama,完美的链接(而且很明智没有将其作为答案)。PA,只有一个外部链接(或者如果外部链接无效则毫无意义的内容)的答案在这里是不可接受的。答案应该是独立的,并且在没有任何其他内容的情况下仍然有用。TLama做出了完美的决定。只有外部链接的答案通常会被标记并很快被删除。 - Ken White
是的,我找到了这个链接并尝试进行实现。但是出现了一些小错误,因此我改变了源代码中的逻辑。不过,提前感谢你的帮助。你应该将它发布为一个答案,我会把它设置为正确答案。 - Jordan Borisov
1
@Jordan,请不要这样做。最好自己回答,解释你遇到的错误并提供自己的解决方案。这样你可能会获得一些声望和/或徽章。 - NGLN
4个回答

16

根据我的测试,最简单和最完整的方法如下:

在您单位的私有部分中,声明一个全局变量来保留网格选项。这将用于在输入复选框列时临时禁用文本编辑,然后进行还原 - 因为这可能是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不会被初始化。简单的解决方法是,在表单的Create方法中添加GridOriginalOptions:= DBGrid1.Options。 - WeststarEric

2

如果您正在使用TClientDataset+TDatasetProvider+TDataset,您可以在数据数组变体到达clientdataset之前操纵它,并包括一个不可更新的布尔字段。

一旦完成,您只需要使用OnDrawColumnCell事件在网格上绘制即可。在这里,我没有使用复选框,而是使用位图(当用户单击时更改为已选择/未选择)。


2
请原谅我将此作为答案发布,我还没有50点声望来添加评论。 Mihai MATEI的答案非常接近罕见(真正有效)的解决方案,但有一个使用情况会出现错误。
每当用户在网格上的第一次操作是单击复选框时,第一次单击将起作用,但第二次将会显示底层的DBGrid编辑器。
这是因为“GridOriginalOptionsmechan”机制需要初始化。 要这样做,请在网格的OnEnter事件中添加以下代码:
procedure TForm1.DBGrid1Enter(Sender: TObject);
begin
  DBGrid1ColEnter(Sender);
end;

就是这样!


-2

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


1
在我看来,这不足以作为一个答案,而应该是主题问题的修改。也许你想在那里加入一些代码,以阐明你的操作方式... - Fabricio Araujo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接