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


Drag and Drop


First a clarification, Drag and Drop here refers to drag and drop within the TreeView, or from the TreeView to another control within the same application. This tutorial does not cover drag and drop between applications, eg to/from Explorer. That has more to do with OLE than it does TreeViews.

This example is based on example 10 and there are thus file and folder nodes as well as a root node. Take a look at the "rules" for this TreeView (example 10). These rules must be kept when nodes are dragged.

The OnDragOver event is called when something (on this case a TreeNode) is dragged over a control (a TTreeView). You must indicate if the dragged item may be dropped at the current position.


   procedure TForm1.tv_eg5DragOver(Sender, Source: TObject; X, Y: Integer;  State: TDragState; var Accept: Boolean);
   begin
   /////////////////////////////////////////
   // Decide if drag-drop is to be allowed
   /////////////////////////////////////////

      Accept := false;

         {Only accept drag and drop from a TTreeView}
      if(  Sender is TTreeView  ) then
            {Only accept from self}
         if(  TTreeView(Sender) = tv_eg5  ) then
            Accept := true;
   end;
  1. Assume fail
  2. If the source is a TreeView
  3. If dragging internally ie tv_eg5 to ev_eg5
  4. Allow drag-drop



The OnDragDrop event is called once an item is dropped on the TTreeView. This is a rather long function so a outline of the procedure will help clarify what exactly it does.

  1. Get the target node (the node that the item was dropped on)
  2. Get an alias for the source node. This makes the source easier to read
  3. Make sure the Target is a valid node
  4. Can the target node accept the source node
    1. Cant drop onto self, or drop onto immediate parent
    2. May not drag the root
    3. Cant drop a parent onto a child
    4. May not drop if an item with the same names as the source already exists
  5. Check the rules - IsNodeAllowed
  6. Copy the node
  7. Delete old node (Copy + Delete = move)
  8. Display node in its new position


   procedure TForm1.tv_eg5DragDrop(Sender, Source: TObject; X, Y: Integer);
   var
      TargetNode : TTreeNode;
      SourceNode : TTreeNode;
   begin
   /////////////////////////////////////////
   // Somthing has just been droped
   /////////////////////////////////////////

      with tv_eg5 do
      begin
            {Get the node the item was dropped on}
         TargetNode := GetNodeAt(  X,  Y  );
            {Just to make things a bit easier}
         SourceNode := Selected;


            {Make sure somthing was droped onto}
         if(  TargetNode = nil  ) then
         begin
            EndDrag(  false  );
            Exit;
         end;

            {Dropping onto self or onto parent?}
         if(  (TargetNode = Selected) or
              (TargetNode = Selected.Parent)
           ) then
         begin
            MessageBeep(  MB_ICONEXCLAMATION  );
            ShowMessage(  'Destination node is the same as the source node'  );
            EndDrag(  false  );
            Exit;
         end;

            {No drag-drop of the root allowed}
         if(  SourceNode.Level = 0  ) then
         begin
            MessageBeep(  MB_ICONEXCLAMATION  );
            ShowMessage(  'Cant drag/drop the root'  );
            EndDrag(  false  );
            Exit;
         end;

            {Can't drop a parent onto a child}
         if(   IsAParentNode(  Selected,  TargetNode  )   ) then
         begin
            MessageBeep(  MB_ICONEXCLAMATION  );
            ShowMessage(  'Cant drop parent onto child'  );
            EndDrag(  false  );
            Exit;
         end;

            {Does a node with this name exists as a child of TargetNde}
         if(   IsDuplicateName(  TargetNode.GetFirstChild,  SourceNode.Text,  true  )   ) then
         begin
            MessageBeep(  MB_ICONEXCLAMATION  );
            ShowMessage(  'A node with this name already exists'  );
            EndDrag(  false  );
            Exit;
         end;

         //////////////////////////////////////////////////////////////
         // Nothing differant up to here.  Just the normal drag and
         //   drop checking.  Now the code to make sure that enforce
         //   "the rules".  Eg books may contain no sub-nodes
         //////////////////////////////////////////////////////////////
   
            {Use the IsNodeAllowed function to test if the node
              may be dropped here}
         if(  not IsNodeAllowed(   TargetNode,
                                   GetNodeType(  SourceNode  )
                                 )
            ) then
         begin
            MessageBeep(  -1  );
            ShowMessage(  'You cant drop this type of node here!'  );
            EndDrag(  false  );
            Exit;
         end;


            {Drag drop was valid so move the nodes}
         MoveTreeNode(  tv_eg5,  SourceNode,  TargetNode  );

            {Delete the old node}
         SourceNode.Delete;


            {Show the nodes that were just moved}
         TargetNode.Expand(  true  );
      end;
   end;


Drag and Drop between a TreeView and its linked ListView (eg 12) is a bit more difficult. Although not that much more...
Use a function that works similarly to the OnDragDrop function above, but TargetNode and SourceNode are passed as parameters

Then...
TreeView to ListView Get the ListItem the TreeNode was dropped onto. Get the TreeNode that this ListItem is linked to and use it as the TargetNode.
ListView.TreeView Get dragged TreeItem, get linked TreeNode use this as SourceNode
ListView to ListView Get source and target ListItems, get linked Source and Target TreeNodes. Call function

I've not actually implemented this, but with the examples in this tutorial you should be able to get this working without too much trouble.






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