Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 3/2012.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Zusammenfassung

Lernen Sie ein komplexes Beispiel für das Drag and Drop zwischen verschiedenen Steuerelementen wie dem TreeView- und dem ListView-Steuerelement kennen.

Techniken

Formulare, TreeView, ListView, VBA

Voraussetzungen

Access 2000 und höher

Beispieldateien

aiuTimeplanner.mdb

Shortlink

www.access-im-unternehmen.de/833

Drag and Drop mit TreeView und ListView

André Minhorst, Duisburg

Wenn Sie mit ListView- und TreeView-Steuerelementen arbeiten, sind Drag-and-Drop-Operationen ein tolles Hilfsmittel, um Daten zwischen den Steuerelementen hin- und herzuschieben. In der Anwendung aiuTimeplanner gibt es gleich zwei ListView- und ein TreeView-Steuerelement - genügend Möglichkeiten also, um Drag and Drop einmal anhand eines Praxisbeispiels zu demonstrieren. Dabei sollen Aufgaben aus dem TreeView in beide ListViews verschoben werden sowie von ListView zu ListView - und das Verschieben und Kopieren von Einträgen innerhalb eines ListView-Steuerelements ist ebenfalls gefragt.

Das Hin- und Herschieben von Elementen zwischen verschiedenen ListView- und TreeView-Einträgen ist prinzipiell nicht schwierig. Beim Start des Drag-and-Drop-Vorgangs wird immer das OLEStartDrag-Ereignis ausgelöst, dem Sie mit dem Parameter Data Informationen über die zu verschiebenden Daten mitgeben. Beim Überfahren des Drop-Ziels und beim Fallenlassen werden die beiden Ereignisprozeduren OLEDragOver und OLEDragDrop ausgelöst, denen Sie wiederum über den gleichen Parameter die beim Start übergebenen Daten entnehmen können.

Sie starten also beispielsweise von einem ListView-Steuerelement einen Drag-and-Drop-Vorgang und speisen den Key-Wert des gezogenen Elements in den Parameter Data ein, beispielsweise t123. Dann sollte t einen Hinweis auf das Steuerelement geben, von dem aus der Vorgang gestartet wurde, und 123 entspricht dem Primärschlüsselwert des Datensatzes, der per Drag and Drop bewegt werden soll.

Im Beispiel, das im Beitrag Tagesablauf verwalten mit dem aiuTimeplanner (www.access-im-unternehmen.de/839) genauer erläutert wird, gibt es drei Steuerelemente, die Drag-and-Drop-Operationen unterstützen:

  • das ListView-Steuerelement lvwDailyTasks,
  • das TreeView-Steuerelement tvwTasks und
  • das ListView-Steuerelement lvwTimeplan.

Es gibt gleich eine ganze Reihe möglicher Drag-and-Drop-Operationen, die durch die Pfeile in Abb. 1 verdeutlicht werden:

pic001.png

Abb. 1: Mögliche Drag-and-Drop-Vorgänge in der Beispielanwendung

  • Vom TreeView zur Tagesliste: Stellt die Eigenschaft HeuteErledigen auf True ein und fügt den Eintrag zur Tagesliste hinzu.
  • Vom TreeView zu einem anderen TreeView-Element: Ordnet die Aufgabe einer anderen Aufgabe unter.
  • Vom TreeView an eine leere Stelle im TreeView: Löscht den Eintrag nach Rückfrage. Bei gedrückter Umschalttaste wird ohne Rückfrage gelöscht.
  • Vom TreeView zur Tätigkeitsliste: Fügt eine neue Tätigkeit auf Basis der gezogenen Aufgabe hinzu.
  • Von der Tagesliste zur Tätigkeitsliste: Fügt eine neue Tätigkeit auf Basis der gezogenen Aufgabe hinzu.
  • Von der Tagesliste in einen leeren Bereich der Tagesliste: Stellt die Eigenschaft HeuteErledigen auf False ein und entfernt den Eintrag aus der Liste.
  • Von der Tätigkeitsliste an eine andere Stelle der Tätigkeitsliste: Verschiebt die Tätigkeit.
  • Von der Tätigkeitsliste an eine andere Stelle der Tätigkeitsliste, diesmal mit gedrückter Strg-Taste: Kopiert die Tätigkeit.

