I want to allow the user to arrange a treeView's nodes as he likes, but I am running into a lot of problems. Like for example:
That's not good. I want a behavior like in this picture
So the destination of the Node3, should be between Node1 and Node2. Of course the drop ON TOP of a node should be available, but this BETWEEN NODES functionality should be available too.
My code so far is:
procedure TForm3.FormCreate(Sender: TObject);
begin
tv.FullExpand;
end;
procedure TForm3.tvDragDrop(Sender, Source: TObject; X, Y: Integer);
var
TargetNode, SourceNode : TTreeNode;
begin
with TV do
begin
TargetNode := GetNodeAt(X,Y); // Get target node
SourceNode := Selected;
if (TargetNode = nil) then
begin
EndDrag(False);
Exit;
end;
MoveNode(TargetNode,SourceNode);
SourceNode.Free;
end;
end;
procedure TForm3.tvDragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
if (Sender = TV) then // If TRUE than accept the draged item
begin
Accept := True;
end;
end;
procedure TForm3.tvEndDrag(Sender, Target: TObject; X, Y: Integer);
begin
TV.Repaint;
end;
procedure TForm3.tvMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
tv.BeginDrag(false,-1);
end;
Procedure TForm3.MoveNode(TargetNode, SourceNode : TTreeNode);
var
nodeTmp : TTreeNode;
i : Integer;
begin
with TV do
begin
nodeTmp := Items.AddChild(TargetNode,SourceNode.Text);
for i := 0 to SourceNode.Count -1 do
begin
MoveNode(nodeTmp,SourceNode.Item[i]);
end;
end;
end;
where of course TV is a TTreeView.
First of all, throw away all the code that you currently have. It's got too many flaws to make it worthwhile discussing.
The minimum code needed for this is as follows:
procedure TMyForm.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
Src, Dst: TTreeNode;
begin
Src := TreeView1.Selected;
Dst := TreeView1.GetNodeAt(X,Y);
Src.MoveTo(Dst, naAdd);
end;
procedure TMyForm.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
var
Src, Dst: TTreeNode;
begin
Src := TreeView1.Selected;
Dst := TreeView1.GetNodeAt(X,Y);
Accept := Assigned(Dst) and (Src<>Dst);
end;
You need to set DragMode
to dmAutomatic
for the tree view. And you also need to hook up the two events to OnDragDrop
and OnDragOver
.
If you wish to implement different logic in the drop to handle adding as a sibling (before or after), or adding as a child, pass a different value for the second parameter of MoveTo
.
The possibilities are listed here:
type
TNodeAttachMode = (naAdd, naAddFirst, naAddChild, naAddChildFirst, naInsert);
These options are described in the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With