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.