Я использую пользовательский компонент списка, и мне нужно, чтобы в нем был элемент всплывающего меню «копировать данные в буфер обмена». Если нет назначенного всплывающего окна, я создаю его и добавляю элемент меню, если уже назначено меню, добавляю элемент в текущее всплывающее окно. Пытался поместить код в конструктор, но потом понял, что всплывающее меню все еще не создано и не связано с моим списком. Итак, есть идеи, когда создать элемент по умолчанию?
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;
Не могу воспроизвести. Рассмотрим минимальный воспроизводимый пример. Какая версия Делфи?
Что, если разработчик назначает всплывающее окно во время выполнения? Что вам нужно сделать, так это предоставить доступный метод и оставить остальное пользователю компонента.
Я разработчик. Пользователи хотят иметь возможность копировать/вставлять выбранные данные из любого списка в существующем программном обеспечении с более чем 100 экземплярами. Поэтому я подумал добавить «фиксированный» элемент в меню. Кажется, нет способа сделать это, поскольку я не получаю уведомления, если всплывающее окно назначено моему списку. Также нельзя переопределить TControl.SetPopupMenu, он частный и не виртуальный.
Работайте во время выполнения, обрабатывайте wm_contextmenu, смотрите, прикреплено ли всплывающее окно, если оно прикреплено, смотрите, добавлено ли уже «копировать данные ...», в противном случае добавьте его. Создайте всплывающее окно, если оно не прикреплено.
Вместо того, чтобы обрабатывать WM_CONTEXTMENU напрямую, переопределите виртуальный метод TControl.DoContextPopup() или даже метод TControl.GetPopupMenu().





Переопределите виртуальный метод 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;
Работает идеально и применимо к любому элементу управления. Большое спасибо, Реми!
Принятый ответ действительно работает отлично, если вы не добавите сочетания клавиш в свой пункт меню. Если вы это сделаете, они не будут работать до тех пор, пока всплывающее меню не будет открыто каким-либо другим способом, потому что элементы не будут созданы.
Если вам нужны ярлыки, поэтому может быть предпочтительнее переместить код из 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;
Это не будет проверять наличие всплывающих меню, добавленных во время выполнения, но, вероятно, лучше подходит для большинства случаев.
Что вы делаете, когда PopupMenu уже содержит «Копировать данные в буфер обмена»-
TMenuItem?