Delphi 如何设置ListView标题栏的弹出菜单以及项目弹出菜单?

Delphi 如何设置ListView标题栏的弹出菜单以及项目弹出菜单?,delphi,listview,popupmenu,Delphi,Listview,Popupmenu,我有一个带有ViewStyle=vsReport的列表视图和两个弹出菜单: 列弹出菜单,我想在用户右键单击标题栏时打开该菜单 项目弹出菜单必须在用户右键单击任何列表项目/子项目或项目下方的空白时打开 显示该菜单的最正确方式是什么?我应该处理哪些事件 问题是当我设置ListView.PopupMenu属性时,右键单击ListView客户端矩形中的任意点后会出现弹出菜单 当我处理ListView.OnColumnRightClick事件时,如果仅在单击列标题后激发,则不包括标题栏(列右侧)的可用空间

我有一个带有
ViewStyle=vsReport
的列表视图和两个弹出菜单:

  • 列弹出菜单,我想在用户右键单击标题栏时打开该菜单
  • 项目弹出菜单必须在用户右键单击任何列表项目/子项目或项目下方的空白时打开
  • 显示该菜单的最正确方式是什么?我应该处理哪些事件

    问题是当我设置
    ListView.PopupMenu
    属性时,右键单击ListView客户端矩形中的任意点后会出现弹出菜单

    当我处理ListView.OnColumnRightClick事件时,如果仅在单击列标题后激发,则不包括标题栏(列右侧)的可用空间


    事件
    LisView.OnMouseUp
    仅在右键单击项目下方的空格后激发。

    我就是这样解决的,但我不喜欢这个解决方案。如果你有更好的,请写下来,我会认为它是正确的

    uses
      CommCtrl;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      ListView.PopupMenu := TPopupMenu.Create(Self);
      ListView.PopupMenu.OnPopup := ListViewPopup;
    end;
    
    procedure TForm1.ListViewPopup(Sender: TObject);
    var
      Pos: TPoint;
      SrcMenu: TPopupMenu;
      I: Integer;
      MenuItem: TMenuItem;
      Header: HWND;
      HeaderRect: TRect;
      HeaderHeight: Integer;
    begin
      // Re-filling ListView's popup menu
      ListView.PopupMenu.Items.Clear();
    
      // Getting header height
      Header := ListView_GetHeader(ListView.Handle);
      GetWindowRect(Header, HeaderRect);
      HeaderHeight := HeaderRect.Bottom - HeaderRect.Top;
      Pos := ListView.ScreenToClient(ListView.PopupMenu.PopupPoint);
    
      // Clicked on header?
      if Pos.Y < HeaderHeight then
        SrcMenu := PopupMenuColumns
      else
        SrcMenu := PopupMenuItems;
    
      // Copying destired menu to ListView.PopupMenu
      for I := 0 to SrcMenu.Items.Count - 1 do
      begin
        MenuItem := TMenuItem.Create(FListViewPopupMenu);
    
        with SrcMenu.Items[I] do
        begin
          MenuItem.Action := Action;
          MenuItem.Caption := Caption;
          MenuItem.ShortCut := ShortCut;
          MenuItem.Checked := Checked;
          MenuItem.Enabled := Enabled;
          MenuItem.OnClick := OnClick;
          MenuItem.HelpContext := HelpContext;
          MenuItem.Name := Name;
          MenuItem.ImageIndex := ImageIndex;
        end;
    
        ListView.PopupMenu.Items.Add(MenuItem);
      end;
    
      ListView.PopupMenu.Images := SrcMenu.Images;
    end;
    
    使用
    CommCtrl;
    过程TForm1.FormCreate(发送方:TObject);
    开始
    ListView.PopupMenu:=TPopupMenu.Create(Self);
    ListView.PopupMenu.OnPopup:=ListViewPopup;
    结束;
    程序TForm1.ListViewPopup(发送方:ToObject);
    变量
    位置:TPoint;
    SrcMenu:TPopupMenu;
    I:整数;
    菜单项:TMenuItem;
    标题:HWND;
    头颅ct:TRect;
    HeaderHeight:整数;
    开始
    //重新填充ListView的弹出菜单
    ListView.PopupMenu.Items.Clear();
    //获取收割台高度
    Header:=ListView\u GetHeader(ListView.Handle);
    GetWindowRect(标题、标题等);
    HeaderHeight:=HeaderRect.Bottom-HeaderRect.Top;
    Pos:=ListView.ScreenToClient(ListView.PopupMenu.PopupPoint);
    //点击标题?
    如果位置Y<车头高度,则
    SrcMenu:=PopupMenuColumns
    其他的
    srcmenue:=popupmenuiems;
    //正在将目标菜单复制到ListView.PopupMenu
    对于I:=0到srcmunu.Items.Count-1 do
    开始
    MenuItem:=TMenuItem.Create(FListViewPopupMenu);
    使用SrcMenu.Items[I]do
    开始
    MenuItem.Action:=操作;
    MenuItem.Caption:=标题;
    MenuItem.ShortCut:=快捷方式;
    MenuItem.Checked:=已检查;
    MenuItem.Enabled:=已启用;
    MenuItem.OnClick:=OnClick;
    MenuItem.HelpContext:=HelpContext;
    MenuItem.Name:=名称;
    MenuItem.ImageIndex:=ImageIndex;
    结束;
    ListView.PopupMenu.Items.Add(菜单项);
    结束;
    ListView.PopupMenu.Images:=SrcMenu.Images;
    结束;
    
    您不必使用listview的
    PopupMenu
    属性,将其置为未设置状态,您可以将处理程序附加到
    OnContextPopup
    事件,并根据位置启动所需的任何弹出菜单。例如:

    procedure TForm1.ListViewContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
    var
      HeaderRect: TRect;
      Pos: TPoint;
    begin
      GetWindowRect(ListView_GetHeader(ListView.Handle), HeaderRect);
      Pos := ListView.ClientToScreen(MousePos);
      if PtInRect(HeaderRect, Pos) then
        PopupMenuColumns.Popup(Pos.X, Pos.Y)
      else
        PopupMenuItems.Popup(Pos.X, Pos.Y);
    end;
    

    你可以大大简化它。创建两个弹出菜单(标题行和列各一个。在IDE中指定
    TListView.PopupMenu
    列弹出菜单

    将其用于ListView的事件处理程序:

    procedure TForm1.ListView1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
    var
      HeaderRect: TRect;
      HeaderHeight: Integer;
      Header: HWnd;
    begin
      ListView1.PopupMenu := ColumnMenu;   // Default to ColumnMenu
      Header := ListView_GetHeader(ListView1.Handle);
      GetWindowRect(Header, HeaderRect);
      HeaderHeight := HeaderRect.Bottom - HeaderRect.Top;
      if MousePos.Y < HeaderHeight then
        ListView1.PopupMenu := HeaderMenu;
    end;
    
    procedure TForm1.ListView1ContextPopup(发送方:TObject;鼠标点:TPoint;变量处理:Boolean);
    变量
    头颅ct:TRect;
    HeaderHeight:整数;
    标题:HWnd;
    开始
    ListView1.PopupMenu:=ColumnMenu;//默认为ColumnMenu
    Header:=ListView\u GetHeader(ListView1.Handle);
    GetWindowRect(标题、标题等);
    HeaderHeight:=HeaderRect.Bottom-HeaderRect.Top;
    如果MousePos.Y

    它与@Sertac的方法稍有不同,不调用
    ClientToScreen
    PtInRect
    ——因为我们知道点在ListView的范围内,所以简单的点击高度测试就足以知道我们是否在标题或列区域。它还确保始终至少有一个弹出窗口始终分配给
    列表视图的菜单。

    您不喜欢这个解决方案的哪些方面?@NGLN当您需要复制菜单项时,感觉有点奇怪。我认为可以滑到WinAPI级别并在那里执行一些操作。您是否希望仅当您在某个项目上,甚至在您正在运行时,才弹出
    弹出菜单项er子项?@TLama是的,有多个子项比我强。:-)当“新答案发布”横幅出现时,我正在从IDE复制我的测试代码粘贴到我的答案中,说了同样的话+1.@Ken-我觉得在几个小时前的问题上出现这种情况很奇怪,对不起。。谢谢。)@塞塔克,这很奇怪。我把这归咎于我今天的网络连接滞后。:-)+一对二@安德鲁,我给你留下了关于
    OnContextPopup
    的评论,但几分钟后就删除了。但是无论如何,
    Handled
    参数呢?您不应该将其设置为True吗?@TLama-仅当控件的“PopupMenu”指定了一个弹出窗口,并且您不想启动它时才可以。