Revision 1 of 2, by Trev on 2-14-2020. The page as it is now.
Drag and Drop/de
Zurück zu den Zusätzlichen Informationen.
Dieser Artikel beschäftigt sich mit der Windows- und der Linuxprogrammierung.
Dieser Artikel bezieht sich auf Lazarus Version 1.0.10 und höher.
=Grundlegendes zu Drag and Drop= Drag and Drop ist eine Methode zur Bedienung grafischer Benutzeroberflächen.
Bei einem Drag and Drop Vorgang sind immer zwei Objekte beteiligt. Das sendende Objekt und das entgegennehmende Objekt.
\
Drag and Drop innerhalb eines Formulars
Damit ein Objekt senden kann, benötigt es genau ein Ereignis:\
- OnMouseDown
Damit ein Objekt empfangen kann, benötigt es zwei Ereignise:\ - OnDragDrop
- OnDragOver
==Das OnMouseDown-Ereignis des sendenden Objekts== Beispiele wie ein OnMouseDown-Ereignis des sendenden Objektes aussehen kann:
===Beispiel für ein Edit===
procedure TForm1.Edit1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: integer);
begin
if Button = mbLeft then
Edit1.BeginDrag(False); // False, damit Drag and Drop erst nach einer Mausbewegung beginnt
end;
===Beispiel für ein Memo===
procedure TForm1.Memo1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
Memo1.BeginDrag(False); // False, damit Drag and Drop erst nach einer Mausbewegung beginnt
end;
==Die Ereignisse OnDragDrop, OnDragOver und EndDrag des empfangenden Objekts==
Beispiel für ein Edit, wenn ein Edit der Sender ist
// Auswerten, ob es sich um den richtigen Sendertyp handelt
// und nicht, ob es sich um den richtigen Sender handelt
procedure TForm1.Edit2DragOver(Sender, Source: TObject; X, Y: integer;
State: TDragState; var Accept: boolean);
begin
if (Source is TEdit) then // Fragt den Objekttyp ab
Accept := True; // Wenn der Objekttyp stimmt ist der Datensatz zu akzeptieren
end;
// Datenübernahme
procedure TForm1.Edit2DragDrop(Sender, Source: TObject; X, Y: integer);
begin
if (Source is TEdit) then // Wenn der Objekttyp stimmt werden die Daten übernommen
Edit2.Text := TEdit(Source).Text;
end;
// Fehlerauswertung
procedure TForm1.Edit2EndDrag(Sender, Target: TObject; X, Y: Integer);
begin
if (Target = nil) then // Wenn beim Drag and Drop ein Fehlerauftritt
Showmessage('Bei Drag and Drop ist ein Fehler aufgetreten.');
end;
===Beispiel für eine Listbox, wenn ein Edit der Sender ist===
// Auswerten, ob es sich um den richtigen Sendertyp handelt
// und nicht, ob es sich um den richtigen Sender handelt
procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: integer;
State: TDragState; var Accept: boolean);
begin
if (Source is TEdit) then // Fragt den Objekttyp ab
Accept := True; // Wenn der Objekttyp stimmt ist der Datensatz zu akzeptieren
end;
// Datenübernahme
procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: integer);
begin
if (Source is TEdit) then // Wenn der Objekttyp stimmt werden die Daten übernommen
Listbox1.Items.Add(TEdit(Source).Text); // Fügt den Text aus dem Edit hinzu
end;
// Fehlerauswertung
procedure TForm1.ListBox1EndDrag(Sender, Target: TObject; X, Y: integer);
begin
if (Target = nil) then // Wenn beim Drag and Drop ein Fehlerauftritt
ShowMessage('Bei Drag and Drop ist ein Fehler aufgetreten.');
end;
===Beispiel für ein Treeview, wenn ein Edit der Sender ist===
// Auswerten, ob es sich um den richtigen Sendertyp handelt
// und nicht, ob es sich um den richtigen Sender handelt
procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: integer;
State: TDragState; var Accept: boolean);
begin
if (Source is TEdit) then // Fragt den Objekttyp ab
Accept := True; // Wenn der Objekttyp stimmt ist der Datensatz zu akzeptieren
end;
// Datenübernahme
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: integer);
var
tv: TTreeView;
Knoten: TTreeNode;
begin
tv := TTreeView(Sender); // Sender is TreeView where the data is being dropped
Knoten := tv.GetNodeAt(x, y); // x,y sind die Drop Koordinaten im Baum des Treeview
// Wenn der Objekttyp stimmt werden die Daten übernommen
if Source is TEdit then
// nun werden die Daten dem Knoten hizugefügt
tv.Items.AddChild(Knoten, TEdit(Source).Text);
end;
// Fehlerauswertung
procedure TForm1.TreeView1EndDrag(Sender, Target: TObject; X, Y: integer);
begin
if (Target = nil) then // Wenn beim Drag and Drop ein Fehlerauftritt
ShowMessage('Bei Drag and Drop ist ein Fehler aufgetreten.');
end;\
Drag and Drop vom Dateimanager auf das Formular
Vorab:
Fast jedes Betriebsystem bringt einen oder mehrere Dateimanager mit, das heisst, dass das Funktionieren von Drag and Drop nicht mit jedem Dateimanager garantiert werden kann.
Dateimanager sind z. B.:
Explorer (Betriebsystem Windows), Nautilus (Betriebssystem Ubuntu), Dolphin, Konqueror, usw.
Vorgehensweise:
Zu erst muss im Objektinspektor des Formulars im Register Eigenschaft die Eigenschaft <b>AllowDropFiles</b> auf True gesetzt werden.

