The OS posts a WM_LBUTTONDBLCLK
on the second down of the left mouse button. When you execute a ShowModal
call here, the application does not get the chance to process the, yet to be posted, WM_LBUTTONUP
message until after your dialog is shown. Since TDBGrid
fires the OnCellClick
event while the control is handling a WM_LBUTTONUP
message and the message happens to be posted to the grid since the modal form is the active window now, you encounter the problem.
The behavior of the grid is kind of documented;
Occurs when the user releases the mouse in one of the cells of the
grid.
although it could be argued that it should've mention that you don't even have to press the mouse button...
This is an unfortunate design decision, this is not how a click works. Think of pressing the button on one cell and releasing on another. No OnCellClick
should be fired. Current behavior is rather confusing, the event fires for the cell you pressed the button on - provided you release the button on a valid cell and not on empty space.
As you have found out, you can even fire the event by pressing the button on a different form and releasing it on a cell of the grid on this form. In this case the event fires for the currently selected cell and mouse position does not play any role in it at all. My opinion is that OnCellClick
is a total mess.
You can use kobik's answer for a solution. Below solution fails if for some reason mouse button is held down on the second press for any time period.
Posting a self received message to delay the showing of the dialog, as suggested in the comments to the question, does not work because posted messages have higher priority then input messages. See documentation for GetMessage
for more detail.
If you follow the link, you'll notice the timer approach, also as suggested in the comments to the question, will work. Unlike the comment suggests the timing interval does not matter since the WM_TIMER
message have the lowest priority. And this is a good thing which makes it a fail-safe approach.
I wanted to put the timer on the modal dialog as it owns the problem control.
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;
WM_LBUTTONUP.
Whereas aWM_LBUTTONDBLCLK
is posted in the second button down. I've seen several times handling a mouse up is suggested to implement a click. A click is different, it's down/capture/up. This is a VCL design error. – Draper