Как выполнить мое пользовательское действие при щелчке правой кнопкой мыши на элементе управления TMemo?

В 32-разрядном приложении VCL Delphi 10.4.2 мне нужно выполнять разные действия, когда пользователь (левый или правый) щелкает элемент управления TMemo (который находится в режиме ReadOnly):

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 состоит из вызова определенного диалога.

Однако, когда я щелкаю правой кнопкой мыши элемент управления Memo, появляется собственное контекстное меню элемента управления TMemo, а DoAction2 не выполняется:

введите здесь описание изображения

Я попытался деактивировать контекстное меню элемента управления Memo, вызываемое правой кнопкой мыши, с помощью этого кода:

Memo1.OnContextPopup := nil;

Но это не работает: контекстное меню по-прежнему отображается при щелчке правой кнопкой мыши элемента управления Memo.

Итак, как я могу деактивировать собственное контекстное меню и выполнить свое действие при щелчке правой кнопкой мыши на элементе управления Memo?


person user1580348    schedule 18.05.2021    source источник
comment
Рассматривали ли вы возможность перемещения действия по щелчку левой кнопкой мыши на событие OnClick, а действия щелчка правой кнопкой мыши на событие OnContextPopup?   -  person Remy Lebeau    schedule 18.05.2021
comment
@RemyLebeau: Просто помните, что вы можете вызвать контекстное меню другими способами, кроме щелчка правой кнопкой мыши.   -  person Andreas Rejbrand    schedule 18.05.2021
comment
@RemyLebeau Вы правы: это была бы другая возможность. Но тогда я бы никогда не обнаружил двусмысленность типов (см. ниже).   -  person user1580348    schedule 18.05.2021


Ответы (1)


Это просто.

Ваш код Memo1.OnContextPopup := nil; не действует, поскольку свойство Memo1.OnContextPopup уже имеет значение nil, как вы можете видеть в Инспекторе объектов; то есть по умолчанию у вас нет специального обработчика.

Вам нужно добавить такой настраиваемый обработчик и установить для свойства Handled var значение True. Во время разработки используйте Инспектор объектов, чтобы создать обработчик OnContextPopup для вашей заметки со следующим кодом:

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

Теперь контекстное меню по умолчанию подавлено, и вы можете попробовать, например,

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;
person Andreas Rejbrand    schedule 18.05.2021
comment
К сожалению, здесь это не работает. - person user1580348; 18.05.2021
comment
Обработчик события OnMouseDown выполняется, но ни условия if Button = mbLeft, ни условия if Button = mbRight then не выполняются. - person user1580348; 18.05.2021
comment
@ user1580348: Сомневаюсь. Каково является значением Button? - person Andreas Rejbrand; 18.05.2021
comment
Ну, TMouseButton имеет только 3 определенных значения, поэтому, если это не mbLeft или mbRight, то это должно быть mbMiddle. - person Remy Lebeau; 18.05.2021
comment
@RemyLebeau: Если что-то пошло не так, это также может быть TMouseButton(152) или что-то еще ... Но я подозреваю, что здесь ошибка тестового примера; приведенный выше код работает в новом проекте VCL. - person Andreas Rejbrand; 18.05.2021
comment
@AndreasRejbrand все места в коде VCL, которые запускают события OnMouse..., жестко кодируют параметр Button, поэтому он никогда не должен быть чем-то другим, кроме 3 упомянутых значений. - person Remy Lebeau; 18.05.2021
comment
Я стал жертвой НЕОДНОЗНАЧНОСТИ ТИПА: мне пришлось переименовать тип TMouseButton в Vcl.Controls.TMouseButton, а тип mbRight в Vcl.Controls.mbRight. Теперь это работает. - person user1580348; 18.05.2021