Gezogene Elemente identifizieren

Die Elemente können über den Wert der Eigenschaft Key dem jeweiligen Steuerelement zugeordnet werden, also beispielsweise d für lvwDailyTasks, t für tvwTasks und p für lvwTimeplan. So kann man über den Wert des Parameters Data jeweils am ersten Buchstaben erkennen, von welchem Steuerelement aus der Drag-and-Drop-Vorgang gestartet wurde, die folgenden Zahlen liefern die ID des Elements aus der jeweiligen Tabelle.

Dies wird natürlich etwas schwieriger, wenn Sie etwa in einem TreeView-Steuerelement die Daten aus mehreren Tabellen speichern und beispielsweise Kunden mit dem Präfix k und Artikel mit dem Präfix a versehen.

Dies erhöht jedoch nur die Anzahl der möglichen Kombinationen und damit die verschiedenen Arten, einen Drag-and-Drop-Vorgang anhand von Quelle und Ziel zu verarbeiten. Sie können nach wie vor mit einem Präfix-Buchstaben arbeiten, der die Art der Daten beschreibt, und daran den Primärschlüsselwert des entsprechenden Elements anhängen.

Starten eines Drag-and-Drop-Vorgangs

Der Start eines Drag-and-Drop-Vorgangs beginnt immer mit dem Herunterdrücken der Maustaste auf einem Element eines ListView- oder TreeView-Steuerelements und dem Bewegen des Mauszeigers bei gedrückter Maustaste. Dies ist der Moment, in dem Sie Informationen über das gezogene Element aufnehmen und speichern müssen.

Das passende Ereignis lautet OLEStartDrag und kann über die beiden Kombinationsfelder des Klassenmoduls des Formulars hinzugefügt werden (s. Abb. 2).

pic002.png

Abb. 2: Hinzufügen des OLEStartDrag-Ereignisses

Damit dieses Ereignis und die beiden im Verlauf dieses Beitrags vorgestellten Ereignisse nach Wunsch ausgelöst werden, müssen Sie für die entsprechenden Objektvariablen außerdem noch je zwei Eigenschaften einstellen - dies geschieht in Konfigurationsprozeduren, die im Beitrag Tagesablauf verwalten mit aiuTimeplanner (www.access-im-unternehmen.de/839) beschrieben werden:

objTasks.OLEDragMode = ccOLEDragAutomatic

objTasks.OLEDropMode = ccOLEDropManual

Die drei Ereignisprozeduren objTasks_OLEStartDrag, objDailyTasks_OLEStartDrag und objTimeplan_OLEStartDrag werden dann wie in Listing 1 angelegt und wie die Prozedur objTasks_OLEStartDrag gefüllt.

Listing 1: Diese Prozeduren werden beim Starten eines Drag-and-Drop-Vorgangs ausgelöst.

Private Sub objTasks_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long)

    Dim objNode As MSComctlLib.Node

    Set objNode = objTasks.SelectedItem

    If objNode Is Nothing Then Exit Sub

    Data.Clear

    Data.SetData objNode.Key, ccCFText

End Sub

Private Sub objTimeplan_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long)

    Dim objListitem As MSComctlLib.ListItem

    Set objListitem = objDailyTasks.SelectedItem

    If objListitem Is Nothing Then Exit Sub

    Data.Clear

    Data.SetData objListitem.Key, ccCFText

End Sub

Private Sub objDailyTasks_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long)

    ... wie objTimeplan_OLEStartDrag

End Sub

Die Prozeduren ermitteln jeweils das beim Start des Drag-Vorgangs markierte Element. Ist kein Element markiert, wird die Prozedur beendet. Anderenfalls wird der Parameter Data erst geleert und dann mit dem Wert der Key-Eigenschaft des betroffenen Elements gefüllt, also beispielsweise t123 beim Ziehen eines Elements des Aufgabenbaums, d234 beim Ziehen eines Elements der Tagesliste oder p345 beim Ziehen eines Elements der Tätigkeitenliste.

