Die Drag-Operation einleiten


Das Control sendet eine "TVN_BEGINDRAG"-Benachrichtigung (in Form von "WM_NOTIFY") an sein übergeordnetes Fenster, sobald der Anwender ein Item auswählt und es mit gedrückter linker Maustaste zu ziehen beginnt. Da Drag&Drop aber auch mit der rechten Maustaste möglich ist, lautet die Benachrichtigung evtl. auch "TVN_BEGINRDRAG". In beiden Fällen enthält der lParam-Parameter die Adresse auf ein TNMTreeView-Record, das alle Informationen zu dem ausgewählten Item enthält.

WM_NOTIFY:
  with PNMTreeView(lp)^ do
    case hdr.code of
      TVN_BEGINDRAG,
      TVN_BEGINRDRAG:
        begin
          { ... }
        end;
    end;

Unsere erste Aufgabe besteht darin, uns das aktuelle Item zu merken. Wir benutzen dazu eine globale HTREEITEM-Variable:

hOldItem := itemNew.hItem;


Als nächstes benötigen wir ein Bild, das während des Ziehens angezeigt werden soll. Sie kennen diesen Effekt sicher vom Windows Explorer: wenn Sie dort einen Ordner verschieben, dann sehen Sie transparent das Symbol und den Namen des Ordners, während im Hintergrund immer der Ordner markiert wird, über dem Sie sich gerade befinden. Würden wir das nicht tun, sehen wir beim Ziehen entweder gar nichts oder bestenfalls das Item, über dem wir uns gerade befinden (wenn wir diese Funktionalität denn einbauen).

Wir könnten nun spezielle Grafiken benutzen, wir können aber auch dem Tree-View-Control "sagen", dass es ein Bild erzeugen soll. Dabei hilft uns die Nachricht "TVM_CREATEDRAGIMAGE"

hDragImgList := SendMessage(hTreeview,TVM_CREATEDRAGIMAGE,0,LPARAM(itemNew.hItem));

bzw. folgendes Makro:

hDragImgList := TreeView_CreateDragImage(hTreeview,itemNew.hItem);

Das Handle des Items, das sozusagen als Bild benutzt werden soll, nehmen wir aus dem TNMTreeView-Record, dessen Adresse von "WM_NOTIFY" übermittelt wurde. (Nicht durcheinander kommen! TNMTreeView ist das Record, das hinter allem steht. Da wir aber nur die Adresse besitzen, brauchen wir PNMTreeView, um über den Zeiger auf das eigentliche Record zugreifen zu können.)

Der nächste Schritt sind die beiden Anweisungen "ImageList_BeginDrag" und "ImageList_DragEnter". Die Funktion "ImageList_BeginDrag" erwartet neben dem Index des Bildes auch dessen Hotspot. Dieser Punkt bezieht sich auf die linke obere Ecke des Bildes. Wir benutzen hier in beiden Fällen Null

ImageList_BeginDrag(hDragImgList,0,0,0);

Würden Sie beispielsweise

ImageList_BeginDrag(hDragImgList,0,6,6);

verwenden, befände sich der Mauszeiger entsprechend weiter innerhalb des Bildes.

Zum Index ist zu sagen, dass unsere Liste nur ein Image enthält. Aus dem Grund muss natürlich in jedem Fall der Wert Null für den Index benutzt werden. Sie dürfen "Bild" dabei nicht ausschließlich auf das Ordnersymbol beziehen. Tatsächlich erzeugt das TreeView-Control ein Bild, das sowohl aus dem benutzten Symbol als auch aus dem Text des Items besteht. Würden Sie testweise einen anderen Index angeben, würden Sie alles mögliche sehen, aber nicht das Image, auf das es uns ankommt:

ImageList_BeginDrag(hDragImgList,1,0,0);


Die zweite Funktion "ImageList_DragEnter" verhindert, dass ein Fenster während des Ziehens verändert wird und zeigt das Bild an der angegebenen Position an. Da es um den Tree-View geht, übergeben wir dessen Fenster-Handle. Und die Position stammt hier wieder aus dem TNMTreeView-Record, das durch "WM_NOTFIY" im lParam übermittelt wurde:

ImageList_DragEnter(hTreeview,ptDrag.x,ptDrag.y);


Als nächstes sorgen wir mit "SetCapture" dafür, dass alle Mausnachrichten direkt an unser Hauptfenster geleitet werden. Das macht auch Sinn, da man die Maus während einer Drag&Drop-Aktion schwerlich anderweitig nutzen kann. Zusätzlich nutzen wir noch eine bool-Variable zur Kontrolle, ob wir uns im "Drag-Modus" befinden:

SetCapture(wnd);
DragMode := true;