Solved

TreeView add item

Posted on 2006-07-05
10
1,279 Views
Last Modified: 2010-04-05
Hello,

I want to use TreeView to create somekind of a very simple "document browser".

The TreeView starts with an empty "Root".

If user RIGHT-CLICK to a node, a "popup menu" will appear with this menu items :

- Add FOLDER
- Add FILE
- Delete

If user choose Add FOLDER, it can have child nodes  FILEs , but not FOLDER
If user choose ADD FILE, it can not have child node

At the end the structure will be something like this :

Root
|-------- FILE
|-------- FOLDER
                 |------ FILE
                 |------ FILE

So, this structure below is not allowed because FOLDER may not have FOLDER as child node:

Root
|-------- FILE
|-------- FOLDER
                 |------ FOLDER

One more thing, how can I add "compound items" as node value ? For example: a FILE/FOLDER item is constructed from 2 values :
1. Node LABEL (example: Price List)
2. File (or folder) path (example: C:\DATA\Price_List.xls)

The TreeView will display only the "Node LABEL"

If user choose Delete from the popup menu, the node and all childs will be deleted.

Please if you can show me some codes how to make this scenario.

Thanks in advance.
0
Comment
Question by:nova2002
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
  • +2
10 Comments
 
LVL 21

Expert Comment

by:ziolko
ID: 17041112
here's part of my old code:

procedure TCustomInventoryForm.AddSubCategory(Idx: Integer;const Caption: string);
var tn: TTreeNode;
    sc: TSubCategory;
begin
  sc := TSubCategory.Create(Idx, Caption);
  FSubCategories.Add(sc);
  tn := TreeView.Items.AddChild(nil ,Caption);
  tn.Data := sc;
  tn.ImageIndex := Idx;
  tn.SelectedIndex := Idx;
end;

>> AddChild(nil ,Caption); adds child of the "root"

if You want add child nodes:

tn := TreeView.Items.AddChild(nil ,Caption);
tn2 := TreeView.Items.AddChild(tn ,Caption2);
tn3 := TreeView.Items.AddChild(tn2 ,Caption3);

and so on.

ziolko.
0
 

Author Comment

by:nova2002
ID: 17041316
ziolko, thats not what I expected from my questions above.
0
 
LVL 10

Expert Comment

by:atul_parmar
ID: 17041452
I suggest to go with Tvirtualstringtree, It best fits your requirement. see http://www.soft-gems.net/VirtualTreeview/

See the demos available with and if you feel any doubt ask me.

Or If you want to use treeview, it has Data property where you can store other data.

To give you rough idea on your structure.
1. When user right clicks, exmine the selected item
    - If it is FILE, disable Add FILE menu item
    - If it is FOLDER, disable Add FOLDER menu item
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:nova2002
ID: 17042468
atul, it looks interesting. But I am not that familiar with the licensing. They have Mozilla MPL1.1 and GNU Lesser GPL. Does it means I can use it for a commercial product for free ? Which one should I choose.

I will try to give it a go and will ask if I have problem or questions with it.
0
 
LVL 10

Expert Comment

by:atul_parmar
ID: 17042532
Can you tell me what Delphi version you are using the same is also available with Delphi 7
0
 
LVL 10

Expert Comment

by:atul_parmar
ID: 17042560
as long as the licensing is concerned you can use and distribute is freely. see the licensing document.
0
 
LVL 17

Accepted Solution

by:
TheRealLoki earned 450 total points
ID: 17048569
Just wrote this example for you on how I'd do it using a standard TTreeview

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, (*Variants,*) Classes, Graphics, Controls, Forms, // uncomment variants if using delphi7+
  Dialogs, ComCtrls, ActnList, Menus, StdCtrls;

type TTreeDataObject = class(TObject) // every object we add to a node is of this type, so we can easily work with it
  public
  end;

type TTreeRootObject = class(TTreeDataObject) // our own root node
  public
  end;

type TTreeFolderObject = class(TTreeDataObject) // a folder
  public
    DisplayName: string;
    constructor Create(DisplayName_: string);
  end;

type  TTreeFileObject = class(TTreeDataObject) // a file
  public
      DisplayName: string;
      Filename: string;
      constructor Create(Filename_, DisplayName_: string);
  end;