Damit enthält der Parameter Data genaue Informationen über den Ursprung der Drag-and-Drop-Operation und über den Primärschlüsselwert des gezogenen Elements.

Ziel beim Überfahren markieren

Damit der Benutzer erkennt, wo er ein Element fallenlassen kann und wo nicht, markieren wir potenzielle Ziele beim Überfahren. Dies erledigen die Ereignisprozeduren objTasks_OLEDragOver, objDailyTasks_OLEDragOver und objTimeplan_OLEDragOver. Die Prozeduren sind für alle drei Steuerelemente sehr ähnlich aufgebaut, sodass wir nur eines in Listing 2 komplett abbilden.

Listing 2: Ereignisprozedur beim Überfahren des Zielelements

Private Sub objTasks_OLEDragOver(Data As MSComctlLib.DataObject, Effect As Long, _

        Button As Integer, Shift As Integer, x As Single, y As Single, State As Integer)

    Dim strData As String

    Dim strDatatype As String

    If Data.GetFormat(ccCFText) = False Then Exit Sub

    strData = Data.GetData(ccCFText)

    strDatatype = Left(strData, 1)

    Select Case strDatatype

        Case "t"

            Set objTasks.DropHighlight = objTasks.HitTest(x, y)

    End Select

End Sub

Dort wird zunächst das Format des gezogenen Elements geprüft, das den Wert ccCFText aufweisen sollte - anderenfalls wird die Prozedur abgebrochen. Ist das Format korrekt, liest die Prozedur den Inhalt des Parameters Data in eine String-Variable namens strData ein, also beispielsweise t123.

Daraus entnimmt sie den ersten Buchstaben, der einen Hinweis auf die Herkunft des gezogenen Elements liefert. t steht wie erwähnt für objTasks, p für objTimeplan und d für objDailyTasks. Anhand dieses Wertes entscheidet die Prozedur, ob ein Element beim Überfahren als Ziel markiert werden soll.

Dies geschieht, indem mit der HitTest-Funktion des Zielsteuerelements ein Verweis auf das Zielelement ermittelt wird.

Dieser wird anschließend der DropHighlight-Eigenschaft des jeweiligen Steuerelements zugeordnet, was dazu führt, dass das Zielelement durch einen blauen Hintergrund markiert wird.

Für das Objekt objDailyTasks sieht die Prozedur genauso aus wie die für objTasks. Die Prozedur objTimeplan_OLEDragOver enthält jedoch eine andere Bedingung zur Prüfung des Datentyps des gezogenen Elements:

Select Case strDatatype

    Case "t", "d", "p"

        Set objTimeplan.DropHighlight = objTimeplan.HitTest(x, y)

End Select

Das bedeutet, dass ein Element nicht nur beim Ziehen einer Aufgabe aus dem TreeView-Objekt objTasks als Ziel angeboten wird, sondern auch beim Ziehen von Elementen aus der Tagesliste und aus der Tätigkeitsübersicht selbst.

An dieser Stelle könnten Sie noch verschiedene Symbole einblenden, die einen Hinweis auf die geplante Aktion liefern. Dazu stellen Sie den Parameter Effect auf einen der folgenden Werte ein:

  • ccOLEDropEffectCopy
  • ccOLEDropEffectMove
  • ccOLEDropEffectNone
  • ccOLEDropEffectScroll

Element fallenlassen

Kommen wir zu den wirklich interessanten Aktionen - den Datenoperationen und den Änderungen der Darstellung beim Fallenlassen eines Elements auf einem erlaubten Ziel.

Als Erstes sehen wir uns das Fallenlassen eines Elements auf dem TreeView-Objekt des Formulars an. Dies löst die Ereignisprozedur objTasks_OLEDragDrop aus (s. Listing 3). Diese Prozedur enthält ebenfalls einen Parameter namens Data, der den Kennbuchstaben für den entsprechenden Elementtyp und den Primärschlüsselwert liefert.

