1

In a Delphi 10.4.2 32-bit VCL Application, I need to do different actions when the user (left- or right-)clicks on a TMemo control (which is in ReadOnly mode):

procedure TForm1.Memo1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
    DoAction1
  else if Button = mbRight then
    DoAction2;
end;

DoAction2 consists of invoking a specific dialog.

However, when I right-click on the Memo control, the native context menu of the TMemo control shows up, and DoAction2 is not executed:

enter image description here

I have tried to deactivate the right-click context menu of the Memo control with this code:

Memo1.OnContextPopup := nil;

But it does not work: The context menu still shows up when right-clicking the Memo control.

So how can I deactivate the native context menu and execute my action when right-clicking on the Memo control?

user1580348
  • 5,721
  • 4
  • 43
  • 105
  • Have you considered moving your left-click action to the `OnClick` event, and your right-click action to the `OnContextPopup` event? – Remy Lebeau May 18 '21 at 19:28
  • @RemyLebeau: Just remember that you can invoke the context menu by other means than right-clicking. – Andreas Rejbrand May 18 '21 at 19:30
  • @RemyLebeau You are right: that would have been another possibility. But then I would have never discovered the type ambiguity (see below). – user1580348 May 18 '21 at 19:49

1 Answers1

4

This is easy.

Your code Memo1.OnContextPopup := nil; has no effect because the Memo1.OnContextPopup property already is nil, as you can see in the Object Inspector; that is, by default you have no custom handler.

What you need to do is to add such a custom handler and set the Handled var property to True. At design time, use the Object Inspector to create an OnContextPopup handler for your memo, with the following code:

procedure TForm1.Memo1ContextPopup(Sender: TObject; MousePos: TPoint;
  var Handled: Boolean);
begin
  Handled := True;
end;

Now the default context menu is suppressed and you can try, for example,

procedure TForm1.Memo1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
    Winapi.Windows.Beep(300, 250)
  else if Button = mbRight then
    Winapi.Windows.Beep(300, 1000);
end;
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • The `OnMouseDown` event-handler is executed, but neither `if Button = mbLeft` nor `if Button = mbRight then` conditions are met. – user1580348 May 18 '21 at 19:21
  • 1
    @user1580348: I doubt that. What *is* the value of `Button`? – Andreas Rejbrand May 18 '21 at 19:25
  • Well, `TMouseButton` only has 3 values defined, so if it is not `mbLeft` or `mbRight` then it must be `mbMiddle`. – Remy Lebeau May 18 '21 at 19:26
  • @RemyLebeau: If something has gone wrong, it can also be `TMouseButton(152)` or anything... But I suspect there is a test-case error here; the code above works in a new VCL project. – Andreas Rejbrand May 18 '21 at 19:28
  • @AndreasRejbrand all of the places in the VCL's code that trigger the `OnMouse...` events are hard-coding the `Button` parameter, so it should never be something other than then 3 values mentioned. – Remy Lebeau May 18 '21 at 19:31
  • 1
    I have been the victim of a TYPE AMBIGUITY: I had to rename the type `TMouseButton` to `Vcl.Controls.TMouseButton`, and the type `mbRight` to `Vcl.Controls.mbRight`. Now it works. – user1580348 May 18 '21 at 19:32