OnDragOver处理是否允许放下:
01.procedure TMainForm.TreeViewDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
02.var
03. TargetNode, SourceNode: TTreeNode;
04.begin
05. Accept := False;
06. TargetNode := TTreeView(Sender).GetNodeAt(X, Y);
07. if (Source = Sender) and (TargetNode <> nil) then
08. begin
09. Accept := True;
10. SourceNode := TTreeView(Sender).Selected;
11. if TargetNode = SourceNode.Parent then
12. Accept := False;
13. if Accept then
14. begin
15. while (TargetNode.Parent <> nil) and (TargetNode <> SourceNode) do
16. TargetNode := TargetNode.Parent;
17. if TargetNode = SourceNode then
18. Accept := False;
19. end;
20. end;
21.end;
OnDragDrop是放下后节点的处理方法:
01.procedure TMainForm.TreeViewDragDrop(Sender, Source: TObject; X, Y: Integer);
02.var
03. TargetNode, SourceNode: TTreeNode;
04.begin
05. TargetNode := TTreeView(Sender).GetNodeAt(X, Y);
06. if TargetNode <> nil then
07. begin
08. SourceNode := TTreeView(Sender).Selected;
09. TTreeView(Sender).Items.BeginUpdate;
10. SourceNode.MoveTo(TargetNode, naAddChildFirst);
11. TTreeView(Sender).Selected := SourceNode;
12. TTreeView(Sender).Items.EndUpdate;
13. end;
14.end;
另外TreeView本身还需要设定支持拖放,俩个方法:
1: 静态设定TreeView可以拖放
procedure TMainForm.FormCreate(Sender: TObject);
begin
TreeView.DragMode := dmAutomatic;
end;
2: 通过事件动态设定
01.procedure TMainForm.TreeViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
02.begin
03. if (Button = mbLeft) and (htOnItem in TTreeView(Sender).GetHitTestInfoAt(X, Y)) then //判断是左键并且点击在Item上
04. begin
05. if (ssCtrl in Shift) then //如果按下了Ctrl键
06. TTreeView(Sender).BeginDrag(False); //允许拖放
07. end;
08.end;
////////////////////////////////////////////////////////////////////
procedure TfrmMain.TreeView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var node: TTreeNode; begin node := TreeView1.GetNodeAt(X, Y); // 获取鼠标按下位置的节点 if (node <> nil) and (node.Level > 0) and (Button = mbLeft) then TreeView1.BeginDrag(True); // 启动拖动 end;
需要注意的是,TreeView 控件的 DragMode 要设置为 dmManual,才会需要执行 BeginDrag 手工启动拖动。DragMode 的缺省值就是 dmManual。
接下来就是 OnDargOver 事件。
procedure TfrmMain.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var node: TTreeNode; begin node := TreeView1.GetNodeAt(X, Y); // node.Level 是节点的层级,等于0时,表示是根节点(没有上级节点了) // 本语句控制只能将节点拖动到与父节点平级的其他节点上,Accept表示,是否可释放 if (node <> nil) and (node.Level = 0) and (TreeView1.Selected.Parent <> node) then Accept := True else Accept := False; end;
最后是实现 OnDragDrop 事件,此事件里就要写上与业务相关的代码了。
procedure TfrmMain.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer); var node: TTreeNode; begin node := TreeView1.GetNodeAt(X, Y); if (node <> nil) and (node.Level = 0) then begin // 此处用到了StateIndex,只是在生成TreeView的时候,将每条记录的主键值储存到了这里,并不代表StateIndex的实际意义 Query1.SQL.Text := 'update sys_config set class_id=' + IntToStr(node.StateIndex) + ' where cid=' + IntToStr(TreeView1.Selected.StateIndex); if Query1.ExecSQL() > 0 then TreeView1.Selected.MoveTo(node, naAddChild); // 将节点移动到目标节点的下一级,也就是使目标节点成为被拖动节点的父节点 end; end;