Delphi TTreeViewの使い方|階層ツリー表示・ノード操作・ドラッグ&ドロップ実装
このページでは、DelphiのTTreeViewコンポーネントを使って階層構造のツリー表示を行う方法を解説します。
TTreeNodeの追加・展開・並び替えに加え、ノードのドラッグ&ドロップ移動やShiftキーによる兄弟・子ノード制御など、実用的な操作をサンプルコード付きで紹介します。
以下のようにTTreeView×1個(TreeView1)とTButton×1個(Button1)があるフォームでButton1をクリックした時にTreeView1を操作するソースコードを記述します。
プロジェクトとユニットの保存(「すべて保存」ボタンをクリック)しておきます。(自動的に必要なユニットがUsesに記述されます)
Button1をクリックした時のイベント
Button1をクリックして選択し、左下ペインの「オブジェクトインスペクタ」にあるタブ「イベント」をクリックして切り替えます。
「OnClick」をダブルクリックするとクリックした時のイベントのひな形が生成されますのでソースコードを記述します。
Button1をクリックした時にTreeView1にアイテムを追加するソースコードの記述
以下ソースコードを入力します
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls;
type
TForm1 = class(TForm)
TreeView1: TTreeView;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var root1,root2,child:TTreeNode;
begin
//全てのツリーノードを削除
TreeView1.Items.Clear;
//TreeView1.Items.AddChild(親ノード,子ノード)メソッドは
//指定した親ノードの子ノードとしてその階層内の最後(一番下)に追加します
//親ノードを「nil」で指定するとルートノードとして追加されます
root2:=TreeView1.Items.AddChild(nil,'ルート2');
//親ノード「root2」の子ノードを追加
TreeView1.Items.AddChild(root2,'子ノード21');
//親ノード「root2」の子ノードを追加
child:=TreeView1.Items.AddChild(root2,'子ノード22');
//「child」の子ノードを追加
TreeView1.Items.AddChild(child,'子ノード222');
//「child」の子ノードを追加
TreeView1.Items.AddChild(child,'子ノード221');
//親ノードを「nil」で指定するとルートノードとして追加されます
root1:=TreeView1.Items.AddChild(nil,'ルート1');
//「root1」の子ノードを追加
TreeView1.Items.AddChild(root1,'子ノード11');
//「root1」の子ノードを追加
TreeView1.Items.AddChild(root1,'子ノード12');
//TTreeNode.Expand(Recurse) は下位ノードを展開します
//RecurseがFalseの場合は子ノードのみ展開し
//Trueの場合は全ての下位ノードを展開します
root1.Expand(True);
root2.Expand(True);
end;
end.
実行
実行してButton1をクリックするとTreeView1にノードが追加され展開されます
ソートする
以下ソースコードを1行追加するとノードがソートされます。
procedure TForm1.Button1Click(Sender: TObject);
var root1,root2,child:TTreeNode;
begin
//全てのツリーノードを削除
TreeView1.Items.Clear;
//TreeView1.Items.AddChild(親ノード,子ノード)メソッドは
//指定した親ノードの子ノードとしてその階層内の最後(一番下)に追加します
//親ノードを「nil」で指定するとルートノードとして追加されます
root2:=TreeView1.Items.AddChild(nil,'ルート2');
//親ノード「root2」の子ノードを追加
TreeView1.Items.AddChild(root2,'子ノード21');
//親ノード「root2」の子ノードを追加
child:=TreeView1.Items.AddChild(root2,'子ノード22');
//「child」の子ノードを追加
TreeView1.Items.AddChild(child,'子ノード222');
//「child」の子ノードを追加
TreeView1.Items.AddChild(child,'子ノード221');
//親ノードを「nil」で指定するとルートノードとして追加されます
root1:=TreeView1.Items.AddChild(nil,'ルート1');
//「root1」の子ノードを追加
TreeView1.Items.AddChild(root1,'子ノード11');
//「root1」の子ノードを追加
TreeView1.Items.AddChild(root1,'子ノード12');
//TTreeNode.Expand(Recurse) は下位ノードを展開します
//RecurseがFalseの場合は子ノードのみ展開し
//Trueの場合は全ての下位ノードを展開します
root1.Expand(True);
root2.Expand(True);
//ソートする
TreeView1.SortType:=TSortType.stText;
end;
end.
ノードをドラッグ&ドロップで移動できるようにする
TreeView1.DragModeプロパティを「TDragMode.dmAutomatic」に設定するとドラッグできるようになります。
イベントTreeView1.OnDragDropとTreeView1.DragOverとTreeView1.OnEndDragに応答すればドロップ処理できます。
ドロップ時にドロップ先の子ノードとしてノードを移動させます。
SHIFTキーを押しながらドロップするとドロップ先の兄弟ノードとしてノードを移動させます。
また、ノードのドラッグオーバー時にTreeView1の上下20ピクセルの位置にマウスを移動した時に自動でスクロールさせたいのでフォームにTTimerをドラッグ&ドロップします。
実行してButton1をクリックすると多くのノードが表示され、ノードのドラッグ&ドロップができます。
以下ソースコードを記述します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
TreeView1: TTreeView;
Button1: TButton;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure TreeView1EndDrag(Sender, Target: TObject; X, Y: Integer);
procedure TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure Timer1Timer(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var root1,root2,child:TTreeNode;
i:Integer;
begin
//全てのツリーノードを削除
TreeView1.Items.Clear;
//AddChild(親ノード,子ノード)メソッドは
//指定した親ノードの子ノードとして最後に追加します
//親ノードを「nil」で指定するとルートノードとして追加されます
root2:=TreeView1.Items.AddChild(nil,'ルート2');
//親ノード「root2」の子ノードを追加
TreeView1.Items.AddChild(root2,'子ノード21');
//親ノード「root2」の子ノードを追加
child:=TreeView1.Items.AddChild(root2,'子ノード22');
//「child」の子ノードを追加
TreeView1.Items.AddChild(child,'子ノード222');
//「child」の子ノードを追加
TreeView1.Items.AddChild(child,'子ノード221');
//親ノードを「nil」で指定するとルートノードとして追加されます
root1:=TreeView1.Items.AddChild(nil,'ルート1');
//「root1」の子ノードを追加
TreeView1.Items.AddChild(root1,'子ノード11');
//「root1」の子ノードを追加
TreeView1.Items.AddChild(root1,'子ノード12');
//TTreeNode.Expand(Recurse) は下位ノードを展開します
//RecurseがFalseの場合は子ノードのみ展開し
//Trueの場合は全ての下位ノードを展開します
root1.Expand(True);
root2.Expand(True);
//たくさんノードを入れる
for i := 0 to 99 do
begin
TreeView1.Items.AddChild(nil,IntToStr(i));
end;
//ソートする
TreeView1.SortType:=TSortType.stText;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//ドラッグを有効にする
TreeView1.DragMode:=TDragMode.dmAutomatic;
//スクロール用タイマー
Timer1.Enabled:=False;
Timer1.Interval:=50;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if TreeView1.Tag<0 then
//上に1行スクロール
SendMessage(TreeView1.Handle,WM_VSCROLL,SB_LINEUP,0)
else if TreeView1.Tag>0 then
//下に1行スクロール
SendMessage(TreeView1.Handle,WM_VSCROLL,SB_LINEDOWN,0);
end;
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
var o:TObject;
k:SmallInt;
begin
//ドロップされたときの処理
o:=TreeView1.GetNodeAt(X,Y);
if o is TTreeNode then
begin
k:=GetKeyState(VK_SHIFT);
if k<0 then
begin
//シフトキーが押されてドロップ(子ノードとして移動する)
TTreeView(Sender).Selected.MoveTo(
TTreeView(Sender).DropTarget, //ドロップ先オブジェクト
TNodeAttachMode.naAddFirst//ドロップ先の最初の子ノードとして移動
);
end
else
begin
//シフトキーが押されずにドロップ(兄弟ノードとして移動する)
TTreeView(Sender).Selected.MoveTo(
TTreeView(Sender).DropTarget, //ドロップ先オブジェクト
TNodeAttachMode.naAddChildFirst//ドロップ先の最初の兄弟ノードとして移動
);
end;
end;
end;
procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
var o:TObject;
begin
//ドラッグオーバー時
Accept:=False;
if (Source is TTreeView) then
begin
//ドラッグオーバー時のマウスの座標の下がTTreeNodeか確認
o:=TreeView1.GetNodeAt(X,Y);
if o is TTreeNode then
Accept:=True; //ドロップの許可
end;
//スクロール処理用のタイマーを有効にする
if Y<20 then
begin
//TreeView1の上部にマウスがあると上にスクロールしたい
TreeView1.Tag := -1;
Timer1.Enabled := True;
end
else if Y>=(TTreeView(Sender).ClientHeight-20) then
begin
//TreeView1の下部にマウスがあると下にスクロールしたい
TreeView1.Tag := 1;
Timer1.Enabled := True;
end
else
begin
TreeView1.Tag := 0;
Timer1.Enabled := False;
end;
end;
procedure TForm1.TreeView1EndDrag(Sender, Target: TObject; X, Y: Integer);
begin
//ドラッグ&ドロップ処理終了、又はドラッグ中に「ESC」キーを押してキャンセルされたとき
Timer1.Enabled:=False;
TreeView1.Tag:=0;
end;
end.
