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.