Search code examples
treeviewmenuitemdelphi-10.2-tokyo

TreeView as vertical menu - how to get name of associated MenuItem


I am working on changing TMainMenu to TTreeView i.e.vertical menu. I am able to create the TTreeView and by calling AddChildObject() I have Node.Data.

I was able to call the OnClick event of an associated MenuItem using TMenuItem(TreeView1.Selected.Data).Click.

How to get the name of the associated MenuItem?

I tried TMenuItem(TreeView.Selected.Data).Name, but the Name shows as an empty string.

procedure TForm1.TreeViewClick(Sender: TObject);
begin
  if Assigned ((Sender as TTreeView).Selected) then 
  begin
    TMenuItem ((Sender as TTreeView).Selected.Data).Click;
    // this works fine i.e. on node click specific menuitem click is called
    
    TMenuItem ((Sender as TTreeView).Selected.Data).Name;
    // Name is empty inspite of menuitem name being not empty
  end;
end;

Code for populating the TreeView:

procedure CopyMenuToTreeView( aMenu: TMenu; aTreeview: TTreeView );
  procedure AddItems( anItem: TMenuItem; aParentNode: TTreeNode );
  var
    node: TTreeNode;
    i: Integer;
    begin
      for i := 0 To anItem.Count -1 do begin
      node := aTreeView.Items.AddChildObject(
        aParentNode,
        anItem.Items[i].Caption );
      AddItems( anItem.Items[i], node );
    end;
  end;
begin
  Assert( Assigned( aTreeView ), 'No treeview' );
  aTreeView.Items.BeginUpdate;
  try
    aTreeView.Items.Clear;
    if Assigned( aMenu ) then
      AddItems( aMenu.Items, nil );
    aTreeView.FullExpand;
  finally
    aTreeView.Items.EndUpdate;
  end; { Finally }
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  CopyMenuToTreeview( MainMenu1, TreeView1 );
end;

Also, here is the existing TMenuItem.OnClick:

procedure TForm1.MI_Click(Sender: TObject);
begin
  //Common code for many menuitem
  //Code for creating form based on name of menuitem
  CreateMIForm('Frm'+((Sender as TMenuItem). Name));
end;

Solution

  • I have fixed your code - AddChildObject() needs a 3rd argument. In TreeView1Click I used an intermediate variable.

    Tested with Delphi 10.4.1.

    unit TreeViewMenuDemoMain;
        
    interface
        
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Menus, Vcl.ComCtrls;
        
    type
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        MainMenu1: TMainMenu;
        File1: TMenuItem;
        Close1: TMenuItem;
        Exit1: TMenuItem;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Close1Click(Sender: TObject);
        procedure Exit1Click(Sender: TObject);
        procedure TreeView1Click(Sender: TObject);
      end;
        
    var
      Form1: TForm1;
        
    implementation
        
    {$R *.dfm}
        
    procedure CopyMenuToTreeView( aMenu: TMenu; aTreeView: TTreeView );
      procedure AddItems( anItem: TMenuItem; aParentNode: TTreeNode );
      var
        node: TTreeNode;
        i: Integer;
      begin
        for i := 0 To anItem.Count -1 do begin
          node := aTreeView.Items.AddChildObject(
            aParentNode,
            anItem.Items[i].Caption,
            anItem.Items[i]);
          AddItems( anItem.Items[i], node );
        end;
      end;
    begin
      Assert( Assigned( aTreeView ), 'No treeview' );
      aTreeView.Items.BeginUpdate;
      try
        aTreeView.Items.Clear;
        if Assigned( aMenu ) then
          AddItems( aMenu.Items, nil );
        aTreeView.FullExpand;
      finally
        aTreeView.Items.EndUpdate;
      end; { Finally }
    end;
        
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      CopyMenuToTreeView(MainMenu1, TreeView1);
    end;
        
    procedure TForm1.Close1Click(Sender: TObject);
    begin
      ShowMessage('File/Close');
    end;
        
    procedure TForm1.Exit1Click(Sender: TObject);
    begin
      ShowMessage('File/Exit');
    end;
        
    procedure TForm1.TreeView1Click(Sender: TObject);
    var
      MenuItem : TMenuItem;
    begin
      if Assigned ((Sender as TTreeView).Selected) then begin
        MenuItem := TMenuItem((Sender as TTreeView).Selected.Data);
        MenuItem.Click;
        // this works fine i.e. on node click specific menuitem click is called
        
        ShowMessage(MenuItem.Name);
      end;
    end;
        
    end.
    

    DFM file:

    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 299
      ClientWidth = 635
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      Menu = MainMenu1
      OldCreateOrder = False
      PixelsPerInch = 96
      TextHeight = 13
      object TreeView1: TTreeView
        Left = 16
        Top = 24
        Width = 205
        Height = 257
        Indent = 19
        TabOrder = 0
        OnClick = TreeView1Click
      end
      object Button1: TButton
        Left = 280
        Top = 36
        Width = 75
        Height = 25
        Caption = 'Button1'
        TabOrder = 1
        OnClick = Button1Click
      end
      object MainMenu1: TMainMenu
        Left = 364
        Top = 124
        object File1: TMenuItem
          Caption = '&File'
          object Close1: TMenuItem
            Caption = 'Close'
            OnClick = Close1Click
          end
          object Exit1: TMenuItem
            Caption = 'Exit'
            OnClick = Exit1Click
          end
        end
      end
    end