Dann wird im Objektinspektor des Formulars im Register Ereignisse das Ereignis <b>OnDropFiles</b> ausgewählt.

Um zum Beispiel die Dateien in einer ListBox an zuzeigen, wird für das Ereignis <b>OnDropFiles</b> folgender Code benötigt:
===Minimalbeispiel zu OnDropFiles===
procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of string);
var
intI: integer = 0;
begin
for intI := 0 to high(filenames) do
listbox1.Items.Add(filenames[intI]);
end;\
Ein Beispiel dass Probleme bei OnDropFiles erläutert
Dieses Beispiel beschäftigt sich mit Besonderheiten editierbarer Felder und der Auswertung des Drop.
Dieses Beispiel beschäftigt sich auch mit Besonderheiten der Linuxprogrammierung.
===Probleme=== Beim Ziehen auf ein Formular entstehen folgende Effekte:
- Der Drop kann auf das Formular selbst oder ein Komponente auf dem Formular erfolgen, wo spielt keine Rolle, aber es wird kein Zielpunkt übergeben
- Editierbare Felder fügen den erhaltenen Text automatisch ein! Alle Anderen nicht.
- Zusätzlich fügen diese Felder automatisch eine Kennung hinzu z.B. <b>file:</b> oder <b>url:</b>
- <b>Das Ereignis wird vom Formular in jedem Fall verarbeitet</b>, es ist nicht möglich den Drop durch das Editierfeld zu verweigern, abzubrechen oder umzuleiten
- Wegen 2. wird u.U. doppelt eingefügt, wenn nicht geprüft wird, wo der Drop erfolgt
<b>Hinweis:</b> Um 'einfach' ein <b>Drop-Ereignis auf ein editierbares Element zu verhindern</b>, kann es auf <b>Readonly</b> gesetzt werden. Der Cursor zeigt dann, dass das Feld keinen Drop annimmt. Eine bessere Lösung kann ich derzeit nicht anbieten.
Aufbau des Beispiels
Das Beispiel besteht aus zwei ListView-Elementen, da diese auf den FileDrop nicht weiter reagieren, es könnten aber auch andere sein (sollten nur keine editierbaren sein). Diese Element haben sonst keine Aufgaben. Ein Memo-Element wird zur Ausgabe der Ergebnisse benutzt. Hier kann auch ein reiner Text-Drop<sup></sup>) aus einem Editierfeld überprüft werden (markieren und ziehen).
<sup></sup>) In wie weit meine Desktopumgebung (Debian+KDE4) hier automatismen verwendet die zu einem anderem Verhalten führen als geplant, kann ich bisher nicht nachvollziehen.
====Zusätzlich benötigte Units====
- baseunix
- types
====Benötigt Funktionen für Linux (basierend auf <i>baseunix</i>)==== Mit Linux wird im Prizip (fast) alles als Datei behandelt. Anhand des Pfades ist zunächst nicht erkennbar was dahinter steckt.
- Systemdateien: Hier kann ein Problem entstehen wenn ein Lesezugriff z.B. auf einen FIFO gemacht wird, als ob es eine normale Datei wäre: Die Datei hat KEIN ENDE. (In die Falle tappen viele Programme.)
- LINKs: Gerade SymLinks führen zu einem anderen Verzeichniss, dies kann beim Folgen eines solchen zu einer endlosen Kreisbewegung führen.\
<b>Anmerkung:</b> Dateien und Verzeichnisse können ein LINK sein. Siehe Unit <b>Baseunix</b>, Beispiel zu <b>S_ISLNK</b> ; Siehe auch Linuxbefehl <b>stat</b>
Die genaue Auswertung was im Dateisystem hinter dem Pfad steckt, erfolgt mit folgenden Funktionen:
//Prüfe ob StrPath ein LINK im Dateisystem ist
function IsLink(const StrPath: string):Boolean;
var info: stat;
begin
fplstat(StrPath, @info);
Result := (fpS_ISLNK(info.st_mode));
end;
//Prüfe ob StrPath eine reguläre Datei ist
function IsRegular(const StrPath: string):Boolean;
var info: stat;
begin
fplstat(StrPath, @info);
Result := (fpS_ISREG(info.st_mode));
end;
===Beispiel mit Auswertung des Drop=== Es erfolgt folgende Auswertung:
- Gehört der übergebene Pfad zum lokalen Dateisystem
- Ist es etwa eine URL z.B. WebLink <b>http://</b> oder eine Freigabe <b>smb://</b>
- Auf welchem Element ist der Drop erfolgt
\
procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of String );
var i,j: integer;
s: String;
p: TPoint;
begin
// Auswertung des übergebenen Pfades
for i:=0 to High(FileNames) do
begin
s:= FileNames[i];
// Reihenfolge ist für linux wichtig !
if DirectoryExists(s) then begin
if IsLink(s) then Memo1.Lines.Add('VERZEICHNIS LINK:'+s)
else Memo1.Lines.Add('VERZEICHNIS:'+s);
end
else if FileExists(s) then begin
if IsLink(s) then Memo1.Lines.Add('DATEI LINK:'+s)
else if IsRegular(s) then Memo1.Lines.Add('DATEI:'+s)
else Memo1.Lines.Add('Systemdatei NICHT Lesen:'+s); // fifo, socket, usw.
end
else begin
j:= pos('://',s);
if ((j > 0)and(j < 6)) then begin // limit j< 6 hängt von zu erwartetenden Dienst ab
Memo1.Lines.Add('Eine Art von URL:'+s); // 'smb://' , 'http://' , usw.
Memo1.Lines.Add('Dienst:'+copy(s, 1, j));
Memo1.Lines.Add('PFAD:' +copy(s, j+3, Length(s)));
end
// Ein Drop mit Text erfolgt nur auf editierbare Felder
else Memo1.Lines.Add('TEXT:'+s); //Man kann hier also auch Text übergeben
end;
//Auf welchem Element war der Drop: Prüfe ob die Maus über einem ListView war
p:= Mouse.CursorPos;
if PtInRect(ListView1.BoundsRect,Form1.ScreenToClient(p)) then Memo1.Lines.Add('Drop in ListView1');
if PtInRect(ListView2.BoundsRect,Form1.ScreenToClient(p)) then Memo1.Lines.Add('Drop in ListView2');
end;Anmerkung: Die Auswertung der Mausposition erfolgt im Formularkoordinatensystem.
From the Free Pascal wiki, page "Drag and Drop/de", as it stood on 2020-02-14 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.
