How to add subitems dynamically to a TMenuItem the moment its subitems are shown

情到浓时终转凉″ 提交于 2019-12-14 00:33:38

问题


I have a menu structure like this:

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

Why do I do such thing? - This menu is used to select a combination of options A,B,C,D where sequence of selected options matters.
For Example: The user clicks on menu-item 2.3.1. That results in combination B-D-A.

Now, you know how I currently do it theoretically. Actually, there are much more options to combine. But only three are to be combined at the same time.
The problem is that I have to create all menu-items (three levels deep) before the menu is shown.

Is there a way to add submenu-items just when they are needed (that is when they should be shown)?


回答1:


You can add a dummy item to act as a placeholder for sub menus and then use OnClick event handler of items that have the dummy items to replace them with real items.

Below is to demonstrate only, not meant to be used in production code. It duplicates the example in the question.

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;



回答2:


It's a bit complicated, since Delphi doesn't have events for this in PopupMenu. What I think is that maybe it could be done the following way:

First of all, check for custom popup menus, for example TMS' one. With this you can prevent the automatic close of the popup when the user clicks on it. After that you can catch that event and dinamically add the submenus you want. But I don't know it will display it immediately, or the Popup should closed and reopened.

You can try to achieve the same with the standard popup, you can find how to prevent the closing here.



来源:https://stackoverflow.com/questions/28048599/how-to-add-subitems-dynamically-to-a-tmenuitem-the-moment-its-subitems-are-shown

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!