Пользовательский компонент delphi с элементом всплывающего меню по умолчанию

Я использую пользовательский компонент списка, и мне нужно, чтобы в нем был элемент всплывающего меню «копировать данные в буфер обмена». Если нет назначенного всплывающего окна, я создаю его и добавляю элемент меню, если уже назначено меню, добавляю элемент в текущее всплывающее окно. Пытался поместить код в конструктор, но потом понял, что всплывающее меню все еще не создано и не связано с моим списком. Итак, есть идеи, когда создать элемент по умолчанию?

constructor TMyListView.Create(AOwner: TComponent);
var
  FpopupMenu: TPopupMenu;
begin
  inherited;
  .....
  FPopUpMenuItem := TMenuItem.Create(self);
  FPopUpMenuItem.Caption := 'Copy data to clipboard';
  FPopUpMenuItem.OnClick := PopupMenuItemClick;
  if assigned(PopupMenu) then begin
    popupMenu.Items.Add(FPopUpMenuItem);
  end
  else begin
    FpopupMenu := TPopupMenu.Create(self);
    FpopupMenu.Items.Add(FPopUpMenuItem);
    PopupMenu := FpopupMenu;
  end;
...
end;

Что вы делаете, когда PopupMenu уже содержит «Копировать данные в буфер обмена»-TMenuItem?

Delphi Coder 16.04.2019 14:42

Не могу воспроизвести. Рассмотрим минимальный воспроизводимый пример. Какая версия Делфи?

J... 16.04.2019 15:01

Что, если разработчик назначает всплывающее окно во время выполнения? Что вам нужно сделать, так это предоставить доступный метод и оставить остальное пользователю компонента.

Sertac Akyuz 16.04.2019 15:08

Я разработчик. Пользователи хотят иметь возможность копировать/вставлять выбранные данные из любого списка в существующем программном обеспечении с более чем 100 экземплярами. Поэтому я подумал добавить «фиксированный» элемент в меню. Кажется, нет способа сделать это, поскольку я не получаю уведомления, если всплывающее окно назначено моему списку. Также нельзя переопределить TControl.SetPopupMenu, он частный и не виртуальный.

Kiril Hadjiev 16.04.2019 15:26

Работайте во время выполнения, обрабатывайте wm_contextmenu, смотрите, прикреплено ли всплывающее окно, если оно прикреплено, смотрите, добавлено ли уже «копировать данные ...», в противном случае добавьте его. Создайте всплывающее окно, если оно не прикреплено.

Sertac Akyuz 16.04.2019 15:35

Вместо того, чтобы обрабатывать WM_CONTEXTMENU напрямую, переопределите виртуальный метод TControl.DoContextPopup() или даже метод TControl.GetPopupMenu().

Remy Lebeau 16.04.2019 18:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
609
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Переопределите виртуальный метод TControl.DoContextPopup(), например:

type
  TMyListView = class(TListView)
  protected
    ...
    procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
    ...
  end;

procedure TMyListView.DoContextPopup(MousePos: TPoint; var Handled: Boolean);
var
  LPopupMenu: TPopupMenu;
  LItem: TMenuItem;

  function IsSameEvent(const E1, E2: TNotifyEvent): Boolean;
  begin
    Result := (TMethod(E1).Code = TMethod(E2).Code) and
              (TMethod(E1).Data = TMethod(E2).Data);
  end;

begin
  inherited DoContextPopup(MousePos, Handled);
  if Handled then Exit;

  LPopupMenu := PopupMenu;
  if not Assigned(LPopupMenu) then
  begin
    LPopupMenu := TPopupMenu.Create(Self);
    PopupMenu := LPopupMenu;
  end;

  for I := 0 to LPopupMenu.Items.Count-1 do
  begin
    LItem := LPopupMenu.Items[I];
    if IsSameEvent(LItem.OnClick, PopupMenuItemClick) then
      Exit;
  end;

  LItem := TMenuItem.Create(Self);
  LItem.Caption := 'Copy data to clipboard';
  LItem.OnClick := PopupMenuItemClick;
  LPopupMenu.Items.Add(LItem);
end;

Работает идеально и применимо к любому элементу управления. Большое спасибо, Реми!

Kiril Hadjiev 18.04.2019 13:38

Принятый ответ действительно работает отлично, если вы не добавите сочетания клавиш в свой пункт меню. Если вы это сделаете, они не будут работать до тех пор, пока всплывающее меню не будет открыто каким-либо другим способом, потому что элементы не будут созданы. Если вам нужны ярлыки, поэтому может быть предпочтительнее переместить код из DoContextPopup в Loaded. Проще всего,

procedure Loaded; override;
...
procedure Loaded; 
var 
  MI: TMenuItem;
  ItemCovered: boolean;
  i: integer;
begin
  inherited;
  if not Assigned(PopupMenu) then 
    PopupMenu:=TPopupMenu.Create(self);
  ItemCovered:=false;
  for i := 0 to PopupMenu.Items.Count-1 do
    if IsSameEvent(PopupMenu.Items[I].OnClick, CopyDataToClipboardClick) then begin 
      ItemCovered:=true;
      break;
    end;
  if not ItemCovered then begin
    MI:=TMenuItem.Create(PopupMenu);
    MI.Caption:='Copy data to clipboard';
    MI.OnClick:=CopyDataToClipboardClick;
    MI.ShortCut:=ShortCut(Ord('C'),[ssShift,ssCtrl]);
    PopupMenu.Items.Add(MI);
  end;
end;

Это не будет проверять наличие всплывающих меню, добавленных во время выполнения, но, вероятно, лучше подходит для большинства случаев.

Другие вопросы по теме