当我执行 OnDblClick 事件 (Form1) 以打开 Form2 时,它会触发 Form2 的 OnCellClick 事件,而无需单击 form2 网格

When I perform the OnDblClick event (Form1) to open Form2, it fires the OnCellClick event of Form2, without having clicked on the form2 grid

事件形式 1:

procedure TForm1.Panel1DblClick(Sender: TObject);
begin
  TForm2.Create(Self).ShowModal;
end;

事件形式 2:

procedure TForm2.DBGrid1CellClick(Column: TColumn);
begin
  ShowMessage('Test');
end;

我应该怎么做才能避免 fom2 的 onCellClick 事件?

OS 在第二次按下鼠标左键时发布 WM_LBUTTONDBLCLK。当您在此处执行 ShowModal 调用时,在您的对话框显示之前,应用程序没有机会处理尚未发布的 WM_LBUTTONUP 消息。由于 TDBGrid 在控件处理 WM_LBUTTONUP 消息时触发 OnCellClick 事件,并且消息恰好发布到网格,因为模态形式现在处于活动状态 window,你遇到问题了。

网格的行为有点像 documented;

Occurs when the user releases the mouse in one of the cells of the grid.

尽管有人争论说它应该提到您甚至不必按下鼠标按钮...

这是一个不幸的设计决定,这不是点击的工作方式。想想按下一个单元格上的按钮并在另一个单元格上释放。不应解雇 OnCellClick。当前的行为相当令人困惑,事件会针对您按下按钮的单元格触发 - 前提是您在有效单元格而不是空 space 上释放按钮。

正如您所发现的,您甚至可以通过按下不同窗体上的按钮并在此窗体上的网格单元格上释放按钮来触发事件。在这种情况下,事件针对当前选定的单元格触发,鼠标位置在其中根本没有任何作用。我的意见是 OnCellClick 一团糟。



您可以使用 来解决问题。如果出于某种原因在任何时间段内第二次按下鼠标按钮,以下解决方案将失败。


正如问题评论中所建议的那样,发布自己收到的消息以延迟对话框的显示是行不通的,因为发布的消息比输入消息具有更高的优先级。有关详细信息,请参阅 GetMessagedocumentation

如果您遵循 link,您会注意到计时器方法(也如问题评论中所建议的那样)会起作用。与评论不同,时间间隔无关紧要,因为 WM_TIMER 消息的优先级最低。这是一件好事,它使它成为一种故障安全方法。

我想将计时器放在模态对话框上,因为它拥有问题控件。

procedure TForm2.FormCreate(Sender: TObject);
begin
  DBGrid1.Enabled := False;
  Timer1.Interval := 1;
  Timer1.Enabled := True;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  DBGrid1.Enabled := True;
  Timer1.Enabled := False;
end;

@Sertac 对这种行为给出了很好的解释。

我将尝试通过为 TDBGrid 创建一个插入器 class 来提供另一个修复,例如:

type
  TDBGrid = class(DBGrids.TDBGrid)
  protected
    FDown: Boolean;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
  end;

  TForm2 = class(TForm)
    ...
    DBGrid1: TDBGrid;
    ...
  end;

implementation

procedure TDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  FDown := True;
  try
    inherited;
  except
    FDown := False;
    raise;
  end;
end;

procedure TDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if FDown then
  try
    inherited;
  finally
    FDown := False;
  end;
end;

FDown 标志仅表示 MouseUp 必须 仅在 MouseDown 消息之后。
从我的快速测试中,我没有注意到任何影响。但是可能会。

您是否尝试过在 DblClick 处理程序中执行 Application.ProcessMessages()

procedure TForm1.Panel1DblClick(Sender: TObject);
begin
  Application.ProcessMessages;
  TForm2.Create(Self).ShowModal;
end;