【问题标题】:How to set popup menu for ListView header bar together with items popup menu?如何为 ListView 标题栏设置弹出菜单以及项目弹出菜单?
【发布时间】:2012-06-29 09:15:41
【问题描述】:

我有一个带有 ViewStyle = vsReport 的 ListView 和两个弹出菜单:

  1. 列弹出菜单,我想在用户右键单击标题栏时打开它
  2. 项目弹出菜单,必须在用户右键单击任何列表项/子项或项目下方的空白时打开。

显示菜单的最正确方式是什么?我应该处理哪些事件?

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

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

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

【问题讨论】:

  • 您是否只希望在您结束某个项目或什至在您结束子项目时弹出PopupMenuItems 菜单?
  • @TLama 是的,也包括子项目

标签: delphi listview popupmenu


【解决方案1】:

您不必使用列表视图的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 复制我的测试代码以粘贴到我的答案中,并说同样的话。 +1。
  • @Ken - 在几个小时前的问题上发生这种情况时,我觉得很奇怪,对不起..谢谢。 :)
  • @Sertac,这很奇怪。我把它归咎于我今天的互联网连接有延迟。 :-)
  • +1 两者。 @Andrew,我给你留下了关于 OnContextPopup 的评论,但几分钟后删除了它。但无论如何,Handled 参数呢?您不应该将其设置为 True 吗?
  • @TLama - 仅当控件具有分配给其“PopupMenu”的弹出窗口并且您不想启动它时。
【解决方案2】:

您可以大大简化它。创建两个弹出菜单(标题行和列各一个。在 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;

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

【讨论】:

    【解决方案3】:

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

    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;
    

    【讨论】:

    • 你不喜欢这个解决方案的什么?
    • @NGLN 当您需要复制菜单项时,感觉有点奇怪。我认为可以滑到 WinAPI 级别并在那里做一些事情。
    猜你喜欢
    • 2016-04-15
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多