Listing 3: Beenden des Drag-and-Drop-Vorgangs

Private Sub objTasks_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, _

        Button As Integer, Shift As Integer, x As Single, y As Single)

    '... Deklaration

    strData = Data.GetData(ccCFText)

    strDatatype = Left(strData, 1)

    lngKeyDrag = Mid(strData, 2)

    Set objNodeDrop = objTasks.HitTest(x, y)

    Select Case strDatatype

    Case "t"

        If objNodeDrop Is Nothing Then

            AufgabeLoeschen lngKeyDrag, -Shift

        Else

            strKeyDrop = objNodeDrop.Key

            lngKeydrop = Mid(strKeyDrop, 2)

            Set objNodeDrag = objTasks.Nodes(strData)

            If strKeyDrop = strKeyDrag Then

                Exit Sub

            End If

            Select Case Shift

                Case 0 'verschieben

                    AufgabeVerschieben lngKeydrop, lngKeyDrag

                Case 1

                    AufgabenZusammenfuehren Mid(objNodeDrag.Key, 2), Mid(objNodeDrop.Key, 2)

            End Select

            FillTree

        End If

    End Select

End Sub

Dieser Wert wird zunächst ausgelesen. Die einzelnen Bestandteile landen in den beiden Variablen strDatatype und lngKeyDrag. Das TreeView-Steuerelement kann nur Elemente verarbeiten, die auch von dort aus gezogen wurden. Der Wert der Variablen strDatatype muss also t lauten, anderenfalls geschieht nichts.

Danach unterscheidet die Prozedur zwei Fälle, die davon abhängen, ob die Variable objNodeDrop einen Wert enthält oder nicht. Die Variable wird mit einem Verweis auf das TreeView-Element gefüllt, auf dem das Drag-and-Drop-Element fallengelassen wurde. Hat der Benutzer also ein Element auf ein anderes Element gezogen, wird dieses mit objNodeDrop referenziert. Hat er hingegen ein Element an eine freie Stelle innerhalb des TreeView-Steuerelements gezogen, bleibt objNodeDrop leer.

In diesem Fall wird das gezogene Element gelöscht. Es ist nur noch offen, ob es direkt gelöscht werden soll oder ob zuvor noch eine Rückfrage erfolgen soll. Wenn der Benutzer beim Ziehen des Elements in den leeren Raum die Umschalttaste gedrückt hat, wird das Element direkt gelöscht, ohne Betätigen einer Taste erscheint noch eine Rückfrage.

Damit die dadurch aufgerufene Prozedur AufgabeLoeschen je nach Tastenkombination die erforderliche Meldung anzeigt, übergeben Sie dieser den Wert des Parameters Shift mit negativem Vorzeichen (s. Listing 4). 0 bedeutet dann False, -1 heißt True.

Listing 4: Löschen einer Aufgabe

Public Function AufgabeLoeschen(lngAufgabeID As Long, bolLoeschen As Boolean)

    Dim db As DAO.Database

    Set db = CurrentDb

    If bolLoeschen = False Then

        bolLoeschen = MsgBox("Aufgabe wirklich löschen?", vbOKCancel + vbExclamation, _

            "Aufgabe löschen") = vbOK

    End If

    If bolLoeschen = True Then

        db.Execute "DELETE tblAufgaben.* FROM tblAufgaben INNER JOIN tblAufgabenUnteraufgaben " _

            & "ON tblAufgaben.AufgabeID = tblAufgabenUnteraufgaben.UnteraufgabeID "_

            & "WHERE tblAufgabenUnteraufgaben.AufgabeID = " & lngAufgabeID, dbFailOnError

        db.Execute "DELETE FROM tblAufgaben WHERE AufgabeID = " & lngAufgabeID, dbFailOnError

        objTasks.Nodes.Remove "t" & lngAufgabeID

    End If

End Function

