まず VT でドラッグ&ドロップさせるためにはプロパティで以下の設定が必要になります。これを設定しないとうんともすんとも言いません。
[delphi]
DragMode = dmAutomatic
DragType = dtVCL
[/delphi]
主要なイベントハンドラは OnDragDrop と OnDragOver で、
OnDragDrop は、ドロップされた後に呼び出され、ここでノードの移動等を処理をします(自答ではやってくれません)。
処理としてはたぶんこれでいいと思うんですが、
不明(dmNowhere) な場合は処理させない(amNoWhere)。
ドロップ先がノード(dmOnNode) の場合は子ツリーの最後へ(amAddChildLast)。
横棒の上ノード(dmBelow)のすぐ下へ(amInsertAfter)。
横棒の下ノード(dmAbove)のすぐ上へ(amInsertBefore)。
としています。
OnDragOver は、ドラッグ中にマウスが移動するごとに呼び出され、ここでドロップ可能かの正否を判断して返します。
サンプルでは、単純に同じコントロール、自分自身ではない、不明な場所ではない、の条件で判断しています。
メソッドしては、BuildTree と RestructItem があります。
BuildTree は、TItem から VT のツリーを構築します。
RestructItem は逆に VT のツリーから TItem を再構築します。
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ActiveX,
VirtualTrees;
type
TItem = class
public
fID: integer;
fChild: TList;
constructor Create(aID: INTEGER);
end;
TForm3 = class(TForm)
VT: TVirtualStringTree;
BuildBtn: TButton;
RestructBtn: TButton;
///
/// ドロップ処理。
///
procedure VTDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject; Formats:
TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: INTEGER; Mode: TDropMode);
///
/// ドロップ可能かの判断を行う。 以下の条件の場合にのみドロップ可能。
///
/// -
/// 同じコントロール。
///
/// -
/// ドラッグ先がドロップ元でない。
///
/// -
/// ドラッグ先が不明でない。
///
///
///
procedure VTDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState; Pt:
TPoint; Mode: TDropMode; var Effect: INTEGER; var Accept: BOOLEAN);
///
/// ノードのテキストを返す。
///
procedure VTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType:
TVSTTextType; var CellText: STRING);
///
/// VT のツリーをクリアして、fRootItem のツリーを VT に構築させるコマンド。
///
procedure BuildBtnClick(Sender: TObject);
///
/// VT のツリーから TItem のツリーを再構築して VT のツリーをクリアさせるコマンド。
///
procedure RestructBtnClick(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
protected
fRootItem: TItem; // 何らかのツリーリスト
///
/// ツリーの構築。
///
procedure BuildTree(aRootItem: TItem);
procedure RestructItem(aRootItem: TItem);
end;
var Form3: TForm3;
implementation
{$R *.dfm}
constructor TItem.Create(aID: INTEGER);
begin
fID := aID;
fChild := TList.Create;
end;
constructor TForm3.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
VT.NodeDataSize := SizeOf(TObject);
BuildBtnClick(Self);
end;
procedure TForm3.VTDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject; Formats:
TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: INTEGER; Mode: TDropMode);
var am: TVTNodeAttachMode;
begin
inherited;
case Mode of
dmNowhere: am := amNoWhere; // ターゲットが不明。
dmAbove: am := amInsertBefore; // ターゲットは横棒(下向き)の下のノード。
dmOnNode: am := amAddChildLast; // ターゲットがノード。
dmBelow: am := amInsertAfter; // ターゲットは横棒(上向き)の上のノード
end;
Sender.MoveTo(Sender.FocusedNode, Sender.DropTargetNode, am, false);
end;
procedure TForm3.VTDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
Pt: TPoint; Mode: TDropMode; var Effect: INTEGER; var Accept: BOOLEAN);
begin
Accept := (Sender = Source) and (Sender.FocusedNode <> Sender.DropTargetNode) and (Mode <> dmNowhere);
end;
procedure TForm3.VTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType:
TVSTTextType; var CellText: STRING);
var item: TItem;
begin
item := TItem(VT.GetNodeData(Node)^);
CellText := IntToStr(item.fID);
end;
procedure TForm3.BuildTree(aRootItem: TItem);
procedure SetItem(aItem: TItem; aNode: PVirtualNode);
var a: INTEGER;
n: PVirtualNode;
begin
for a := 0 to aItem.fChild.Count - 1 do begin
n := VT.AddChild(aNode, aItem.fChild[a]);
Include(n^.States, vsExpanded);
SetItem(aItem.fChild[a], n);
end;
end;
begin
SetItem(aRootItem, VT.RootNode);
end;
procedure TForm3.RestructItem(aRootItem: TItem);
procedure GetItem(aItem: TItem; aNode: PVirtualNode);
var item: TItem;
begin
aItem.fChild.Clear;
aNode := aNode^.FirstChild;
while aNode <> nil do begin
item := TItem(VT.GetNodeData(aNode)^);
aItem.fChild.Add(item);
GetItem(item, aNode);
aNode := aNode^.NextSibling;
end;
end;
begin
GetItem(aRootItem, VT.RootNode);
end;
procedure TForm3.BuildBtnClick(Sender: TObject);
var i1: TItem;
i2: TItem;
begin
if fRootItem = nil then begin
// サンプルツリーの構築
fRootItem := TItem.Create(0);
i1 := TItem.Create(1);
fRootItem.fChild.Add(i1);
i2 := TItem.Create(2);
i1.fChild.Add(i2);
i2.fChild.Add(TItem.Create(3));
i1.fChild.Add(TItem.Create(4));
i1.fChild.Add(TItem.Create(5));
fRootItem.fChild.Add(TItem.Create(6));
end;
VT.Clear;
BuildTree(fRootItem);
end;
procedure TForm3.RestructBtnClick(Sender: TObject);
begin
RestructItem(fRootItem);
VT.Clear;
end;
end.
サンプルプロジェクト: ダウンロード

0 件のコメント:
コメントを投稿