为什么不一个TStringGrid的子控件正常工作?(Why don't child con

2019-06-26 15:33发布

我把复选框( TCheckBox字符串中的网格() TStringGrid )在第一列。 该复选框显示细腻,正确定位,并且将鼠标悬停在当发光响应鼠标。 当我点击他们,但他们不切换。 他们反应了一下,并强调,但最后,实际的Checked属性不会改变。 是什么使得它更令人费解的是,我没有任何代码改变这些值,一旦他们在那里,也没有我甚至有一个OnClick分配给这些复选框事件。 另外,我也默认这些复选框是选中的,但显示的时候,他们被检查

复选框与被添加到列表中的每个记录一起创建,且记录指针被分配给该对象在该复选框被放置在细胞内被引用。

串格入侵细胞高亮:

type
  THackStringGrid = class(TStringGrid); //used later...

含复选框实录:

  PImageLink = ^TImageLink;
  TImageLink = record
    ...other stuff...
    Checkbox: TCheckbox;
    ShowCheckbox: Bool;
  end;

复选框的创建/销毁:

function NewImageLink(const AFilename: String): PImageLink;
begin
  Result:= New(PImageLink);
  ...other stuff...
  Result.Checkbox:= TCheckbox.Create(nil);
  Result.Checkbox.Caption:= '';
end;

procedure DestroyImageLink(AImageLink: PImageLink);
begin
  AImageLink.Checkbox.Free;
  Dispose(AImageLink);
end;

将行添加到网格:

//...after clearing grid...
//L = TStringList of original filenames
if L.Count > 0 then
  lstFiles.RowCount:= L.Count + 1
else
  lstFiles.RowCount:= 2; //in case there are no records
for X := 0 to L.Count - 1 do begin
  S:= L[X];
  Link:= NewImageLink(S); //also creates checkbox
  Link.Checkbox.Parent:= lstFiles;
  Link.Checkbox.Visible:= Link.ShowCheckbox;
  Link.Checkbox.Checked:= False;
  Link.Checkbox.BringToFront;
  lstFiles.Objects[0,X+1]:= Pointer(Link);
  lstFiles.Cells[1, X+1]:= S;
end;

Grid的OnDrawCell事件处理程序:

procedure TfrmMain.lstFilesDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  Link: PImageLink;
  CR: TRect;
begin
  if (ARow > 0) and (ACol = 0) then begin
    Link:= PImageLink(lstFiles.Objects[0,ARow]); //Get record pointer
    CR:= lstFiles.CellRect(0, ARow); //Get cell rect
    Link.Checkbox.Width:= Link.Checkbox.Height;
    Link.Checkbox.Left:= CR.Left + (CR.Width div 2) - (Link.Checkbox.Width div 2);
    Link.Checkbox.Top:= CR.Top;
    if not Link.Checkbox.Visible then begin
      lstFiles.Canvas.Brush.Color:= lstFiles.Color;
      lstFiles.Canvas.Brush.Style:= bsSolid;
      lstFiles.Canvas.Pen.Style:= psClear;
      lstFiles.Canvas.FillRect(CR);
      if lstFiles.Row = ARow then
        THackStringGrid(lstFiles).DrawCellHighlight(CR, State, ACol, ARow);
    end;
  end;
end;

这里的点击,当它看起来如何?

可能是什么造成的? 这绝对不是改变Checked我的代码的任何财产。 有一些奇怪的行为从复选框来自己放置在一个网格时。

编辑

我做了一个简单的测试,我把一个普通TCheckBox形式。 检查/取消选中罚款。 然后,在我的窗体的OnShow的事件,我改变了复选框的Parent到这个网格。 这一次,我得到了相同的行为,点击后不反复。 因此,它似乎是一个TCheckBox当它有另一个控件作为其父不作出适当的反应。 如何克服呢?

Answer 1:

TStringGridWMCommand处理程序不允许孩子控制来处理消息(除InplaceEdit)。

所以,你可以使用如插入的类(基于由Peter下面的代码 )或用手绘制控件,有些人劝。 这里是插入类的代码:

uses
  Grids;

type
  TStringGrid = class(Grids.TStringGrid)
  private
    procedure WMCommand(var AMessage: TWMCommand); message WM_COMMAND;
  end;

implementation

procedure TStringGrid.WMCommand(var AMessage: TWMCommand);
begin
  if EditorMode and (AMessage.Ctl = InplaceEditor.Handle) then
    inherited
  else
  if AMessage.Ctl <> 0 then
  begin
    AMessage.Result := SendMessage(AMessage.Ctl, CN_COMMAND,
      TMessage(AMessage).WParam, TMessage(AMessage).LParam);
  end;
end;


Answer 2:

在Delphi7的至少我这样做:

您需要绘制细胞上的复选框,并与布尔数组保持同步(这里fChecked[]表示各行中的复选框的状态。 然后,在DrawCell中的一部分TStringGrid

var
 cbstate: integer;
begin
...
if fChecked[Arow] then cbState:=DFCS_CHECKED else cbState:=DFCS_BUTTONCHECK;
DrawFrameControl(StringGrid.canvas.handle, Rect, DFC_BUTTON, cbState);
...
end;

为了获得该复选框以应对空栏,使用KeyDown事件,并强制重绘:

if (Key = VK_SPACE) And (col=ColWithCheckBox) then begin
  fChecked[row]:=not fChecked[row];
  StringGrid.Invalidate;
  key:=0;
end;

需要使用类似的方法OnClick方法。



Answer 3:

  1. ü可以使用VirtualTreeView在toReportMode(TListView的争相模仿)模式,而不是网格?

  2. ü可以使用TDBGrid中过一些在内存中的表像NexusDB或的TClientdataSet?

  3. 丑陋的办法将提交复选框,就像一个自定义字体的字母-像绕组或http://fortawesome.github.com/Font-Awesome

后者是最容易实现的,但也是最丑陋看,最不灵活的维护-业务逻辑被混合到VCL事件处理程序



文章来源: Why don't child controls of a TStringGrid work properly?