Der Prozedur übergeben Sie außerdem noch die ID der zu löschenden Aufgabe. Ist bolLoeschen nun False, was geschieht, wenn das Element einfach in den leeren Bereich gezogen wird, fragt die Prozedur nach, ob die Aufgabe gelöscht werden soll. Falls bolLoeschen den Wert True hat, wird direkt gelöscht.

Zurück zur Prozedur objTasks_OLEDragDrop und zu dem Fall, dass das Element auf ein anderes Element gezogen wurde. Dann liest die Prozedur zunächst den Key des Zielelements in die Variable strKeyDrop ein und die ID der entsprechenden Aufgabe in die Variable lngKeyDrop. Um einfacher auf das gezogene Element zugreifen zu können, wird dieses mit der Objektvariablen objKeyDrag referenziert.

Hier erfolgt nun zunächst die Prüfung, ob das Element auf sich selbst gezogen wurde. Dies würde einen Zirkelbezug und damit einen Fehler auslösen, also wird die Prozedur ohne weitere Aktionen beendet. Anderenfalls wird wiederum geprüft, ob der Benutzer die Umschalttaste gedrückt hält (Shift = 1).

Aufgaben zusammenführen

Wozu aber soll dies gut sein? Nun: Das Kopieren von Aufgaben ist wenig sinnvoll, da eine Aufgabe immer nur im Kontext einer übergeordneten Aufgabe stehen und nicht mehrfach vorkommen soll.

Es kann aber vorkommen, dass man feststellt, dass man Aufgaben mehrfach anlegt und pflegt. Um später in Auswertungen vernünftige Daten zu erhalten, müssen diese parallel gepflegten Aufgaben zusammengeführt werden. Dies erledigen Sie, wenn Sie eine Aufgabe bei gedrückter Umschalttaste auf eine andere Aufgabe ziehen:

  • Die gezogene Aufgabe wird gelöscht.
  • Die Unteraufgaben der gezogenen Aufgabe werden der Zielaufgabe untergeordnet.
  • Die Tätigkeiten, die bereits für die gezogene Aufgabe angelegt wurden, werden ebenfalls der Zielaufgabe untergeordnet.

All dies erledigt die Prozedur AufgabenZusammenfuehren mit drei SQL-Statements (siehe Klassenmodul des Formulars frmTagesablauf in der Beispieldatenbank).

Aufgaben verschieben

Bleibt noch das eigentliche Verschieben, das durch bloßes Drag and Drop ohne jegliche Tastenkombination erfolgt. Dies führt zum Aufruf der Prozedur AufgabeVerschieben (s. Listing 5). Diese Prozedur erwartet die Primärschlüsselwerte der beiden beteiligten Aufgaben als Parameter.

Listing 5: Verschieben einer Aufgabe

Private Sub AufgabeVerschieben(lngKeydrop As Long, lngKeyDrag As Long)

    Dim db As DAO.Database

    Set db = CurrentDb

    If lngKeydrop = 0 Then

        db.Execute "DELETE FROM tblAufgabenUnteraufgaben WHERE UnteraufgabeID = " _

            & lngKeyDrag, dbFailOnError

    Else

        db.Execute "UPDATE tblAufgabenUnteraufgaben SET AufgabeID = " & lngKeydrop _

            & " WHERE UnteraufgabeID = " & lngKeyDrag, dbFailOnError

        If db.RecordsAffected = 0 Then

            db.Execute "INSERT INTO tblAufgabenUnteraufgaben(AufgabeID, UnteraufgabeID) VALUES(" _

                & lngKeydrop & ", " & lngKeyDrag & ")", dbFailOnError

        End If

    End If

    Set db = Nothing

End Sub

Die erste If...Then-Bedingung prüft, ob die Aufgabe auf eine Aufgabe mit dem Primärschlüsselwert 0 gezogen wurde. Die gibt es natürlich gar nicht, aber das Root-Element des Aufgabenbaums hat den Key t0.

