Drag and Drop

Aus Wiki des Deutschsprachige Xbaseentwickler e. V.
Zur Navigation springen Zur Suche springen

Definition

Unter Drag and Drop versteht man das Verschieben von Informationen per Maus. Von welcher Art die Information ist, das ist erst einmal zweitrangig.

Das Programm muss eine sogenannte Drop-Zone definieren (bereitstellen), und auf die entsprechenden Events reagieren.


Definition einer Drop-Zone

Fast jedes Xbase-Part kennt die Instanz-Variable :dropZone. Sie steht standardmässig auf FALSE, d.h. das jeweilige Element ignoriert eine Drag and Drop Operation:

oXbp := XbpPushButton():new(oDlg:drawingArea, oDlg:drawingArea, aPos, aSize)
oXbp:dropZone := .T.

Darüber hinaus ist es (meistens) erforderlich, zumindest einen Callback-Slot zu definieren, der im Fall des Drop ausgeführt wird:

oXbp:dragDrop := {|aState, oDragData, self| HandleDropData(oDragData, aState)}

Für Text-Controls wie XbpSLE() und XbpMLE() kann auf diese Zuweisung normalerweise verzichtet werden, denn vom Format kompatible Informationen werden bei diesen Xbase-Parts direkt eingetragen. Wenn also z.B. eine Datei aus dem Explorer auf ein XbpSLE() gezogen wird, wird im XbpSLE() der Dateiname mit dem kompletten Pfad eingetragen.

Es gibt insgesamt vier Callback-Slots, die im Zusammenhang mit Drag and Drop stehen:

:dragEnter
:dragMotion
:dragLeave
:dragDrop


:dragEnter

Der :dragEnter Callback-Slot wird ausgeführt, wenn die Maus während einer Drag-Operation auf das entsprechende Xbase-Part gezogen wird.

Auf diese Weise kann geprüft werden, ob die Information für das Program "akzeptabel" ist:

oXbp:dragEnter := {|aState, oDragData| CheckDropData(aState, oDragData)}
...
FUNCTION CheckDropData(aState, oDrag)
   IF oDrag:QueryGetFormat(XBPCLPBRD_FILELIST) == .T.
      RETURN XBP_DROPMODE_COPY
   ENDIF
RETURN(XBP_DROPMODE_NONE)

In diesem Beispiel wird nur ein Liste von Dateien (auch eine einzelne Datei stellt eine Liste mit einem Eintrag dar) akzeptiert. Wenn etwas anderes "herübergezogen" wird, gibt die Funktion CheckDropData() eine Information zurück, die dazu führt, dass sich das Maussymbol so ändert, dass der Anwender erkennen kann, dass eine Drop-Operation HIER nicht zulässig ist.

Return-Wert Bedeutung Auswirkung Hinweis
XBP_DROPMODE_NONE Anwendung kann mit dem Datentyp nicht umgehen Cursor zeigt "no drop" Symbol -
XBP_DROPMODE_COPY Anwendung nimmt die Daten als Kopie entgegen Cursor zeigt "drop possible" Symbol Standard-Verhalten
XBP_DROPMODE_MOVE Die Datenquelle soll die Daten nach dem Drop entfernen Cursor zeigt "drop possible" Symbol -
XBP_DROPMODE_LINK Die Datenquelle soll einen Link zu den Daten bereitstellen Cursor zeigt "drop possible" Symbol -

:dragMotion

Der :dragMotion Callback-Slot wird ausgeführt, wenn die Maus innerhalb der DropZone bewegt wird, oder eine Taste gedrückt wird.

aState => {nKeyState, aPos}
 aPos  => {X-Pos Maus, Y-Pos Maus)

Dann kann das Programm wiederum prüfen, ob die Drag and Drop Operation zulässig ist oder nicht. Es gelten die gleichen Rückgabewerte wie bei :dragEnter.


:dragLeave

