Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 111. - Přetahování v TreeView

Jan Šindelář - 8.10.2003

Oč jde při drag & drop vám určitě nemusím říkat, protože tato technologie je v systémech Windows již dlouho. Umožňuje uživateli uchopit myší nějaký objekt (např. soubor, zástupce apod.), přesunout jej jinam a zde jej opět pustit (např. vyhodit do koše). Převážně se tohoto postupu používá právě při rozličné manipulaci se soubory, ale rozhodně to není pravidlo.

Detailnějšímu popisu fungování této technologie v Delphi se vyhneme, protože to patří do jiného seriálu a dnes si ukážeme, jak pomocí "táhni a pusť" přesouvat jednotlivé položky (větve) v rámci komponenty TreeView. Nebudeme tedy komunikovat s jinou aplikací ani s jinými objekty v rámci naší aplikace, ale pouze uvnitř samotného TreeView. Je to poměrně užitečná věc, protože pokud potřebujete přeuspořádat nějakou stromovou strukturu, je to tímto postupem pohybem myši velmi přirozené a pohodlné, což uživatel jistě ocení.

Přistupme tedy k našemu dnešnímu programu. Na formulář umístíme nejprve TreeView a naplňte jej rovněž nějakými testovacími daty. Snažte se vytvořit alespoň náznak nějaké stromové struktury, aby bylo vše při testování příkladu dobře zřetelné. Další důležitá věc je, že v Object Inspectoru musíme nastavit pro vlastnost DragMode hodnotu dmAutomatic. Tolik tedy k "vizuální" stránce a zbytek už je na zdrojovém kódu.

Vytvoříme si proceduru, která nám přesune v rámci daného TreeView vybranou větev z jednoho místa na druhé. Odkud, kam a jak, tak k tomu nám pomohou události OnDragDrop a OnDragOver našeho TreeView.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls;

type
  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);
  private
    { Private declarations }
    procedure MoveNode(TargetNode, SourceNode : TTreeNode);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.MoveNode(TargetNode, SourceNode : TTreeNode);
var
  nodeTmp : TTreeNode;
  i : Integer;
begin
  with TreeView1 do
  begin
    nodeTmp := Items.AddChild(TargetNode, SourceNode.Text);
    for i := 0 to SourceNode.Count -1 do
    begin
      MoveNode(nodeTmp, SourceNode.Item[i]);
    end;
  end;
end;

procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
  TargetNode, SourceNode : TTreeNode;
begin
  with TreeView1 do
  begin
    TargetNode := GetNodeAt(X, Y);
    SourceNode := Selected;
    if (TargetNode = nil) then
    begin
      EndDrag(False);
      Exit;
    end;
    MoveNode(TargetNode,SourceNode);
    SourceNode.Free;
  end;
end;

procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
  if (Sender = TreeView1) then
  begin
    Accept := True;
  end;
end;

end.

Událost OnDragDrop zjistí, kterou větev a kam přemístit, a o zbytek se postará MoveNode. A poslední procedura, událost OnDragOver, zase hlídá, aby komponenta TreeView "přijímala" přesunuté větve jen sama od sebe a ne odjinud.