type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    pmTree: TPopupMenu;
    ActionList1: TActionList;
    aAddFolder: TAction;
    aAddFile: TAction;
    AddFolder1: TMenuItem;
    AddFile1: TMenuItem;
    aDelete: TAction;
    OpenDialog1: TOpenDialog;
    Delete1: TMenuItem;
    Label1: TLabel;
    Label2: TLabel;
    procedure aAddFolderExecute(Sender: TObject);
    procedure aAddFileExecute(Sender: TObject);
    procedure pmTreePopup(Sender: TObject);
    procedure aDeleteExecute(Sender: TObject);
    procedure TreeView1Deletion(Sender: TObject; Node: TTreeNode);
    procedure FormCreate(Sender: TObject);
    procedure TreeView1Click(Sender: TObject);
  private
    { Private declarations }
    RightClickedNode: TTreeNode;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
// add our own root note
    with TreeView1.Items.AddChild(nil, 'ROOT') do
      Data := TTreeRootObject.Create;
end;

procedure TForm1.pmTreePopup(Sender: TObject);
var
  TreeDataObject: TTreeDataObject;
begin
// when the user right clicks, we decide what menu options are available
  if TreeView1.SelectionCount = 1 then // use .SelCount if delphi version < 7
  begin //a tree node is selected. find out what type it is and show the appropriate menu items
    RightClickedNode := TreeView1.Selected;
    if assigned(RightClickedNode.Data) then
    begin
      TreeDataObject := TTreeDataObject(RightClickedNode.Data);
      if (TreeDataObject is TTreeRootObject) then
      begin // can add a file or folder from the root
        aAddFolder.Visible := True;
        aAddFile.Visible := True;
        aDelete.Visible := False;
      end
      else if (TreeDataObject is TTreeFolderObject) then
      begin // can add a file below a folder
        aAddFolder.Visible := False;
        aAddFile.Visible := True;
        aDelete.Visible := True;
      end
      else if (TreeDataObject is TTreeFileObject) then
      begin // can not add anything below a file
        aAddFolder.Visible := False;
        aAddFile.Visible := False;
        aDelete.Visible := True;
      end
      else
      begin // unhandled data type, not a folder or file type (does not happen in this example, but here in case you wish to add future support)
        aAddFolder.Visible := False;
        aAddFile.Visible := False;
        aDelete.Visible := False;
      end;
    end
    else
    begin // this does not have an object assigned to it (does not happen in this example, but here in case you wish to add future support)
        aAddFolder.Visible := False;
        aAddFile.Visible := False;
        aDelete.Visible := False;
    end;
  end
  else
  begin // do not allow adding if user has selected more than 1 node
    aAddFolder.Visible := False;
    aAddFile.Visible := False;
  end;
end;

procedure TForm1.aAddFolderExecute(Sender: TObject);
var
  newcaption: string;
begin
  newcaption := InputBox('Add Folder', 'Folder name', 'new');
  TreeView1.Items.AddChildObject(RightClickedNode, newcaption, TTreeFolderObject.Create(newcaption));
  RightClickedNode.Expand(False);
end;

procedure TForm1.aAddFileExecute(Sender: TObject);
var
  TreeDataObject: TTreeDataObject;
  newcaption, filename: string;
  newnode: TTreeNode;
begin
  if OpenDialog1.Execute then
  begin
    filename := OpenDialog1.FileName;
    newcaption := InputBox('Add File', 'Display name', ExtractFilename(OpenDialog1.FileName));
    TreeView1.Items.AddChildObject(RightClickedNode, newcaption, TTreeFileObject.Create(Filename, newcaption));
    RightClickedNode.Expand(False);
  end;
end;

procedure TForm1.aDeleteExecute(Sender: TObject);
begin
  If MessageDlg('Really delete this node and any child nodes it has?', mtConfirmation, [mbYes, mbCancel], 0) = idYes then
    RightClickedNode.Delete;
end;

procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
var
  TreeDataObject: TTreeDataObject;
begin
  if assigned(Node.Data) then
    TTreeDataObject(Node.Data).Free; // assume all objects are our objects and clean it up as we delete
end;

procedure TForm1.TreeView1Click(Sender: TObject);
var
  TreeDataObject: TTreeDataObject;
begin
// display the tree node details (folder or file)
  if TreeView1.SelectionCount = 1 then // use .SelCount if delphi version < 7
  begin
    if assigned(TreeView1.Selected.Data) then
    begin
      TreeDataObject := TTreeDataObject(TreeView1.Selected.Data);
      if (TreeDataObject is TTreeRootObject) then
      begin // can add a file or folder from the root
        label1.caption := 'ROOT';
        label2.caption := '';
      end
      else if (TreeDataObject is TTreeFolderObject) then
      begin // can add a file below a folder
        label1.caption := TTreeFolderObject(TreeDataObject).DisplayName;
        label2.caption := '';
      end
      else if (TreeDataObject is TTreeFileObject) then
      begin // can not add anything below a file
        label1.caption := TTreeFileObject(TreeDataObject).DisplayName;
        label2.caption := TTreeFileObject(TreeDataObject).Filename;
      end
      else
      begin
        label1.caption := '';
        label2.caption := '';
      end;
    end
    else
    begin // no data object assigned (does not happen in this example)
      label1.caption := '';
      label2.caption := '';
    end;
  end;
