TreeView Drag drop delphi・・・このキーワードでここに来られる方がおられます。以前に .NET(Windowsフォームアプリケーション)での処理を書いていますので、それが該当するんでしょうね。
でもおそらくWIN32での処理をお探しだと思いますので、その処理を書きたいと思います。
簡単に説明すると「TreeView1.OnDragDropで Node の Selected、DropTarget、MoveTo を使って処理するだけです。」と書いてしまえばいいんでしょうが、せっかくなので縮小ノードの展開及び非表示部分のスクロール処理、並びにターゲットの選択部分によるノードの移動処理を含めたサンプルにしたいと思います。
でもTreeViewは奥深いので、Node.DataやOnChange等が原因で様々な問題が起こります。又、DragModeをdmAutomaticで使うとクリックしたかっただけなのに、ノード移動させてしまったという問題も比較的よく起こります。くれぐれもご注意を(笑)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, ImgList, ExtCtrls;
type
TForm1 = class(TForm)
TreeView1: TTreeView;
ImageList1: TImageList;
Timer1: TTimer;
Timer2: TTimer;
procedure FormCreate(Sender: TObject);
procedure TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure TreeView1EndDrag(Sender, Target: TObject; X, Y: Integer);
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//テスト用アイコン作成
procedure MakeTestIcon(ImageList: TImageList);
var
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.Height := 16;
Bitmap.Width := 16;
Bitmap.Canvas.Brush.Color := clRed;
Bitmap.Canvas.FillRect(Rect(2,2,14,14));
ImageList.Add(Bitmap,nil);
Bitmap.Canvas.Brush.Color := clBlue;
Bitmap.Canvas.FillRect(Rect(2,2,14,14));
ImageList.Add(Bitmap,nil);
finally
Bitmap.Free;
end;
end;
// 初期設定いろいろ
procedure TForm1.FormCreate(Sender: TObject);
const
FileName = 'data.txt';
var
Node: TTreeNode;
Path: String;
begin
// 展開用タイマー設定
Timer1.Enabled := False;
Timer1.Interval := 1500;
// スクロール用タイマー設定
Timer2.Enabled := False;
Timer2.Interval := 50;
// アイコンの作成
MakeTestIcon(ImageList1);
// TreeView1の設定
TreeView1.Images := ImageList1;
TreeView1.ReadOnly := True;
TreeView1.DragMode := dmAutomatic;
TreeView1.Height := 150;
// データの読み込み
Path := ExtractFilePath(Application.ExeName);
TreeView1.LoadFromFile(Path + FileName);
Node := TreeView1.Items.GetFirstNode;
repeat
Node.ImageIndex := 1;
Node.StateIndex := 2;
Node := Node.GetNext;
until Node = nil;
// スクロールの際、ごみが出るから(^^;
TreeView1.ControlStyle := TreeView1.ControlStyle - [csDisplayDragImage];
end;
var
ScrollBarCommand: Integer;
procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
function IsSelfOrMyChild(dtNode, slNode: TTreeNode): Boolean;
begin
Result := False;
while (dtNode <> nil) do
begin
if (slNode = dtNode) then
begin
Result := True;
Exit;
end;
dtNode := dtNode.Parent;
end;
end;
const
Offset = 20;
var
slNode, dtNode: TTreeNode;
begin
slNode := TreeView1.Selected;
dtNode := TreeView1.DropTarget;
Accept := ((Sender as TTreeView) = (Source as TTreeView)) and
(not IsSelfOrMyChild(dtNode, slNode));
if not Accept then Exit;
// ノードを展開させます。
if (dtNode <> nil) then
begin
if Timer1.Enabled and (Timer1.Tag <> dtNode.AbsoluteIndex) then
Timer1.Enabled := False;
if (not dtNode.Expanded) and dtNode.HasChildren then
begin
Timer1.Tag := dtNode.AbsoluteIndex;
Timer1.Enabled := True;
end;
end;
// 表示されていない部分をスクロールさせます。
if (Y < Offset) or (Y >= TreeView1.ClientHeight - Offset) then
begin
if (Y < Offset) then
ScrollBarCommand := SB_LINEUP
else
ScrollBarCommand := SB_LINEDOWN;
Timer2.Enabled := True;
end
else
begin
ScrollBarCommand := -1;
Timer2.Enabled := False;
end;
end;
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
srcNode, dstNode: TTreeNode;
HT: THitTests;
begin
// Explorer等は、ファイル名でソートされていますが、
// ソートではなく意図したノードの順番に移動させたい場合があります。
// そのような時に私のアプリでは、
// アイコンで挿入移動、文字列で子追加移動という仕様にしています。
// これって結構便利だと思うんですけど、あまり採用されてないみたい。
srcNode :=TreeView1.Selected; // 選択ノード
dstNode := TreeView1.DropTarget; // ドロップターゲットノード
HT := TreeView1.GetHitTestInfoAt(X, Y);
if (htOnIcon in HT) then
srcNode.MoveTo(dstNode, naInsert) // アイコンを選択している場合
else
srcNode.MoveTo(dstNode, naAddChild); // 項目を選択している場合
end;
procedure TForm1.TreeView1EndDrag(Sender, Target: TObject; X, Y: Integer);
begin
ScrollBarCommand := -1;
Timer1.Enabled := False;
Timer2.Enabled := False;
end;
// 閉じているノードを展開させます。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
TreeView1.Items[Timer1.Tag].Expanded := True;
Timer1.Enabled := False;
end;
// スクロールさせます。
procedure TForm1.Timer2Timer(Sender: TObject);
begin
if (ScrollBarCommand > -1) then
SendMessage(TreeView1.Handle, WM_VSCROLL, ScrollBarCommand, 0);
end;
end.
プログラムと同じフォルダに、下記の内容を書き込んだテキストファイルを作成して下さい。
ファイル名は、data.txtです。
node-01
node-02
node-03
node-04
node-05
node-06
node-07
node-08
node-09
node-10
node-11
node-12
node-13
node-14
node-15
node-16
node-17
node-18
node-19
node-20
node-21
node-22
node-23