【问题标题】:How to add subitems dynamically to a TMenuItem the moment its subitems are shown如何在显示子项时将子项动态添加到 TMenuItem
【发布时间】:2015-03-18 20:57:43
【问题描述】:

我有一个这样的菜单结构:

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

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

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

【问题讨论】:

  • 您可以一次创建所有子菜单项,然后在用户单击菜单项时隐藏/显示您需要的子菜单项。
  • @DalijaPrasnikar 澄清这一点:我想避免创建最终可以使用的所有项目,而只创建需要的项目(因为用户会弹出他们的父项目)。
  • 你用这个解决的实际问题是什么?看起来像是一种“专家系统”?这个问题有多动态?是否还有许多由运行时确定的选项的树?

标签: delphi submenu


【解决方案1】:

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

首先,检查自定义弹出菜单,例如TMS' one。有了这个,您可以防止用户单击弹出窗口时自动关闭它。之后,您可以捕捉该事件并动态添加所需的子菜单。但我不知道它会立即显示,还是弹出窗口应该关闭并重新打开。

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

【讨论】:

    【解决方案2】:

    您可以添加一个虚拟项目作为子菜单的占位符,然后使用具有虚拟项目的项目的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;
    

    【讨论】:

    • 有没有一种方法可以让用户不需要点击某个项目?我想在悬停(鼠标悬停)该项目时创建该项目的直接子项。
    • @Rene - 用户无需单击,当鼠标悬停时,子菜单项的 OnClick 会运行。尝试答案中的示例,只需在名为 PopupMenu1 的表单上放置一个空的 TPopupMenu 并将其分配给具有 ItemClick 过程的表单的 PopupMenu ..
    猜你喜欢
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-08
    相关资源
    最近更新 更多