如何在子项目显示时动态地将子项添加到TMenuItem

时间:2015-01-20 15:03:39

标签: delphi submenu

我有这样的菜单结构:

1. Option A
    1.1 Option B
        1.1.1 Option C
        1.1.2 Option D
    1.2 Option C
        1.2.1 Option B
        1.2.2 Option D
    1.3 Option D
        1.3.1 Option B
        1.3.2 Option C
2. Option B
    2.1 Option A
        2.1.1 Option C
        2.1.2 Option D
    2.2 Option C
        2.2.1 Option A
        2.2.2 Option D
    2.3 Option D
        2.3.1 Option A
        2.3.2 Option C
3. Option C
    3.1 Option A
        3.1.1 Option B
        3.1.2 Option D
    3.2 Option B
        3.2.1 Option A
        3.2.2 Option D
    1.3 Option D
        3.3.1 Option A
        3.3.2 Option B
4. Option D
    4.1 Option A
        4.1.1 Option B
        4.1.2 Option C
    4.2 Option B
        4.2.1 Option A
        4.2.2 Option C
    4.3 Option C
        4.3.1 Option A
        4.3.2 Option B

为什么我这样做? - 此菜单用于选择选项A,B,C,D的组合,其中所选选项的顺序很重要 例如:用户单击菜单项2.3.1。这导致组合B-D-A

现在,您知道我目前在理论上如何做到这一点。实际上,还有更多的选择可以结合起来。但是只有三个要同时合并 问题是我必须在显示菜单之前创建所有菜单项(深层三层)。

有没有办法在需要时添加子菜单项(即应该显示它们的时候)?

2 个答案:

答案 0 :(得分:3)

您可以添加一个虚拟项目作为子菜单的占位符,然后使用具有虚拟项目的项目的OnClick事件处理程序将其替换为实际项目。

以下仅用于演示,不应在生产代码中使用。它复制了问题中的例子。

procedure TForm1.PopupMenu1Popup(Sender: TObject);
var
  NewItem: TMenuItem;
  i: Integer;
begin
  PopupMenu1.Items.Clear;
  for i := 0 to 3 do begin
    NewItem := TMenuItem.Create(PopupMenu1);
    NewItem.Caption := Format('%d. Option %s', [i + 1, Chr(i + 65)]);
    NewItem.OnClick := ItemClick;
    NewItem.Tag := i;
    NewItem.Add(TMenuItem.Create(NewItem));
    PopupMenu1.Items.Add(NewItem);
  end;
end;


procedure TForm1.ItemClick(Sender: TObject);
var
  Root: TMenuItem;

  function ItemLevel(Item: TMenuItem): Integer;
  begin
    Result := 0;
    while Item.Parent <> Root do begin
      Item := Item.Parent;
      Inc(Result);
    end;
  end;

  function ExistsInTree(Item: TMenuItem; Option: Integer): Boolean;
  begin
    Result := Option = Item.Tag;
    if not Result then
      while Item.Parent <> Root do begin
        Item := Item.Parent;
        Result := Option = Item.Tag;
        if Result then
          Break;
      end;
  end;

  function LevelString(Item: TMenuItem): string;
  begin
    Result := '';
    while Item.Parent <> Root do begin
      Item := Item.Parent;
      Result := IntToStr(Item.MenuIndex + 1) + '.' + Result;
    end;
  end;

var
  Item, NewItem: TMenuItem;
  i: Integer;
  path: string;
begin
  Item := Sender as TMenuItem;
  Root := PopupMenu1.Items;

  if ItemLevel(Item) < 2 then begin
    if Item.Count = 1 then begin
      for i := 0 to 3 do begin
        if ExistsInTree(Item, i) then
          Continue;

        NewItem := TMenuItem.Create(Item);
        NewItem.OnClick := ItemClick;
        NewItem.Tag := i;
        Item.Add(NewItem);
        NewItem.Caption := Format('%s%d. Option %s',
                           [LevelString(NewItem), Item.Count - 1, Chr(i + 65)]);
        if ItemLevel(NewItem) < 2 then
          NewItem.Add(TMenuItem.Create(NewItem));
      end;
      Item.Delete(0);
    end;
  end else begin
    path := Chr(Item.Tag + 65);
    while Item.Parent <> Root do begin
      Item := Item.Parent;
      path := Chr(Item.Tag + 65) + '-' + path;
    end;
    ShowMessage(path);
  end;
end;

答案 1 :(得分:0)

这有点复杂,因为Delphi在PopupMenu中没有这方面的事件。我认为也许可以通过以下方式完成:

首先,检查自定义弹出菜单,例如TMS' one。使用此功能,您可以在用户单击时阻止自动关闭弹出窗口。之后,你可以捕捉到这个事件,并在动态上添加你想要的子菜单。但我不知道它会立即显示,或者Popup应该关闭并重新打开。

您可以尝试使用标准弹出窗口实现相同功能,您可以找到如何防止关闭here