end;

{ TTreeFolderObject }

constructor TTreeFolderObject.Create(DisplayName_: string);
begin
  inherited Create;
  DisplayName := DisplayName_;
end;

{ TTreeFileObject }

constructor TTreeFileObject.Create(Filename_, DisplayName_: string);
begin
  inherited Create;
  Filename := Filename_;
  DisplayName := DisplayName_;
end;

end.


***********************************
***** FORM FOLLOWS *****************
***********************************

object Form1: TForm1
  Left = 186
  Top = 107
  Width = 651
  Height = 455
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 24
    Top = 8
    Width = 32
    Height = 13
    Caption = 'Label1'
  end
  object Label2: TLabel
    Left = 24
    Top = 32
    Width = 32
    Height = 13
    Caption = 'Label2'
  end
  object TreeView1: TTreeView
    Left = 16
    Top = 56
    Width = 361
    Height = 297
    HideSelection = False
    Indent = 19
    PopupMenu = pmTree
    ReadOnly = True
    RightClickSelect = True
    RowSelect = True
    ShowRoot = False
    TabOrder = 0
    OnClick = TreeView1Click
    OnDeletion = TreeView1Deletion
  end
  object pmTree: TPopupMenu
    OnPopup = pmTreePopup
    Left = 224
    Top = 128
    object AddFolder1: TMenuItem
      Action = aAddFolder
    end
    object AddFile1: TMenuItem
      Action = aAddFile
    end
    object Delete1: TMenuItem
      Action = aDelete
    end
  end
  object ActionList1: TActionList
    Left = 224
    Top = 176
    object aAddFolder: TAction
      Caption = 'Add Folder'
      Hint = 'Add Folder'
      OnExecute = aAddFolderExecute
    end
    object aAddFile: TAction
      Caption = 'Add File'
      Hint = 'Add File'
      OnExecute = aAddFileExecute
    end
    object aDelete: TAction
      Caption = 'Delete'
      Hint = 'Delete'
      OnExecute = aDeleteExecute
    end
  end
  object OpenDialog1: TOpenDialog
    Left = 224
    Top = 216
  end
end
0
 
LVL 1

Expert Comment

by:tammoz
ID: 17048639
hi
  the best solution is to create your own class and inherite it from the (TTreeNode) class
so you can add any property and save any value you need in it, follow these steps

1) add this code after the (uses) part of the interface of your unit

Type Node_Folder = Class(TTreeNode)
  private
    FolderPrice : float;
    FolderPath : string;
end;

type Node_File = Class(TTreeNode)
  private
    FilePrice: float;
    FilePath : String;
end;
----------------------------------------------------------------------------------------------

2) then identify a global variable like this:
  Current_Class : TTreeNodeClass;
----------------------------------------------------------------------------------------------

3) go to the event (OnCreateNodeClass) of your treeview and write down the following:

procedure TChoseVisitFm.TreeView1CreateNodeClass(Sender: TCustomTreeView;
  var NodeClass: TTreeNodeClass);
begin
  NodeClass := Current_Class;
end;

to tell delphi that you want to type cast the treenode:
----------------------------------------------------------------------------------------------

4) now to add a new file you have to do the following:

procedure Add_New_File(FName, FPath : string, FPrice : float, FParent : TTreeNode);
var NFile : TTreeNode;
begin
     Current_Class := Node_File;
     NFile := TreeView1.Items.AddChild(FParent, FName);
     (NFile as Node_File).FilePrice := FPrice;
     (NFile as Node_File).FilePath  := FPath;
end;

and to add a new folder

procedure Add_New_Folder(FName, FPath : string, FPrice : float);
var NFolder : TTreeNode;
begin
     Current_Class := Node_Folder;
     NFolder := TreeView1.Items.AddChild(Nill, FName);
     (NFolder as Node_Folder).FolderPrice := FPrice;
     (NFolder as Node_Folder).FolderPath  := FPath;
end;

last note
       in your case you can use one class for both file and folder but for me I preffer to separate them for future development and also it will be easer to specify an image from image index for every class of them

Best regards
0
 

Author Comment

by:nova2002
ID: 17049469
TheRealLoki, thanks for your example. That is very nice for learning purposes.

Your quality of answer is always excellent !
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17055354
you're welcome :-)
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…
This video shows how to use Hyena, from SystemTools Software, to update 100 user accounts from an external text file. View in 1080p for best video quality.

737 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question