This site is moving to The Zen Source Library
Please Update your bookmarks


A more complex example


The project started in example one, is not complex enough to demonstrate some of the mode advanced TTreeView related topics. This example is slightly more complex, but is not much more difficult to understand.

In the previous examples there have been two node types - the root and "normal" nodes. Here there a 3 node types - the root, file nodes and folder nodes.

As with example 1 I'm going to use constants to index the node images.


   const
      IMG_NODE_ROOT = 0;
      IMG_NODE_FILE_CLOSED = 1;
      IMG_NODE_FILE_OPEN = 2;
      IMG_NODE_FOLDER_CLOSED = 3;
      IMG_NODE_FOLDER_OPEN = 4;


Here are the "rules" for the nodes for this example


In example 2 we saw how to give node's images. Here there are more types of nodes, but otherwise its exactly the same. What is different is that I'm going to be using a node's ImageIndex to identify it.

I've also defined an enum for each type of node, and one for node's who's type can not be determined


      {Enum used for easily identifying nodes}
   eNodeType = (ntUnknown,  ntRoot,  ntFile,  ntFolder);


Here is the function that determines what type of node we're working with


   //////////////////////////////////////////////////////////////
   // Returns one of the eNodeType values to indicate what type
   //  of node param 1 is.
   //////////////////////////////////////////////////////////////
   function TForm1.GetNodeType(  Node : TTreeNode  ) : eNodeType;
   begin
      if(  Node = nil  ) then
      begin
         Result := ntUnknown;
         Exit;
      end;

         {Determine what type of node this is by looking at the
           node's ImageIndex}
      case Node.ImageIndex of
         IMG_NODE_ROOT : Result := ntRoot;
         IMG_NODE_FILE_CLOSED : Result := ntFile;
         IMG_NODE_FOLDER_CLOSED : Result := ntFolder;
      else
            {Node should be one of the above...}
         Result := ntUnknown;
      end;
   end;


Example 5's form looks like this

Control Caption Name
TTreeView   tv_eg1
TButton Add Folder but_AddFolder
TButton Add File but_AddFile
TButton Remove but_Remove
TImageList   ImageList1


As you can see the buttons are labeled "but_AddFolder" and "but_AddFile". So when, you might ask, do we add the root node? In the OnCreate event...


   procedure TForm1.FormCreate(Sender: TObject);
   begin
         {Add the root node}
      AddRootNode;
   end;



   ///////////////////////////////////
   // Adds the root to an empty tree
   ///////////////////////////////////
   procedure TForm1.AddRootNode;
   begin
         {If the tree is empty}
      if(  tv_eg5.Items.Count = 0  ) then
      begin
            {Add the root node}
         with tv_eg5.Items.AddFirst(  nil,  'Root'  ) do
         begin
            Selected := true;

               {Set the roots image index}
            ImageIndex := IMG_NODE_ROOT;
               {Set the roots selected index. The same image is uses
                  as for the ImageIndex}
            SelectedIndex := IMG_NODE_ROOT;
         end;
      end
   end;


Before adding nodes lets create a function that will check if a node may be added to any given parent. ie A function that checks the node's type and position against the "rules"


   ///////////////////////////////////////////////////////
   // Check if a new node of type NewNodeType may be
   //   created as a child off ParentNode
   ///////////////////////////////////////////////////////
   function TForm1.IsNodeAllowed(  ParentNode : TTreeNode;
                                   NewNodesType : eNodeType
                                 ) : boolean;
   begin
      case GetNodeType(  ParentNode  ) of
         ntRoot :
         begin
               {A root may contain any type of node}
            Result := true;
         end;

         ntFolder :
         begin
               {Folder may contain any type of node}
            Result := true;
         end;

         ntFile :
         begin;
               {Files may have no sub-items}
            Result := false;
         end;
      else
            {Unknown node type, dont allow any operations}
         Result := false;
      end;
   end;


And finally the procedure to add a new node



   ///////////////////////////////////////////////////
   // Procedure used to add a file / folder node
   ///////////////////////////////////////////////////
   procedure TForm1.AddNode(  NodeType : eNodeType  );
   var
      sText : string;
   begin
         {If nothing is selected}
      if(  tv_eg5.Selected = nil  ) then
      begin
            {There is a root, so user must first select a node}
         MessageBeep(  -1  );
         ShowMessage(  'Select parent node'  );
         Exit;
      end
      else begin
            {Get a name for the new node}
         if(   not InputQuery(  'New Node',  'Caption ?',  sText  )   ) then
            Exit;

            {Check if this name is already in use}
         if(   IsDuplicateName(  tv_eg5.Selected.GetFirstChild,
                                 sText,
                                 true
                               )
            ) then
         begin
            MessageBeep(  -1  );
            ShowMessage(  'A node with this name already exists'  );
            Exit;
         end;

            {Check if adding this type of node is allowed}
         if(   not IsNodeAllowed(  tv_eg5.Selected,  NodeType  )   ) then
         begin
            MessageBeep(  -1  );
            ShowMessage(  'Cant creat this type of node here'  );
            Exit;
         end;

            {Add the node}
         with tv_eg5.Items.AddChildFirst(  tv_eg5.Selected,  sText  ) do
         begin
            case NodeType of
               ntFolder :
               begin
                     {Set the image used when the node is not selected}
                  ImageIndex := IMG_NODE_FOLDER_CLOSED;
                     {Image used when the node is selected}
                  SelectedIndex := IMG_NODE_FOLDER_OPEN;
                  MakeVisible;
               end;

               ntFile :
               begin
                     {Set the image used when the node is not selected}
                  ImageIndex := IMG_NODE_FILE_CLOSED;
                     {Image used when the node is selected}
                  SelectedIndex := IMG_NODE_FILE_OPEN;
                  MakeVisible;
               end;
            else
                  {Trying to add a node that is not a file or a folder,
                    this is not allowed. So remove the node that was
                    just created.}
               Delete;
            end;
         end;
      end;
   end;


As you can see this procedure is quite differant from the one in example 1. However the underlying ideas are exactly the same. There is additional checking, and "rule" enforcement.

Well thats example 5. The next few examples will be based on this one, so understanding how this example works is well worth the time.






All information on these www pages is copyright (©) 1997 Andre .v.d. Merwe And may not be copied or mirrored without my permission.