Damit ein Element direkt unterhalb dieses Elements angezeigt wird, darf es keine übergeordnete Aufgabe besitzen. Die entsprechende AufgabeID darf also nicht im Feld UnteraufgabeID der Tabelle tblAufgabenUnteraufgaben vorkommen. Um dies zu erreichen, werden schlicht alle Datensätze aus dieser Tabelle gelöscht, die diese Bedingung erfüllen.

Falls die Aufgabe nicht auf das Root-Element, sondern auf eine echte Aufgabe gezogen wurde, versucht die Prozedur zunächst, einen eventuell vorhandenen Eintrag in der Tabelle tblAufgabenUnteraufgaben umzubiegen. Ist keiner vorhanden, war die gezogene Aufgabe wohl zuvor direkt dem Root-Element untergeordnet und es muss ein neuer Eintrag in der Tabelle tblAufgabenUnteraufgaben angelegt werden.

Heutige Aufgaben anlegen

Wenn der Benutzer eine Aufgabe aus dem TreeView in die Liste der heutigen Aufgaben zieht, soll dort ein Eintrag für die entsprechende Aufgabe angelegt werden. Außerdem soll die Eigenschaft HeuteZuErledigen auf den Wert True eingestellt werden.

Beides erledigt die Ereignisprozedur objDailyTasks_OLEDragDrop, die beim Fallenlassen einer Aufgabe im ListView-Steuerelement lvwDailyTasks ausgelöst wird (s. Listing 6). Die Prozedur liest den Wert des Parameters Data ein und ermittelt über den ersten Buchstaben des enthaltenen Ausdrucks die Herkunft des gezogenen Elements. Lautet dieser Buchstabe t, wurde eine Aufgabe aus dem TreeView in die Liste gezogen. In diesem Fall wird die Eigenschaft HeuteZuErledigen dieser Aufgabe auf True eingestellt. Das anschließende Neufüllen des Listenfeldes führt zum Anzeigen des neuen Eintrags.

Listing 6: Heutige Aufgaben anlegen und entfernen

Private Sub objDailyTasks_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, _

        Button As Integer, Shift As Integer, x As Single, y As Single)

    Dim strData As String

    Dim strDatatype As String

    Dim lngKeyDrag As Long

    Dim db As DAO.Database

    Set db = CurrentDb

    strData = Data.GetData(ccCFText)

    strDatatype = Left(strData, 1)

    lngKeyDrag = Mid(strData, 2)

    Select Case strDatatype

        Case "t"

            db.Execute "UPDATE tblAufgaben SET HeuteErledigen = True WHERE AufgabeID = " _

                & lngKeyDrag, dbFailOnError

        Case "d"

            If objDailyTasks.HitTest(x, y) Is Nothing Then

                db.Execute "UPDATE tblAufgaben SET HeuteErledigen = False WHERE AufgabeID = " _

                    & lngKeyDrag, dbFailOnError

            End If

    End Select

    FillDailyTasks

    Set db = Nothing

End Sub

Es gibt jedoch noch eine zweite Variante: Der Benutzer kann auch einen vorhandenen Eintrag in den leeren Bereich des ListView-Steuerelements ziehen, um diesen aus der Liste zu entfernen. Das bedeutet, dass der Parameter Data einen mit dem Buchstaben d beginnenden Eintrag liefert. Die Prozedur prüft dann noch, ob der Eintrag tatsächlich auf den leeren Bereich gezogen wurde (objDailyTasks.Hittext(x,y) Is Nothing), und stellt die Eigenschaft HeuteZuErledigen der Aufgabe auf den Wert False ein. Nach der Aktualisierung verschwindet dieser Eintrag aus der Liste.

Tätigkeiten anlegen

Das Listenfeld lvwTimeplan bietet einige Drag-and-Drop-Möglickeiten, die in der Ereignisprozedur objTimeplan_OLEDragDrop abgearbeitet werden (s. Listing 7). Auch diese Prozedur speichert den Wert des Parameters Data, der Informationen über das gezogene Element liefert, in der Variablen strData. Aus dieser wird der erste Buchstabe als Kennzeichen für das Herkunftssteuerelement in der Variablen strDatatype gespeichert. Die ID des Elements landet in der Variablen lngKeyDrag.

