4 votes

Comment copier une partie d'un Treeview dans un Menu

J'essaie de copier une partie d'un Treeview dans un menu popup, et je n'ai pas de chance. Je n'arrive pas à faire fonctionner la récursion, et je sais que je m'y prends probablement mal.

Prenez cet exemple d'image (qui est une capture d'écran d'exécution du code ci-dessous) :

enter image description here

J'ai besoin que le menu soit créé avec la même relation que le Treeview, mais je ne veux pas que l'élément Root soit ajouté. Voici à quoi je veux que cela ressemble :

enter image description here

Notez que le premier élément n'est pas l'icône des paramètres (Root), et qu'ils sont en niveaux comme l'arborescence.

Voici le code que j'ai :

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  Menus, StdCtrls, Buttons;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ImageList1: TImageList;
    MenuItem1: TMenuItem;
    PopupMenu1: TPopupMenu;
    TreeView1: TTreeView;
    procedure MyMenuItemClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure TreeViewToMenu(TreeView: TTreeView; BaseNode: TTreeNode; OutMenu: TMenu);
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.MyMenuItemClick(Sender: TObject);
begin
  ShowMessage('You selected ' + TMenuItem(Sender).Name + ' - Tag: ' +
    IntToStr(TMenuItem(Sender).Tag));
end;

procedure TForm1.TreeViewToMenu(TreeView: TTreeView; BaseNode: TTreeNode; OutMenu: TMenu);
var
  I: Integer;
  MenuItem: TMenuItem;
begin
  MenuItem := TMenuItem.Create(nil);
  with MenuItem do
  begin
    Caption := BaseNode.Text;
    ImageIndex := BaseNode.ImageIndex;
    OnClick := @MyMenuItemClick;
  end;

  for I := 0 to BaseNode.Count - 1 do
  begin
    MenuItem.Tag := I;
    TreeViewToMenu(TreeView, BaseNode[I], OutMenu);
  end;

  OutMenu.Items.Add(MenuItem);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Pt: TPoint;
  I: Integer;
  Node: TTreeNode;
begin
  Pt.X := Button1.Left + 1;
  Pt.Y := Button1.Top + Button1.Height + 1;
  Pt := ClientToScreen(Pt);

  PopupMenu1.Items.Clear;
  TreeViewToMenu(TreeView1, TreeView1.Items[0], PopupMenu1);

  PopupMenu1.Popup(Pt.X, Pt.Y);
end;

end.

J'essaie également d'ajouter à la propriété Tag de MenuItem afin de pouvoir identifier chaque élément de menu par son tag.

Je pensais que la récursion signifiait essentiellement appeler à nouveau la procédure depuis l'intérieur de la procédure, de sorte qu'elle se répète elle-même, mais dans tous les cas, j'aurais vraiment besoin d'aide.

Merci.

6voto

Sertac Akyuz Points 32656

Il n'y a pas de problème avec votre compréhension d'un appel récursif, mais vous ne voulez pas ajouter un élément pour le nœud racine, donc vous devriez ajouter un élément et faire une récursion pour chaque enfant de tout nœud qui est passé à la procédure. Voici un exemple d'implémentation :

type
  TForm1 = class(TForm)
    ..
  private
    procedure TreeViewToMenu(BaseNode: TTreeNode; OutMenu: TComponent);
    ..

procedure TForm1.TreeViewToMenu(BaseNode: TTreeNode; OutMenu: TComponent);
var
  i: Integer;
  Node: TTreeNode;
  MenuItem: TMenuItem;
begin
  for i := 0 to BaseNode.Count - 1 do begin
    Node := BaseNode.Item[i];

    MenuItem := TMenuItem.Create(nil);
    MenuItem.Caption := Node.Text;
    MenuItem.ImageIndex := Node.ImageIndex;
    MenuItem.Tag := i;
    if Node.Count = 0 then
      MenuItem.OnClick := MyMenuItemClick;

    if OutMenu is TPopupMenu then
      TMenu(OutMenu).Items.Add(MenuItem)
    else if
      OutMenu is TMenuItem then
        TMenuItem(OutMenu).Add(MenuItem)
      else
        raise Exception.Create('Invalid class type');

    TreeViewToMenu(Node, MenuItem);

  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ..
begin
  ..
  TreeViewToMenu(TreeView1.Items[0], PopupMenu1);
  ..

Notez que j'ai changé la déclaration de TreeViewToMenu car (1) l'arborescence n'est pas utilisée et (2) nous ajoutons les éléments à l'un ou l'autre des éléments de la liste. TPopupMenu ou un TMenuItem c'est pourquoi j'ai déclaré 'OutMenu' en tant que TComponent qui accepterait les deux.

3voto

NGLN Points 25671

Comme Sertac dit vous ajoutez tous les éléments du menu à la racine du PopupMenu. Vous devez ajouter des éléments de sous-menu au dernier élément de menu créé.

Par conséquent, une approche alternative, faisant usage de TTreeNode.GetFirstChild y .GetNextSibling :

procedure TForm1.TreeViewToMenu(Node: TTreeNode; Menu: TMenuItem);
var
  MenuItem: TMenuItem;
begin
  while Node <> nil do
  begin
    MenuItem := TMenuItem.Create(nil);
    MenuItem.Caption := Node.Text;
    MenuItem.ImageIndex := Node.ImageIndex;
    Menu.Add(MenuItem);
    if Node.HasChildren then
      TreeViewToMenu(Node.GetFirstChild, MenuItem)
    else
      MenuItem.OnClick := MyMenuItemClick;
    Node := Node.GetNextSibling;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PopupMenu1.Items.Clear;
  TreeViewToMenu(TreeView1.Items[1], PopupMenu1.Items);
end;

Notez que la routine commence ici avec l'index de l'élément 1 le premier enfant de votre élément Root. S'il n'y a pas d'élément racine, commencez par l'indice 0 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X