Delphi Dynamic Menu Elements

I have a popup menu that has several items.

  Option 1
  - Sub1
  - Sub2
 Option 2
  - Sub1
  - Sub2
 Option 3
  - Sub1
  - Sub2

I want to be able to add a submenu to a submenu of the 3rd option so that it looks like this:

  Option 1
  - Sub1
  - Sub2
 Option 2
  - Sub1
  - Sub2
 Option 3
  - Sub1
  - Sub2
    - Dynamic Item1
    - Dynamic Item2
    - Dynamic Item3

I am trying to work with the following code to figure this out, I can do it โ€œIFโ€, the menu option does not exist yet (option 3), but I cannot do this if Option 3 already exists (It creates a duplicate menu)

How can I do it?

thanks

unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls; type TForm2 = class(TForm) popMenu: TPopupMenu; gbDynamic: TGroupBox; gbMain: TGroupBox; popDynamic: TPopupMenu; Option11: TMenuItem; Option21: TMenuItem; Option31: TMenuItem; Sub11: TMenuItem; Sub21: TMenuItem; Item11: TMenuItem; Item21: TMenuItem; Item31: TMenuItem; Item41: TMenuItem; Sub12: TMenuItem; Sub22: TMenuItem; Sub13: TMenuItem; Sub23: TMenuItem; Option12: TMenuItem; Sub24: TMenuItem; Sub14: TMenuItem; Option22: TMenuItem; Sub25: TMenuItem; Sub15: TMenuItem; Option32: TMenuItem; Sub26: TMenuItem; Sub16: TMenuItem; Label1: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } Procedure PopupItemClick ( Sender : TObject ); end; var Form2: TForm2; stlist: TStrings; implementation {$R *.dfm} procedure TForm2.FormCreate(Sender: TObject); Var menuItem,SubItem : TMenuItem; I, N : Integer; s : String; begin //This will be a downloaded list from a server. stlist := TStringList.Create; stlist.Add ( 'Item 1' ); stlist.Add ( 'Item 2' ); stlist.Add ( 'Item 3' ); SubItem := TMenuItem.Create(popDynamic); SubItem.Caption := 'Option 3'; popDynamic.Items.Add(SubItem); MenuItem := TMenuItem.Create(popDynamic); MenuItem.Caption := 'Sub 1'; SubItem.Add(MenuItem); //This would work if Option 3 menu item was not aleady a menu item. For I := 0 To stlist.Count - 1 Do Begin SubItem := TMenuItem.Create ( popDynamic ); SubItem.Caption := stlist [i]; SubItem.OnClick := PopupItemClick; //assign it a custom integer value.. SubItem.Tag := i; MenuItem.Add(SubItem); End; end; Procedure TForm2.PopupItemClick ( Sender : TObject ); Var menuItem : TMenuItem; Begin menuItem := TMenuItem ( sender ); label1.caption := stlist.Strings [menuItem.Tag]; End; end. 

The form:

 object Form2: TForm2 Left = 0 Top = 0 Caption = 'Form2' ClientHeight = 247 ClientWidth = 480 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object gbDynamic: TGroupBox Left = 0 Top = 0 Width = 217 Height = 247 Align = alLeft Caption = 'Dynamic' PopupMenu = popDynamic TabOrder = 0 object Label1: TLabel Left = 48 Top = 32 Width = 31 Height = 13 Caption = 'Label1' end end object gbMain: TGroupBox Left = 217 Top = 0 Width = 263 Height = 247 Align = alClient Caption = 'What I Want Dynamically Created' PopupMenu = popMenu TabOrder = 1 ExplicitLeft = 336 ExplicitTop = 72 ExplicitWidth = 185 ExplicitHeight = 105 end object popDynamic: TPopupMenu Left = 136 Top = 96 object Option12: TMenuItem Caption = 'Option 1' object Sub14: TMenuItem Caption = 'Sub 1' end object Sub24: TMenuItem Caption = 'Sub 2' end end object Option22: TMenuItem Caption = 'Option 2' object Sub15: TMenuItem Caption = 'Sub 1' end object Sub25: TMenuItem Caption = 'Sub 2' end end object Option32: TMenuItem Caption = 'Option 3' object Sub16: TMenuItem Caption = 'Sub 1' end object Sub26: TMenuItem Caption = 'Sub 2' end end end object popMenu: TPopupMenu Left = 256 Top = 112 object Option11: TMenuItem Caption = 'Option 1' object Sub13: TMenuItem Caption = 'Sub 1' end object Sub23: TMenuItem Caption = 'Sub 2' end end object Option21: TMenuItem Caption = 'Option 2' object Sub12: TMenuItem Caption = 'Sub 1' end object Sub22: TMenuItem Caption = 'Sub 2' end end object Option31: TMenuItem Caption = 'Option 3' object Sub11: TMenuItem Caption = 'Sub 1' object Item11: TMenuItem Caption = 'Item 1' end object Item21: TMenuItem Caption = 'Item 2' end object Item31: TMenuItem Caption = 'Item 3' end object Item41: TMenuItem Caption = 'Item 4' end end object Sub21: TMenuItem Caption = 'Sub 2' end end end end 
+4
source share
2 answers

The easiest way to do this is to give Option3 a name, and then check it in a loop:

  SubItem := nil; for i := 0 to popdynamic.Items.Count-1 do if SameText(popdynamic.Items[i].Name, 'mnuOption3') then SubItem := popdynamic.Items[i]; if SubItem = nil then begin SubItem := TMenuItem.Create(popDynamic); SubItem.Caption := 'Option 3'; Subitem.Name := 'mnuOption3'; popDynamic.Items.Add(SubItem); end; 

This way, you will not create a new subitem if it already exists.

+3
source

All you need to do to create a new submenu is a link to an existing menu item - if it is the same each time, just access the object directly, otherwise find it somehow - and then call Add to it with using the TMenuItem that you want to add. I use something like this in one of my applications to recursively create menus from an XML file.

This should be a very concise version of what I'm doing.

 procedure TMainForm.AddMenuItems(XMLNode: IXMLDOMNode; Parent: TMenuItem); var node: IXMLNode; item: TMenuItem; begin for i := 0 to XMLNode.childNodes.length - 1 do begin node := XMLNode.childNodes.item[i]; item := NewItem(node.attributes.getNamedItem('name').nodeValue, 0, false, true, nil, 0, ''); if node.nodeName = 'group' then begin Parent.Add(item); AddMenuItems(node, item); end else begin //You probably want to add a Tag to your items so you can tell them apart. item.OnClick := DynamicItemClick; Parent.Add(item); end; end; end; procedure TMainForm.LoadData; var XMLNode: IXMLNode; //... begin //Clear old dynamic items while Set1.Count > 0 do Set1.Items[0].Free; //Open XML file, find right XMLNode... AddMenuItems(XMLNode.firstChild, Set1, ''); end; 

... where Set1 is the menu item for which I am creating menu items. In your case, I assume it will be Sub26 (and Sub23 for one in the popup menu). Just use this basic approach, replacing the XML material with what you need to read your file.

+1
source

Source: https://habr.com/ru/post/1302543/


All Articles