Listing 7: Tätigkeiten anlegen und verschieben

Private Sub objTimeplan_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, _

        Button As Integer, Shift As Integer, x As Single, y As Single)

    '... Variablendeklaration

    Set db = CurrentDb

    strData = Data.GetData(ccCFText)

    strDatatype = Left(strData, 1)

    lngKeyDrag = Mid(strData, 2)

    Set objDrop = objTimeplan.HitTest(x, y)

    If objDrop Is Nothing Then

        Exit Sub

    End If

    strKeyDrop = objDrop.Key

    lngKeydrop = Mid(strKeyDrop, 2)

    Select Case strDatatype

        Case "t" 'from tvwTasks

            Set objDrag = objTasks.Nodes(strData)

            objDrop.ListSubItems(1).Text = objDrag.Text

        Case "d" 'from lvwDailyTasks

            Set objDrag = objDailyTasks.ListItems(strData)

            objDrop.ListSubItems(1).Text = objDrag.Text

        Case "p" 'from lvwTimeplan

            Set objDrag = objTimeplan.ListItems(strData)

            If strKeyDrop = strKeyDrag Then

                Exit Sub

            End If

            lngKeyDrag = Nz(DLookup("AufgabeID", "tblTaetigkeiten", "TaetigkeitID = " & objDrag.Tag))

            If Not IsNull(lngKeyDrag) Then

                objDrop.ListSubItems(1).Text = objDrag.ListSubItems(1).Text

                If Shift = 0 Then 'verschieben

                    db.Execute "DELETE FROM tblTaetigkeiten WHERE Taetigkeitdatum = " _

                        & ISODatum(Me!txtDatum) & " AND Taetigkeitzeit = " _

                        & ISODatum(objDrag.Text), dbFailOnError

                        objDrag.ListSubItems(1).Text = ""

                End If

            End If

    End Select

    objDrop.Tag = AddTaskToTimeplan(lngKeyDrag, Me!txtDatum, objDrop.Text)

    If Not objDrag Is Nothing Then objDrag.Selected = False

    Set objTimeplan.DropHighlight = Nothing

    Set db = Nothing

End Sub

Danach folgt eine Prüfung, ob ein bestehender Listeneintrag als Ziel der Drag-and-Drop-Operation verwendet wurde. Falls nicht, wird die Prozedur beendet. Falls doch, sammelt die Prozedur die Informatoinen über das Zielelement in den Variablen strKeyDrop und lngKeyDrop. lngKeyDrop entspricht dabei der Position des Zieleintrags.

Zeigt das ListView-Steuerelement 8:00 als ersten Eintrag an und zieht der Benutzer eine Aufgabe auf diesen Eintrag, erhält lngKeyDrop beispielsweise den Wert 1.

Danach folgt eine Select Case-Bedingung, die je nach der Herkunft des gezogenen Elements verschiedene Aktionen durchführt.

Kommt das Element vom Aufgaben-TreeView, wird das Element referenziert und sein Text in die zweite Spalte des Zielelements geschrieben. Gleiches gilt, wenn das Element von der Liste der heutigen Aufgaben auf die Tätigkeitsliste gezogen wurde. Etwas komplizierter wird es, wenn der Benutzer einen Eintrag der Tätigkeitsliste auf einen anderen Eintrag der Tätigkeitsliste gezogen hat. In diesem Fall prüft die Prozedur zunächst, ob der Eintrag auf sich selbst gezogen wurde, und beendet gegebenenfalls die Prozedur.

Anderenfalls liest sie mit einer DLookup-Anweisung die AufgabeID ein, auf welcher die gezogene Tätigkeit basiert. Ist diese nicht Null, stellt die Prozedur den Text des Zielelements auf den Text des Quellelements ein. Nun kommt es noch darauf an, ob das Element bei gedrückter Strg-Taste gezogen wurde. Falls ja, soll das Element kopiert werden, falls nein, wird es verschoben. Ersteren Fall hätten wir bereits erledigt: Das bestehende Element ist noch vorhanden, das neue Element wurde angelegt. Wenn das Element verschoben werden soll, müssen wir das gezogene Element also noch löschen. Dies erledigt die Prozedur mit einer entsprechenden DELETE-SQL-Anweisung. Außerdem wird der Text des entsprechenden Elements noch geleert.