Der :dragLeave Callback-Slot wird ausgeführt, wenn die Maus aus dem Bereich der DropZone herausgeführt wird. Falls das Xbase-Programm irgendwelche Vorbereitungen für den Drop getroffen hat, können diese nun freigegeben werden.

Abweichend von den anderen Callback-Slots sind hier die beiden Parameter NIL.


:dragDrop

Der :dragDrop Callback-Slot wird ausgeführt, wenn die Daten im Bereich der DropZone durch Loslassen der Maustaste "gedropt" werden.

Analog zu :dragMotion enthält der Parameter aState Informationen zur gedrückten Taste und der Position des Maus-Cursors zum Zeitpunkt des Drop:

FUNCTION HandleDropData(oData, aState)
   Local aData
   aData := oData:getData(XBPCLPBRD_FILELIST)
   IF aData == NIL
      ConfirmBox(, "Falsches Format.", "Fehler", XBPMB_OK, XBPMB_CRITICAL)
      RETU(.F.)
   ENDIF

Ein Xbase-Programm kann nicht jedes Datenformat entgegennehmen, das unter Windows möglich ist. Wenn die Daten nicht im angeforderten Format vorliegen (in diesem Beispiel als XBPCLPBRD_FILELIST), liefert die Methode :getData() NIL als Ergebnis zurück. NIL signaliert also nicht "keine Daten", sondern "keine Daten in diesem Format".

Neben dem obigen Beispie, die Daten direkt entgegenzunehmen, besteht auch die Möglichkeit, das Format abzufragen: oData ist ein Objekt der DragDataObject() Klasse, und über die Methode :QueryGetFormat() kann geprüft werden, ob die Daten in einem bestimmten Format vorliegen:

   lFormat := oData:QueryGetFormat(XBPCLPBRD_FILELIST)

Folgende Abfragen sind möglich:

Format-Typ Bedeutung
XBPCLPBRD_TEXT Daten liegen im ASCII-Format als Text vor
XBPCLPBRD_BITMAP graphische Daten liegen im Bitmap-Format vor
XBPCLPBRD_METAFILE graphische Daten liegen im Metafile-Format vor
XBPCLPBRD_FILELIST Die Daten werden als Liste von Dateinamen vom Windows-Explorer übergeben
  nLen := Len(aData)
  cTitle := RootWindow():getTitle()
  RootWindow():setTitle(cTitle + " - processing input")
  nColor := RootWindow():drawingArea:setColorBG(GRA_CLR_CYAN)
  FOR nI := 1 TO nLen
     PushData(aData[nI])
  NEXT
  RootWindow():drawingArea:setColorBG(nColor)
  RootWindow():setTitle(cTitle)

In diesem Beispiel ist die :drawingArea des Programmfenster als DropZone definiert. Wenn ein passender Wert (hier eine Datei-Liste) per Drag and Drop übergeben wird, wird der Titel des Programms geändert, und die Hintergrundfarbe der :drawingArea verändert, um anzuzeigen, dass ein besonderer Prozess abläuft. Dann werden die übergebenen Dateien der Reihe nach in der Funktion PushData() verarbeitet. Zum Abschluss wird der ursprüngliche Titel des Programms wiederhergestellt, und auch die Farbe der :drawingArea zurückgeändert.

Besonderheiten

Wenn z.B. ein Link aus dem Browser auf eine DropZone gezogen wird, bleibt der Browser so lange "gesperrt" (d.h. reagiert nicht auf Eingaben), wie das Xbase-Programm im Rahmen der Drop-Operation tätig ist. Erst mit Aufnahme des Event-Loops kann wieder mit dem Browser gearbeitet werden.

Um auf das vorhergehende Beispiel zurückzukommen: wenn während der Verarbeitung der Drag and Drop-Operation das Programm weiterhin genutzt werden soll, besteht die Möglichkeit, die Drag and Drop-Verarbeitung über einen Thread zu starten und dann wieder in den Event-Loop zurückzukehren.