【问题标题】:delphi custom component with default popupmenu item带有默认弹出菜单项的delphi自定义组件
【发布时间】:2019-09-06 13:22:01
【问题描述】:

我使用自定义列表视图组件,我需要它有一个弹出菜单项“将数据复制到剪贴板”。如果没有分配的弹出窗口,我创建一个并添加菜单项,如果已经分配了菜单,则将该项目添加到当前弹出窗口中。试图将代码放在构造函数中,但后来我意识到,弹出菜单仍未创建或关联到我的列表视图。那么知道何时创建我的默认项目吗?

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
  • 无法复制。考虑minimal reproducible example。什么版本的德尔福?
  • 如果开发者在运行时分配一个弹窗怎么办?您需要做的是公开一个可访问的方法,并将其余的留给组件用户。
  • 在运行时工作,处理 wm_contextmenu,查看是否附加了弹出窗口,如果已附加,则查看“复制数据...”是否已附加,否则附加。如果没有附加,则创建一个弹出窗口。
  • 不是直接处理WM_CONTEXTMENU,而是覆盖虚拟的TControl.DoContextPopup()方法,甚至是TControl.GetPopupMenu()方法。

标签: delphi components popupmenu


【解决方案1】:

接受的答案确实非常有效 - 除非您在菜单项中添加键盘快捷键。如果这样做,在以其他方式访问弹出菜单之前,这些将不起作用,因为这些项目不会被创建。 如果您需要快捷方式,最好将代码从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;

这不会检查在运行时添加的弹出菜单,但可能更适合大多数情况。

【讨论】:

    【解决方案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;
    

    【讨论】:

    • 完美运行,适用于任何控件。非常感谢你,雷米!
    猜你喜欢
    • 1970-01-01
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 2014-12-08
    • 2011-03-08
    相关资源
    最近更新 更多