Sicher ist Ihnen aufgefallen, dass die beschriebenen Anweisungen dieser Prozedur bislang zwar eine Menge Elemente verschoben und kopiert haben, jedoch wurde nur das innerhalb der Tätigkeitenliste verschobene Element auch in der zugrunde liegenden Tabelle gelöscht - und immerhin haben wir in der Select Case-Anweisung bereits alle möglichen Fälle abgearbeitet.

Dies ist der Fall, weil die Vorgehensweise zum Anlegen einer neuen Tätigkeit im ListView-Steuerelement lvwTimeplan für alle Konstellationen gleich erfolgt, und zwar über einen Aufruf der Funktion AddTaskToTimeplan (s. Listing 8). Diese erwartet die AufgabeID, das Datum und die Zeit der neuen Tätigkeit.

Listing 8: Tätigkeit zum Timeplan hinzufügen

Private Function AddTaskToTimeplan(lngAufgabeID As Long, datTaetigkeitdatum As Date, _

        datTaetigkeitzeit As Date) As Long

    Dim db As DAO.Database

    Set db = CurrentDb

    db.Execute "DELETE FROM tblTaetigkeiten WHERE Taetigkeitdatum = " & ISODatum(datTaetigkeitdatum) _

        & " AND Taetigkeitzeit = " & ISODatum(datTaetigkeitzeit), dbFailOnError

    db.Execute "INSERT INTO tblTaetigkeiten(Taetigkeitdatum, Taetigkeitzeit, Bezeichnung, " _

        & "Beschreibung, AufgabeID, KategorieID, AngelegtAm) SELECT " _

        & ISODatum(datTaetigkeitdatum) & ", " & ISODatum(datTaetigkeitzeit) _

        & ", Aufgabe, Beschreibung, AufgabeID, KategorieID, " _

        & ISODatum(Now) & " AS AngelegtAm FROM tblAufgaben WHERE AufgabeID = " & lngAufgabeID, _

    dbFailOnError

    AddTaskToTimeplan = db.OpenRecordset("SELECT @@IDENTITY").Fields(0)

End Function

Sie löscht eine eventuell bereits vorhandene Tätigkeit für diese Zeit und legt einen neuen Datensatz in der Tabelle tblTaetigkeiten an, wobei die Daten aus dem Datensatz der Tabelle tblAufgaben entnommen werden, welcher der übergebenen AufgabeID entspricht.

Die Funktion gibt die TaetigkeitID der neuen Tätigkeit als Funktionswert zurück. Dieser wird der Eigenschaft Tag des entsprechenden Eintrags des ListView-Steuerelements lvwTimeplan zugewiesen, damit dieser beispielsweise beim Löschen per Kontextmenü identifiziert werden kann.

Zusammenfassung und Ausblick

Dieses komplexe Beispiel zeigt, wie Sie Drag and Drop für Formulare mit mehreren Drag-and-Drop-fähigen Steuerelementen wie ListView- und TreeView-Steuerelementen implementieren können. Sie können Elemente vom TreeView innerhalb des TreeViews verschieben oder löschen oder diese auf die beiden ListView-Steuerelemente ziehen. Damit definieren Sie heute zu erledigende Aufgaben oder die soeben durchgeführten Tätigkeiten.

Grundlagen zu den hier beschriebenen Techniken finden Sie beispielsweise in den Beiträgen Drag and Drop im TreeView-Steuerelement (http://www.access-im-unternehmen.de/320) oder Drag and Drop mit dem ListView-Steuerelement (http://www.access-im-unternehmen.de/334).

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Download

Download

Die .zip-Datei enthält folgende Dateien:

TagesablaufVerwalten.mdb

Beispieldateien downloaden

© 2003-2015 André Minhorst Alle Rechte vorbehalten.