The automatic popping up of a context menu is a response to a right click of the mouse. The same click also fires the OnMouseUp
event. The VCL developers could either choose to fire the 'OnMouseUp' event before the popup is shown, or after. Apparently the latter is in effect, that is, the event is fired when the popup is closed (either by mouse or by the keyboard like pressing 'Esc').
There's no doubling of the event, when you press the left button to close the popup, you're firing the 'OnMouseUp' event again by releasing the left button.
You have several alternatives. One is to derive a new class and override the MouseDown
method to fire your own event. An example;
type
TMyStringGrid = class(TStringGrid)
private
FOnRButtonUp: TMouseEvent;
protected
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
published
property OnRButtonUp: TMouseEvent read FOnRButtonUp write FOnRButtonUp;
end;
[...]
procedure TStringGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
if (Button = mbRight) and Assigned(FOnRButtonUp) then
FOnRButtonUp(Self, Button, Shift, X, Y);
inherited;
end;
Another alternative can be to handle VM_RBUTTONUP
message. This can either be done by deriving a new class as above, or replacing the WindowProc
of the grid. There's an example of replacing the WindowProc here in this question.
Another alternative can be to leave the mouse-up event alone and do your processing in the OnPopup
event of the popup menu. This event is fired before the popup is shown. You can get the mouse coordinates with Mouse.CursorPos
.
Still, another alternative can be to set the AutoPopup
property of the popup menu to False
, and in the OnMouseUp
event (or better yet in the OnContextMenu
event) first do some processing and then show the popup. An example;
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Pt: TPoint;
begin
// Do processing
if Button = mbRight then begin
Pt := (Sender as TStringGrid).ClientToScreen(Point(X, Y));
PopupMenu1.Popup(Pt.X, Pt.Y);
end;
end;