7

我有一个 ListViewViewStyle = vsReport和两个弹出菜单:

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

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

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

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

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

4

3 回答 3

8

您不必使用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;
于 2012-06-29T13:18:26.617 回答
3

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

将此用于 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

于 2012-06-29T13:41:52.440 回答
0

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

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;
于 2012-06-29T10:01:16.930 回答