[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

TreeView add item

Posted on 2006-07-05
10
Medium Priority
?
1,291 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
  • 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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

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 1800 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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
Suggested Courses

868 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