Im ersten Teil dieses Beitrags haben wir die Grundlagen für die Arbeit mit Ordnern und Dateien im TreeView-Steuerelement gelegt: Ordner und Dateien im Explorer anzeigen und öffnen, das Ermitteln des Pfades über die Tabellen-IDs, Kontextmenüs für Ordner- und Datei-Elemente sowie die vollständige Implementierung der Ordner-Operationen Kopieren, Ausschneiden, Einfügen, Umbenennen und Löschen. Im vorliegenden zweiten Teil ergänzen wir die noch fehlenden Datei-Operationen und erörtern die Funktionen im Modul „mdlDateisystem“, welche die TreeView-Änderungen tatsächlich auf das Dateisystem übertragen.
Voraussetzung
Dieser Beitrag baut unmittelbar auf Teil 1 auf (www.access-im-unternehmen.de/1585). Alle dort beschriebenen Module, Funktionen und Formulare werden vorausgesetzt und hier nicht erneut erklärt.
Wir setzen auf dem dort beschriebenen Formular frmDateienImTreeView auf (siehe Bild 1).

Bild 1: Das TreeView-Steuerelement mit den Ordnern und Dateien
Ergänzung im Formular: SelectedItem setzen
Im Vergleich zum Listing aus Teil 1 wurde die Ereignisprozedur ctlTreeView_MouseDown um eine zusätzliche Zuweisung ergänzt. Bislang wurde objCurrentNode nur dann geleert und das markierte Element abgewählt, wenn kein Node getroffen wurde. Nun wird außerdem in allen anderen Fällen – also wenn tatsächlich ein Node-Element angeklickt wurde – die Eigenschaft SelectedItem des TreeView-Steuerelements explizit auf dieses Element gesetzt:
Set objCurrentNode = ctlTreeView.Object.HitTest(x, y) If objCurrentNode Is Nothing Then Me.ctlTreeView.Object.SelectedItem = Nothing Else Me.ctlTreeView.Object.SelectedItem = objCurrentNode End If
Das stellt sicher, dass beim Aufruf von Kontextmenü-Funktionen, die über Screen.ActiveControl auf das aktive Steuerelement zugreifen, das angeklickte Element stets korrekt als markiert gilt.
Datei einfügen – neuer Kontextmenü-Eintrag im Ordner-Menü
Das Kontextmenü für Ordner-Elemente wurde gegenüber dem in Teil 1 gezeigten Listing um einen weiteren Eintrag ergänzt.
Nach dem Eintrag Ordner umbenennen erscheint nun auch Datei einfügen, der die Funktion DateiEinfuegen ohne Parameter aufruft:
With cbr.Controls.Add(msoControlButton) .Caption = "Datei einfügen" .OnAction = "=DateiEinfuegen()" .FaceId = 2512 End With
Dieser Eintrag erlaubt es, eine zuvor kopierte oder ausgeschnittene Datei in den Zielordner einzufügen, ohne dass das Datei-Kontextmenü benötigt wird.
Da DateiEinfuegen keinen Key-Parameter erwartet, ermittelt die Funktion das Ziel-Element selbst über Screen.ActiveControl.Object.SelectedItem.
Das Kontextmenü für Dateien
Das Kontextmenü für Datei-Elemente wird in der Prozedur CreateCommandBarFile zusammengesetzt. Es enthält die fünf Einträge Datei kopieren, Datei ausschneiden, Datei umbenennen, Datei löschen und Datei mit Zielanwendung öffnen (siehe Bild 2).

