TreeView項目のD&D移動
こちらの掲示板の話題です。
使用するイベントは、TreeViewのOnDragDrop,OnDragOver,OnMouseDown,OnStartDragの4つです。
usesにWinapi.CommCtrl(XE以前の場合はCommCtrl)を追加。
項目の移動先が下記のように表示されます。移動先の表示はTVM_SETINSERTMARKメッセージをTreeViewに送る事で実現しています。
TVM_SETINSERTMARKCOLORメッセージで色を変えることも出来るようですが試していません。
TForm1 = class(TForm) TreeView1: TTreeView; procedure TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer); procedure TreeView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure TreeView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure TreeView1StartDrag(Sender: TObject; var DragObject: TDragObject); private FDragNode: TTreeNode; FDragMode: Integer; public end; procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer); var Node: TTreeNode; begin Node := (Sender as TTreeView).DropTarget; if Assigned(Node) And Assigned(FDragNode) then begin if FDragMode = 1 then begin // 子の一番最後に移動 FDragNode.MoveTo(Node, naAddChild); end else if FDragMode = 2 then begin // ターゲットの前に同レベルのアイテムとして移動 FDragNode.MoveTo(Node, naInsert); end else if FDragMode = 3 then begin // ターゲットの同レベル次のアイテムがあればそのアイテムの前に移動 // 無ければ同レベルの最後に移動 Node := Node.getNextSibling; if Assigned(Node) then begin FDragNode.MoveTo(Node, naInsert); end else begin Node := (Sender as TTreeView).DropTarget; FDragNode.MoveTo(Node, naAdd); end; end; // ドロップ処理が終わったら挿入マークを消す SendMessage((Sender as TTreeView).Handle, TVM_SETINSERTMARK, 1, 0); end; end; procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var Node: TTreeNode; DragM: Integer; rc: TRect; ht: THitTests; begin Node := (Sender as TTreeView).GetNodeAt(X, Y); Accept := (Sender = Source) And Assigned(Node) And (Node <> FDragNode); if Accept then begin ht := (Sender as TTreeView).GetHitTestInfoAt(X, Y); if htOnLabel in ht then begin DragM := 1; end else begin rc := Node.DisplayRect(False); InflateRect(rc, -1, -1); if (rc.Top + rc.Bottom) div 2 > Y then begin DragM := 2; end else begin DragM := 3; end; end; if DragM = 1 then begin // 子に追加するので挿入マークを消す SendMessage((Sender as TTreeView).Handle, TVM_SETINSERTMARK, 1, 0); end else if DragM = 2 then begin // ターゲットの上側に挿入マークを表示 SendMessage((Sender as TTreeView).Handle, TVM_SETINSERTMARK, 0, LPARAM(Node.ItemId)); end else if DragM = 3 then begin // ターゲットの下側に挿入マークを表示 SendMessage((Sender as TTreeView).Handle, TVM_SETINSERTMARK, 1, LPARAM(Node.ItemId)); end; FDragMode := DragM; end else begin SendMessage((Sender as TTreeView).Handle, TVM_SETINSERTMARK, 1, 0); FDragMode := 0; end; end; procedure TForm1.TreeView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Node: TTreeNode; begin if Button = mbLeft then begin FDragNode := (Sender as TTreeView).GetNodeAt(X, Y); (Sender as TTreeView).BeginDrag(False, 5); end; end; procedure TForm1.TreeView1StartDrag(Sender: TObject; var DragObject: TDragObject); begin FDragMode := 0; end;