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;