Bild 2: Kontextmenü für Dateien
Der Aufbau der Prozedur aus Listing 1 ist identisch mit dem Ordner-Kontextmenü aus Teil 1.
Private Sub CreateCommandBarFile() Dim strKey As String Dim cbr As Office.CommandBar strKey = objCurrentNode.Key On Error Resume Next CommandBars("Ordner").Delete On Error GoTo 0 Set cbr = CommandBars.Add("Ordner", msoBarPopup, False, True) With cbr.Controls.Add(msoControlButton) .Caption = "Datei kopieren" .OnAction = "=DateiKopieren('" & strKey & "')" .FaceId = 1667 End With With cbr.Controls.Add(msoControlButton) .Caption = "Datei ausschneiden" .OnAction = "=DateiAusschneiden('" & strKey & "')" .FaceId = 1667 End With With cbr.Controls.Add(msoControlButton) .Caption = "Datei umbenennen" .OnAction = "=DateiUmbenennen()" .FaceId = 1667 End With With cbr.Controls.Add(msoControlButton) .Caption = "Datei löschen" .OnAction = "=DateiLoeschen('" & strKey & "')" .FaceId = 1667 End With With cbr.Controls.Add(msoControlButton) .Caption = "Datei mit Zielanwendung öffnen" .OnAction = "=DateiOeffnen('" & strKey & "')" .FaceId = 1667 End With cbr.ShowPopup End Sub
Listing 1: Prozedur zum Anzeigen des Kontextmenüs für Dateien
Der Key des angeklickten Nodes wird aus objCurrentNode.Key gelesen und an die jeweilige Funktion übergeben.
Alle fünf Funktionen liegen im Modul mdlKontextmenues.
Dateien kopieren und ausschneiden
Analog zu den bereits beschriebenen Ordner-Variablen strKeyOrdnerKopiert und strKeyOrdnerAusgeschnitten gibt es im Modulkopf von mdlKontextmenues zwei weitere öffentliche Variablen für Dateien:
Public strKeyDateiKopiert As String Public strKeyDateiAusgeschnitten As String
Die zugehörigen Funktionen schreiben den Key in die jeweilige Variable und leeren die andere:
Public Function DateiKopieren(strKey As String) strKeyDateiKopiert = strKey strKeyDateiAusgeschnitten = "" End Function Public Function DateiAusschneiden(strKey As String) strKeyDateiAusgeschnitten = strKey strKeyDateiKopiert = "" End Function
Das Vorgehen ist das gleiche, das wir in Teil 1 bereits für Ordner beschrieben haben.
Eine Datei umbenennen
Beim Umbenennen einer Datei gibt es einen kleinen Unterschied zu Ordnern. Die Funktion OrdnerUmbenennen greift direkt über die globale Variable objTreeView auf das Steuerelement zu.
Für Dateien wurde eine andere Lösung gewählt, weil der Umbenennen-Befehl über das Datei-Kontextmenü ohne Key-Parameter aufgerufen wird. Die Funktion holt sich das aktive Steuerelement über Screen.ActiveControl:
Public Function DateiUmbenennen() Dim ctlTreeView As Object Set ctlTreeView = Screen.ActiveControl ctlTreeView.Object.StartLabelEdit End Function
Das bereits aus Teil 1 bekannte Ereignis ctlTreeView_AfterLabelEdit im Formularmodul übernimmt dann den neuen Namen sowohl in die Tabelle tblFiles als auch im Dateisystem über den Aufruf von FS_DateiUmbenennen.
Eine Datei löschen
Die Funktion DateiLoeschen löscht eine Datei aus dem Dateisystem, aus der Tabelle tblFiles und aus dem TreeView-Steuerelement (Listing 2).
Sie übernimmt den Key des zu löschenden Elements, ermittelt daraus die ID und holt sich das aktive Steuerelement über Screen.ActiveControl.
Public Function DateiLoeschen(strKey As String) Dim db As DAO.Database Dim lngID As Long Dim ctlTreeView As Object Set ctlTreeView = Screen.ActiveControl lngID = Mid(strKey, 2) Set db = CurrentDb If FS_DateiLoeschen(lngID) = True Then db.Execute "DELETE FROM tblFiles WHERE FileID = " _ & lngID, dbFailOnError ctlTreeView.Object.Nodes.Remove "i" & lngID End If End Function
Nur wenn FS_DateiLoeschen den Wert True zurückgibt – also die Datei tatsächlich im Dateisystem gelöscht werden konnte – werden auch der Datenbank-Datensatz und der TreeView-Eintrag entfernt. Das vermeidet inkonsistente Zustände.
Eine Datei öffnen
Um eine Datei in der zugehörigen Standardanwendung zu öffnen, nutzen wir die Funktion DateiOeffnen. Sie ermittelt aus dem Key die ID, ruft GetFilePath auf und übergibt den vollständigen Pfad an FollowHyperlink:
Public Function DateiOeffnen(strKey As String) As Long Dim strPath As String Dim lngID As Long lngID = Mid(strKey, 2) strPath = GetFilePath(lngID) FollowHyperlink strPath End Function
Das Ergebnis ist identisch mit dem Doppelklick-Verhalten, das wir bereits in Teil 1 beschrieben haben. Zusätzlich ist der Befehl nun auch über das Kontextmenü erreichbar.
Eine Datei einfügen
Die Funktion DateiEinfuegen ist die komplexeste der Datei-Kontextmenü-Funktionen, weil sie sowohl den Fall des Einfügens einer kopierten als auch einer ausgeschnittenen Datei behandelt (siehe Listing 2).
Public Function DateiEinfuegen() As Long Dim db As DAO.Database, ctlTreeView As Object, objSourceItem As MSComctlLib.Node Dim lngSourceID As Long, lngTargetID As Long Dim strSourceKey As String, strSourceText As String, strTargetKey As String Dim bolKopiert As Boolean, bolAusgeschnitten As Boolean, lngNewID As Long Set db = CurrentDb If Not Len(strKeyDateiKopiert) = 0 Then lngSourceID = Mid(strKeyDateiKopiert, 2) bolKopiert = True Else If Not Len(strKeyDateiAusgeschnitten) = 0 Then lngSourceID = Mid(strKeyDateiAusgeschnitten, 2) bolAusgeschnitten = True End If End If If Not lngSourceID = 0 Then Set ctlTreeView = Screen.ActiveControl strTargetKey = ctlTreeView.Object.SelectedItem.Key lngTargetID = Mid(strTargetKey, 2) If bolKopiert = True Then If FS_DateiKopieren(lngSourceID, lngTargetID) = True Then strSourceKey = "i" & lngSourceID Set objSourceItem = ctlTreeView.Object.Nodes(strSourceKey) strSourceText = objSourceItem.Text db.Execute "INSERT INTO tblFiles SELECT Filename, " _ & lngTargetID & " AS ParentID, FileSize, Filedatetime" _ & " FROM tblFiles WHERE FileID = " & lngSourceID, dbFailOnError lngNewID = db.OpenRecordset("SELECT @@IDENTITY").Fields(0) ctlTreeView.Object.Nodes.Add "f" & lngTargetID, tvwChild, _ "i" & lngNewID, strSourceText, "book" End If Else If FS_DateiVerschieben(lngSourceID, lngTargetID) = True Then strSourceKey = "i" & lngSourceID Set objSourceItem = ctlTreeView.Object.Nodes(strSourceKey) strSourceText = objSourceItem.Text db.Execute "UPDATE tblFiles SET ParentID = " & lngTargetID _ & " WHERE FileID = " & lngSourceID, dbFailOnError If db.RecordsAffected = 1 Then ctlTreeView.Object.Nodes.Remove strSourceKey ctlTreeView.Object.Nodes.Add "f" & lngTargetID, tvwChild, _ "i" & lngSourceID, strSourceText, "book" End If End If End If End If End Function
Listing 2: Funktion zum Einfügen einer kopierten oder ausgeschnittenen Datei
Die Funktion prüft zunächst, ob eine Datei zum Kopieren oder zum Ausschneiden markiert ist. Das Ziel-Element – also der Ordner, in den eingefügt werden soll – wird über das aktuell im TreeView-Steuerelement selektierte Element bestimmt.
Die Quelle wird über die ID aus strKeyDateiKopiert beziehungsweise strKeyDateiAusgeschnitten ermittelt.
Beim Kopieren rufen wir FS_DateiKopieren auf. Ist das erfolgreich, legen wir in der Tabelle tblFiles einen neuen Datensatz an – mit einem INSERT INTO … SELECT-Ausdruck, der Dateiname, Größe und Datum übernimmt, aber die neue ParentID verwendet.
Die neue FileID ermitteln wir danach mit SELECT @@IDENTITY und fügen das Element unter dem Zielordner in das TreeView-Steuerelement ein.
Beim Ausschneiden rufen wir FS_DateiVerschieben auf. Nach erfolgreichem Verschieben aktualisieren wir die ParentID des vorhandenen Datensatzes in tblFiles per UPDATE.
Wir prüfen über db.RecordsAffected, ob genau ein Datensatz geändert wurde.
Ist das der Fall, entfernen wir den Node an seiner alten Position und fügen ihn beim Zielordner neu ein.
Nur für Abonnenten
Ab hier wird’s wirklich spannend – der Rest ist exklusiv für Abonnenten.
Mit dem Abo von Access im Unternehmen bekommst du den kompletten Artikel – inklusive vollständigem Code, Beispieldatenbank und Schritt-für-Schritt-Erklärung.
So sparst du dir stundenlanges Herumprobieren, vermeidest teure Fehler in deiner Access-Anwendung und kannst Lösungen direkt in deinem Unternehmen einsetzen, statt nur darüber zu lesen.
Teste Access im Unternehmen jetzt 4 Wochen lang kostenlos: Voller Zugriff auf alle Artikel, Downloads und Beispieldatenbanken. Kein Risiko – wenn es für dich nicht passt, kündigst du einfach innerhalb der ersten vier Wochen.
Bereits Abonnent? Hier einloggen
Kostenlos & unverbindlich
Oder hast Du eine konkrete Frage zu Deiner eigenen Access-Anwendung?
Vielleicht stellt Deine Anwendung Dich vor eine Herausforderung, zu der Du bisher keine Lösung findest. Schlechte Performance, kein ausreichender Zugriffsschutz, Du bist unsicher über Dein Datenmodell oder Dein Code liefert unerklärliche Fehler?
In unserem kostenlosen Access-Audit schaut sich André Minhorst persönlich gemeinsam mit Dir Deine Lösung per Zoom an – und zeigt Dir, wo Datenmodell, VBA-Code, Ergonomie und Sicherheit Optimierungspotenzial bieten.
Jetzt kostenloses Access-Audit anfordern →