当我执行 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
一团糟。
您可以使用 来解决问题。如果出于某种原因在任何时间段内第二次按下鼠标按钮,以下解决方案将失败。
正如问题评论中所建议的那样,发布自己收到的消息以延迟对话框的显示是行不通的,因为发布的消息比输入消息具有更高的优先级。有关详细信息,请参阅 GetMessage
的 documentation。
如果您遵循 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;
事件形式 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
一团糟。
您可以使用
正如问题评论中所建议的那样,发布自己收到的消息以延迟对话框的显示是行不通的,因为发布的消息比输入消息具有更高的优先级。有关详细信息,请参阅 GetMessage
的 documentation。
如果您遵循 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;