Treeview ohne MSCOMCTL

Dieser Artikel ist Teil des Magazins 'Access im Unternehmen', Ausgabe 5/2017.

Treeview ohne MSCOMCTL

Im Juli/August 2017 war es wieder mal soweit: Microsoft hat ein Update für einige Office-Varianten geliefert, das die TreeView-Steuerelemente in den Anwendungen auf den betroffenen Rechnern lahmgelegt hat. Zwar gibt es ein paar Wochen später immer einen Patch oder ein weiteres Update zur Behebung des Fehlers, aber wer kurzfristig handeln muss, darf manuell an der Datei MSCOMCTL.ocx und/oder der Registry herumpfuschen. Das kann man natürlich keinem Kunden zumuten, daher zeigen wir eine mögliche Lösung.

Normalerweise beschreiben wir in Access im Unternehmen keine Tools von Drittanbietern, die kostenpflichtig sind. Im Falle des Treeviews scheint es jedoch sinnvoll, eine Ausnahme zu machen. Thomas Pfoch hat mit seiner Firma picoware einen TreeView-Ersatz programmiert, der komplett ohne zusätzliche Dateien wie .ocx- oder .dll-Dateien auskommt.

Er verwendet stattdessen ein Unterformular, das er geschickt aufbohrt, um Daten nach den Vorgaben des Benutzers anzuzeigen und diese – wie es für ein Treeview typisch ist – für die untergeordneten Ebenen nach rechts einzurücken.

Wenn Sie diese Erweiterung nutzen, müssen Sie lediglich einige Objekte aus der Beispieldatenbank, die Sie nach dem Erwerb des Pakets erhalten, in die Zieldatenbank kopieren. Darunter befindet sich auch ein Formular, das Sie als Unterformular in das Zielformular einfügen.

Im Code, der beim Laden des Zielformulars ausgelöst wird, tragen Sie dann die Anweisungen ein, welche die anzuzeigenden Daten definieren.

Der picoware-Treeview kostet 299,- EUR (inkl. 19% MwSt.) pro Entwicklerlizenz. Das heißt, dass Sie für jeden Entwickler, der das Tools einsetzt, eine Lizenz benötigen. Dieser Entwickler kann allerdings beliebig viele Anwendungen mit den Treeview-Funktionen ausstatten und weitergeben. Gemessen an dem Ärger, den die regelmäßigen Updates der Datei MSCOMCTL.ocx mit sich bringen, ist dies nach unserem Ermessen eine sinnvolle Investition.

Hinzu kommt, dass Sie als Leser von Access im Unternehmen im Shop unter www.amvshop.de 20% Rabatt erhalten, und zwar mit dem Gutscheincode aiu-treeview.

Vorteile des picoware-Treeviews

Zu den Vorteilen des picoware-Treeviews gehören die folgenden:

  • Es ist keine externe Komponente mehr erforderlich, die durch Updates kompromittiert werden könnte.
  • Es funktioniert nicht nur unter 32bit-Versionen von Access, sondern auch unter 64bit.
  • Die Elemente können per spezieller SQL-Abfrage und somit mit wesentlich weniger Code zugewiesen werden.

Nachteile des picoware-Treeviews

Durch die Anpassung an die Eigenarten einer Datenbank mit ihren in Tabellen gespeicherten Daten und durch die Verwendung eines Unterformulars zur Realisierung TreeViews ergeben sich auch ein paar Nachteile:

  • Bestehende MSCOMCTL-TreeViews lassen sich nicht ohne weiteres in das picoware-Treeview umwandeln.
  • Durch die Verwendung eines Unterformulars kommt es beim Aktualisieren von Daten und anderen Vorgängen manchmal zum Neuaufbau des Treeviews.

Beispieldatenbank

Wenn Sie nicht sicher sind, ob das Tool das Richtige für Sie ist, können Sie unter dem Link http://shop.minhorst.com/access-tools/322/picoware-treeview Beispieldatenbanken für verschiedene Access-Versionen herunterladen, welche die Möglichkeiten des Tools demonstrieren. Auf den folgenden Seiten zeigen wir Ihnen, wie Sie das picoware-Treeview programmieren.

picoware-Treeview-Elemente hinzufügen

Nach dem Erwerb und dem Download erhalten Sie eine Datenbank etwa namens treeview_20170629_1451_Source.mdb. Diese enthält alle Objekte, die Sie für den Einsatz in eigenen Datenbanken benötigen.

Sie brauchen sich keine Mühe zu machen, die benötigen Objekte selbst in die Zieldatenbank zu ziehen. Die Datenbank aus dem Download enthält ein Tool, das Ihnen diese Arbeit abnimmt. Dazu öffnen Sie das Formular namens Tool_CopyCode. Dieses zeigt eine Treeview-Ansicht der Verzeichnis- und Dateistruktur auf Ihrer Festplatte an, wobei das Verzeichnis der Quelldatenbank geöffnet wird (s. Bild 1).

Auswahl der Zieldatenbank für die Datenbankobjekte

Bild 1: Auswahl der Zieldatenbank für die Datenbankobjekte

Wählen Sie hier die Zieldatenbank aus und klicken Sie auf die Schaltfläche Copy. Dies kopiert nun alle notwendigen Datenbankobjekte in die ausgewählte Datenbank. Falls nötig, halten Sie dabei die Umschalttaste gedrückt.

Erstes Beispiel: Kategorien auflisten

Im ersten Beispiel wollen wir einfach die Daten der Tabelle tblKategorien im Treeview anzeigen. Dazu erstellen Sie ein neues Formular namens frmKategorien, öffnen es in der Entwurfsansicht und ziehen das Formular USys_pTV_TreeView als Unterformular in den Entwurf. Stellen Sie den Namen des Unterformular-Steuerelements auf sfmTreeView ein.

Passen Sie außerdem die Größe des Unterformulars an, das initial in der vollen Breite eingefügt wird (s. Bild 2). Stellen Sie außerdem die Eigenschaften Bildlaufleisten, Datensatzmarkierer, Navigationsschaltflächen und Trennlinien auf den Wert Nein ein – das Hauptformular selbst zeigt keine Daten an, sodass wir diese Elemente nicht benötigen.

Einfügen des Unterformulars und Anpassen der Größe

Bild 2: Einfügen des Unterformulars und Anpassen der Größe

Ein erster Wechsel in die Formularansicht liefert natürlich noch kein sinnvolles Ergebnis – kein Wunder, denn wir füllen das Treeview ja auch noch nicht mit Daten (s. Bild 3). Das ändern wir allerdings in den folgenden Schritten.

Erster Wechsel in die Formularansicht

Bild 3: Erster Wechsel in die Formularansicht

Dazu fügen Sie dem Klassenmodul des Formulars frmKategorien, das Sie durch Einstellen der Eigenschaft Enthält Modul des Formulars anlegen, eine Objektvariable hinzu, welche das Unterformular zur Anzeige des Treeviews referenzieren soll:

Public WithEvents objTreeView As  Form_USys_pTV_TreeView

Die Deklaration enthält das Schlüsselwort With­Events, damit wir innerhalb der Klasse auch die Ereignisse dieses Formulars beziehungsweise der Formularklasse Form_USys_pTV_TreeView implementieren können.

Damit wir das Unterformular zur Anzeige des Treeviews füllen können, weisen wir der Objektvariablen objTreeView das im Unterformularsteuerelement sfmTreeView gespeicherte Formular zu, und zwar in der Prozedur, die durch das Ereignis Beim Öffnen des Hauptformulars ausgelöst wird:

Private Sub Form_Open(Cancel As Integer)
     Set objTreeView = Me!Treeview.Form
End Sub

Treeview mit Daten füllen

Damit wäre das Treeview-Unterformular schon einmal referenziert. Nun wollen wir diese noch mit den gewünschten Daten füllen, in diesem Falle den Namen der Kategorien aus der Tabelle tblKategorien.

Beim MSCOMCTL.ocx-TreeView hätten Sie jedes Element einzeln mit der Add-Methode hinzufügen müssen. Hier spielt das speziell auf die Anzeige von Daten aus Tabellen oder Abfragen ausgelegte picoware-Treeview seine Stärken aus. Sie müssen lediglich eine SQL-Anweisung mit einem bestimmten Format definieren, welche die anzuzeigenden Daten liefert, und diese mit der AddSQL-Methode dem in der Variablen objTreeView gespeicherten Treeview zuweisen. Das sieht dann beispielsweise wie in Listing 1 aus.

Private Sub Form_Open(Cancel As Integer)
     Dim strSQL As String
     Set objTreeView = Me!Treeview.Form
     strSQL = "SELECT KategorieID AS Reference, Kategoriename AS Caption, 'Kategorie' AS RefContext " _
         & "FROM tblKategorien"
     objTreeView.AddSQL strSQL
End Sub

Listing 1: Anzeigen der Kategorien beim Öffnen des Formulars

Ein Wechsel zur Formularansicht liefert bereits ein akzeptables Ergebnis (s. Bild 4) – und das mit einer sehr überschaubaren Anzahl von Codezeilen!

Die Kategorien im picoware-Treeview

Bild 4: Die Kategorien im picoware-Treeview

Erläuterung des SQL-Ausdrucks

Der zum Füllen des Treeviews verwendete SQL-Ausdruck sieht zusammengefasst wie folgt aus:

SELECT KategorieID AS Reference, Kategoriename AS Caption, 'Kategorie' AS RefContext FROM tblKategorien

Hier erkennen Sie drei Felder, die jeweils mit einem ALIAS-Namen ausgestattet wurden. Dies dient dem Zweck, dass das Treeview beim Anzeigen der Daten genau weiß, welches Feld die Daten für welchen Zwecke enthält. Wir verwenden die folgenden drei ALIAS-Bezeichnungen:

  • Reference: Das hier genannte Feld, in diesem Fall KategorieID, wird nicht angezeigt, sondern als Referenz verwendet, wenn die untergeordnete Ebene Daten aufnehmen soll, die über ein Fremdschlüsselfeld, das ebenfalls speziell gekennzeichnet wird, entsprechend verknüpfte Daten enthält.
  • Caption: Das mit dem ALIAS namens Caption versehene Feld enthält den im Treeview anzuzeigenden Wert, in diesem Fall den Inhalt des Feldes Kategoriename.
  • RefContext: Dieses Feld nimmt eine Zeichenkette auf, mit der Sie den Typ des daraus generierten Elements im TreeView definieren – in diesem Fall Kategorie. Im folgenden Beispiel werden Sie sehen, wie Sie die hierfür angegebene Zeichenkette nutzen können.

Artikel zu Kategorien hinzufügen

Nun gehen wir einen Schritt weiter und fügen in einer zweiten Ebene noch die zu einer jeden Kategorie gehörenden Artikel hinzu. Dazu kopieren Sie das soeben erstellte Formular und fügen es unter dem Namen frmKategorienArtikel erneut in die Datenbank ein (frmKategorie markieren, Strg + C, Strg + V, neuen Namen eingeben).

Am Entwurf des Formulars brauchen Sie keine Änderungen vorzunehmen, wir kümmern uns nur um den Code.

Wie zuvor soll beim Öffnen des Formulars die Liste der Kategorien erscheinen. Beim Klick auf eines der Plus-Zeichen sollen die zur jeweiligen Kategorie gehörenden Artikel im Treeview angezeigt werden.

Dazu implementieren wir ein Ereignis der Klasse Form_USys_pTV_TreeView. Zu diesem Zweck wechseln Sie zum VBA-Fenster des Klassenmoduls des Formulars frmKategorienArtikel, wählen im linken Kombinationsfeld des Fensters den Eintrag objTreeView und im rechten Kombinationsfeld den Eintrag ItemOpened aus (s. Bild 5).

Implementieren einer Ereignisprozedur des picoware-Treeviews

Bild 5: Implementieren einer Ereignisprozedur des picoware-Treeviews

Dies legt die folgende Ereignisprozedur an:

Private Sub objTreeView_ItemOpened(Context As  USys_pCT_Context, ByVal RefPath As String)
End Sub

Die Ereignisprozedur wird immer ausgelöst, wenn der Benutzer auf einen der Einträge im Treeview klickt. Dies können Sie ausprobieren, indem Sie einen Haltepunkt für die erste Zeile der Prozedur festlegen und auf eine der Kategorien im Beispielformular frmKategorienArtikel klicken.

Nun wollen wir die Zeilen hinzufügen, die dafür sorgen, dass beim Anklicken des Plus-Zeichens einer Kategorie die untergeordneten Artikel im Treeview erscheinen. Diese Prozedur sieht wie in Listing 2 aus.

Private Sub objTreeView_ItemOpened(Context As USys_pCT_Context, ByVal RefPath As String)
    Dim strSQL As String
    Dim lngReference As Long
    lngReference = Context.SettingLong("Reference", -1)
    strSQL = "Select ArtikelID As Reference, 'Artikel' As RefContext, Artikelname As Caption " _
          & "FROM tblArtikel WHERE KategorieID = " & lngReference
    objTreeView.AddSQL strSQL, RefPath
End Sub

Listing 2: Ereignisprozedur, welche die Artikel für die angeklickte Kategorie einblendet

Eine zusätzliche Zeile deklariert eine Variable namens lngReference mit dem Datentyp Long, eine weitere füllt diese mit einem Wert, den der Ausdruck Context.SettingLong("Reference", -1) liefert. Context ist einer der beiden Parameter, der beim Auslösen der Ereignisprozedur übergeben wird.

Dieser liefert einige Informationen rund um das angeklickte Element und auch einige mögliche Methoden. In diesem Fall verwenden wir die Funktion SettingLong, um den Wert des Attributs Reference zu ermitteln. Dabei handelt es sich um den Wert des angeklickten Elements, der in der SQL-Anweisung, welche dieses Element definiert, für das Feld mit dem ALIAS-Namen Reference übergeben wurde – in diesem Fall also der Wert des Feldes KategorieID für den angeklickten Eintrag.

Diesen Wert speichern wir in der Variablen lngReference und nutzen ihn in der nachfolgend zusammengestellten SQL-Anweisung als Vergleichswert des Kriteriums. Für die KategorieID mit dem Wert 5 sieht die SQL-Abfrage etwa so aus:

Select ArtikelID As Reference, 
'Artikel' As RefContext, 
Artikelname As Caption 
FROM tblArtikel 
WHERE KategorieID = 5

Danach folgt dann auch für die Elemente dieser zweiten Ebene der Aufruf der Methode AddSQL des Objekts aus objTreeView. Diesmal verwenden wir allerdings auch den zweiten Parameter dieser Methode und übergeben dieser den unveränderten Wert des zweiten Parameters der Ereignisprozedur namens RefPath.

Was enthält dieser Parameter? Dies erfahren wir wieder, indem wir einen Haltepunkt setzen und dann nach dem Abarbeiten der ersten Zeile mit der Maus über den Parameter fahren (s. Bild 6).

Ermitteln eines der Parameter der Ereignisprozedur

Bild 6: Ermitteln eines der Parameter der Ereignisprozedur

Es handelt sich also um die Zeichenfolge /5/, wobei der Wert 5 wieder dem Referenzwert des auslösenden Elements entspricht. Diesen übergeben wir der Methode AddSQL, damit diese weiß, an welches Element sie die neuen Elemente anfügen soll.

Das Ergebnis der neu hinzugefügten Funktion finden Sie schließlich in der Formularansicht aus Bild 7.

Treeview mit zwei Ebenen

Bild 7: Treeview mit zwei Ebenen

Öffnen-Klick auf der zweiten Ebene

Was geschieht aber nun, wenn wir auf das Plus-Zeichen eines der Elemente der zweiten Ebene klicken? Dies bewirkt in den meisten Fällen nichts, außer dass das Plus-Zeichen für den angeklickten Eintrag verschwindet.

Es kann aber auch sein, dass sich eine weitere Ebene öffnet, welche nochmal die gleichen Artikel wie die zweite Ebene enthält, von der aus ein Element aufgeklappt wurde. Aber was geschieht dort im Detail? Da es nur eine Ereignisprozedur namens ItemOpened für alle Elemente des Treeviews gibt, wird diese natürlich auch beim Klicken auf das Plus-Zeichen eines der Elemente der zweiten Ebene mit den Artikeln ausgelöst.

Der Parameter RefPath liefert nun einen Wert wie etwa /5/52/, wobei der Wert 5 dem Referenzwert für das Element der ersten Ebene und 52 dem Referenzwert für das Element der zweiten Ebene, also des Artikels, entspricht. Der Ausdruck Context.SettingLong("Reference", -1) liefert nun den Primärschlüsselwert des angeklickten Elements der zweiten Ebene.

Die SQL-Anweisung ermittelt nun alle Elemente der Tabelle tblArtikel, deren Feld KategorieID den Wert 52 enthält – was in diesem Fall keine Ergebnisse liefert. Hätten wir einen Artikel angeklickt, dessen Wert im Feld ArtikelID auch im Feld KategorieID eines der Datensätze der Tabelle tblKategorien vorkommt, hätte dies alle Datensätze der Tabelle tblArtikel zu dieser Kategorie geliefert. Das soll aber natürlich so nicht geschehen.

Also erweitern wir die Ereignisprozedur objTreeView_Item­Opened wie in Listing 3. Sie erinnern sich, dass wir gleich in der SQL-Anweisung für das Hinzufügen der Kategorie-Elemente ein Feld mit dem ALIAS-Namen RefContext und dem Wert 'Kategorie' übergeben haben. Diesen nutzen wir nun, um zu ermitteln, ob der Benutzer auf eines der Elemente der ersten Ebene, also auf eine Kategorie geklickt hat oder auf eines der Objekte einer anderen Ebene.

Private Sub objTreeView_ItemOpened(Context As USys_pCT_Context, ByVal RefPath As String)
     Dim strSQL As String
     Dim lngReference As Long
     Dim strRefContext As String
     strRefContext = Context.SettingNz("RefContext", "Root")
     Select Case strRefContext
         Case "Kategorie"
             lngReference = Context.SettingLong("Reference", -1)
             strSQL = "Select ArtikelID As Reference, 'Artikel' As RefContext, Artikelname As Caption " _
                    & "FROM tblArtikel WHERE KategorieID = " & lngReference
             objTreeView.AddSQL strSQL, RefPath
     End Select
End Sub

Listing 3: Neue Version der Ereignisprozedur, welche die Artikel für die angeklickte Kategorie einblendet

Wir ermitteln diesen Wert über den Ausdruck Context.SettingNz("RefContext", "Root"), was im Falle des Erweiterns eines der Elemente der ersten Ebene den Wert Kategorie zurückliefert (ist kein RefContext angegeben, lautet der Wert Root). Diesen speichern wir in der Variablen strRefContext und prüfen ihn in einer Select Case-Bedingung. Diese hat nur einen Case-Zweig, der im Falle des Wertes Kategorie aufgerufen wird und die Einträge der Tabelle tblArtikel für die angegebene Kategorie hinzufügt. Wenn wir nun also auf das Plus-Zeichen eines Eintrags der zweiten Ebene, also eines Artikels klicken, liefert Context.SettingNz("RefContext", "Root") den Wert Artikel, für den es keinen Case-Zweig in der Select Case-Variablen gibt. Dementsprechend geschieht auch nichts weiter.

Erst, wenn Sie noch weitere Elemente unterhalb der Artikel-Elemente anzeigen wollten, müssten Sie einen weiteren Case-Zweig zur Select Case-Bedingung hinzufügen.

Unnötige Plus-Zeichen ausblenden

Nun haben wir zunächst einmal zwei Ebene mit Daten zum Treeview hinzugefügt. Sie haben auch gesehen, dass das Plus-Zeichen für Einträge der zweiten Ebene, die ja keine weiteren Einträge enthält, verschwinden, wenn Sie diese anklicken. Dies sollte aber bereits vorher so sein, denn wozu benötigt man ein Element zum Aufklappen von untergeordneten Elementen, wenn keine solchen vorhanden sind? Also kümmern wir uns um diese kleine Schönheitskorrektur.

In unserem Beispiel ist dazu nur ein recht kleiner Aufwand erforderlich – wir müssen lediglich der SQL-Anweisung ein weiteres Feld zuweisen, das den ALIAS-Namen ChildCount trägt und den Wert 0 enthält:

strSQL = "Select ArtikelID As Reference, 
'Artikel' As RefContext, 
Artikelname As Caption, 
0 AS ChildCount 
FROM tblArtikel 
WHERE KategorieID = " & lngReference

Das Ergebnis sieht wie in Bild 8 aus.

Keine Erweiterungssymbole in der zweiten Ebene

Bild 8: Keine Erweiterungssymbole in der zweiten Ebene

Was aber, wenn wir Ebenen mit Daten haben, die teilweise untergeordneten Elemente besitzen und teilweise nicht? Dazu fügen wir etwa eine Kategorie zur Tabelle tblKategorien hinzu, für die es in der Tabelle tblArtikel keine passenden Artikel gibt.

Damit für dieses Element kein Plus-Zeichen zum Aufklappen des Elements angezeigt wird, müssen wir die SQL-Abfrage für die erste Ebene mit den Kategorien so umformulieren, dass ChildCount den Wert 0 erhält, wenn keine untergeordneten Element vorliegen und anderenfalls einen anderen Wert.

Diese Abfrage stellen wir der Einfachheit halber zunächst in der Entwurfsansicht einer neuen Abfrage zusammen. Dazu fügen Sie die beiden Tabellen tblKategorien und tblArtikel hinzu, wobei die Verknüpfung zwischen den beiden Tabellen automatisch mit eingefügt wird.

Fügen Sie die Felder mit den entsprechenden ALIAS-Namen wie in Bild 9 zum Entwurfsraster der Abfrage hinzu. Wenn es nun in der Tabelle tblKategorien einen Datensatz gibt, mit dem kein Datensatz der Tabelle tblArtikel verknüpft ist, wird gar kein Datensatz für diese Kategorie angezeigt. Also stellen wir die Verknüpfungseigenschaften so ein, dass alle Datensätze der Tabelle tblKategorien geliefert werden, auch wenn es keinen verknüpften Datensatz in der Tabelle tblArtikel gibt. Nun soll auch noch jede Kategorie nur einmal angezeigt werden und nicht für jede Kombination aus Kategorie und Artikel jeweils einmal, also stellen wir die Eigenschaft Keine Duplikate der Abfrage auf Nein ein. Schließlich fehlt nun noch ein Weg, die Anzahl der Datensätze der Tabelle tblArtikel für die jeweilige Kategorie zu liefern.

Abfrage, welche die Daten einer Tabelle samt Anzahl der untergeordneten Elemente liefern soll.

Bild 9: Abfrage, welche die Daten einer Tabelle samt Anzahl der untergeordneten Elemente liefern soll.

Dazu fügen Sie durch einen Klick auf den Ribbon-Eintrag Entwurf|Einblenden/Ausblenden|Summen die Zeile Funktion im Abfrageentwurf ein. Hier legen Sie für die Felder Reference: KategorieID und Caption: Kategoriename den Wert Gruppierung, für RefContext: 'Kategorie' den Wert Ausdruck und für ChildCount: ArtikelID den Wert Anzahl fest. Damit erhalten Sie ein Abfrageergebnis wie in Bild 10.

Kategorien mit der Anzahl der Unterelemente

Bild 10: Kategorien mit der Anzahl der Unterelemente

Nun wechseln Sie in die SQL-Abfrage, kopieren den Abfragetext und fügen diesen wie in Listing 4 in der Prozedur Form_Open für die Variable strSQL ein.

Private Sub Form_Open(Cancel As Integer)
     Dim strSQL As String
     Set objTreeView = Me!sfmTreeview.Form
     strSQL = "SELECT DISTINCT tblKategorien.KategorieID AS Reference, 'Kategorie' AS RefContext, " _
          & "tblKategorien.Kategoriename AS Caption, Count(tblArtikel.ArtikelID) AS ChildCount FROM tblKategorien " _
          & "LEFT JOIN tblArtikel ON tblKategorien.KategorieID = tblArtikel.KategorieID " _
          & "GROUP BY tblKategorien.KategorieID, tblKategorien.Kategoriename"
     objTreeView.AddSQL strSQL
End Sub

Listing 4: Diese Version der Prozedur Form_Open liefert nur Plus-Zeichen für Kategorien, die auch Unterelemente enthalten.

Icons

Um die optische Seite abzurunden, wollen wir nun noch ein paar individuelle Icons für die Elemente des Treeviews hinzufügen. Dazu legen wir eine neue Kopie unseres Beispielformulars an und nennen dieses frmKategorienArtikelIcons. Icons werden in der Tabelle USys_pTV_Icon verwaltet, die Sie eventuell nicht sehen – was aber kein Problem ist. Fügen Sie aus der Quelldatenbank mit den Beispielen das Formular Tool_Icons zur Zielanwendung hinzu. Um ein Icon etwa aus einer .png-Datei zu dieser Tabelle hinzuzufügen, gehen Sie wie folgt vor:

  • Öffnen Sie die Bilddatei in einem Bildbearbeitungsprogramm wie beispielsweise Paint (s. Bild 11).
  • Ein Icon in Paint

    Bild 11: Ein Icon in Paint

  • Kopieren Sie das komplette Bild durch Strg + A, Strg + C.

Legen Sie einen neuen Datensatz im Formular Tools_Icons an, klicken Sie auf die noch leere Bild-Spalte mit der entsprechenden Größe (also etwa 16 x 16) des neuen Datensatzes und fügen Sie den Inhalt der Zwischenablage mit Strg + V ein. Das Ergebnis sieht dann wie in Bild 12 aus.

Verwalten der Icons

Bild 12: Verwalten der Icons

Prüfen Sie danach durch einen Blick in die Tabelle USys_pTV_Icon, ob für den neuen Datensatz in der Spalte mit der entsprechenden Größe (hier Pic016), dass dort Bild steht und nicht etwa Bitmap Image, was nicht unter Umständen nicht funktioniert (s. Bild 13).

Prüfen, ob das Bild mit dem richtigen Typ angelegt wurde und nicht etwa mals Bitmap Image

Bild 13: Prüfen, ob das Bild mit dem richtigen Typ angelegt wurde und nicht etwa mals Bitmap Image

Wie zeigen wir das Bild nun an? Im ersten Fall wollen wir alle Elemente der ersten Ebene mit dem Folder-Symbol ausstatten. Dazu können wir dieses fix unter dem ALIAS-Namen IconName als Zeichenkette angeben.

Die entsprechende SQL-Abfrage in der Prozedur Form_Open des neuen Formulars frmKategorienArtikelIcons erweitern wir also um das Feld 'Kategorie' AS IconName:

Private Sub Form_Open(Cancel As Integer)
     ...
     strSQL = "SELECT ..., 'Kategorie' AS IconName FROM ..."
     ...
End Sub

Das Ergebnis sieht dann wie in Bild 14 aus – die Elemente der ersten Ebene werden nun mit dem Folder-Symbol angezeigt.

Treeview-Einträge mit Icon

Bild 14: Treeview-Einträge mit Icon

Verschiedene Icons

Sie können natürlich auch für die Einträge einer Ebene individuelle Icons festlegen. Dazu müssen Sie einfach das Feld, welches mit dem ALIAS-Namen IconName versehen wird, mit dem gewünschten Namen aus der Tabelle USys_pTV_Icon füllen.

Das Ergebnis soll dann beispielsweise wie in Bild 15 aussehen. Es soll also zu jedem Datensatz der Tabelle tblKategorien ein eigenes Icon angezeigt werden. Für das Beispiel haben wir das Formular frmKategorien, das bisher nur die Daten der Tabelle tblKategorien angezeigt hat, in das neue Formular frmKategorienIndividuelleIcons kopiert.

Individuelle Treeview-Icons

Bild 15: Individuelle Treeview-Icons

Dazu fügen Sie zunächst die gewünschten Icons über das Formular Tool_Icons in die Tabelle USys_pTV_Icon ein. Danach müssen Sie dafür sorgen, dass der Name des jeweiligen Icons im entsprechenden Datensatz der Tabelle tblKategorien gespeichert wird. Dazu fügen wir der Tabelle das Feld Icon hinzu und legen die gewünschten Werte an (s. Bild 16). Schließlich passen wir den SQL-Ausdruck in der Prozedzur Form_Open des Formulars frmKategorienIndividuelleIcons wie folgt an:

Verweise auf die Icons in der Tabelle tblKategorien

Bild 16: Verweise auf die Icons in der Tabelle tblKategorien

Private Sub Form_Open(Cancel As Integer)
     Dim strSQL As String
     Set objTreeView = Me!sfmTreeview.Form
     strSQL = "SELECT KategorieID AS Reference, " _
         & "Kategoriename AS Caption, " _
         & "'Kategorie' AS RefContext, " _
         & "Icon AS IconName " _
         & "FROM tblKategorien"
     objTreeView.AddSQL strSQL
End Sub

Wir haben hier also nicht wie im vorherigen Beispiel eine feste Zeichenfolge für das anzuzeigende Icon angegeben, sondern den Namen des Feldes mit dem Namen des Icons.

Icon für die Schaltfläche zum Ein- und Ausklappen ändern

Zugegeben: Das Plus- und da Minuszeichen, das standardmäßig im picoware-Treeview angezeigt wird, gefällt uns wirklich gut. Aber vielleicht nicht allen Programmierern und Benutzern! Also können Sie diese Symbole natürlich auch ändern. Dazu verwenden wir ausnahmsweise nicht die SQL-Anweisung, sondern eine Eigenschaft der Objektvariablen objTreeView. Diese passen wir etwa im Formular frmKategorienArtikelIcons wie folgt in der Prozedur Form_Open an:

objTreeView.IconPrefix = "WinXP"

Dies liefert nun die von Windows XP bekannten Icons für die Plus- und Minuszeichen (s. Bild 17). Aber woher wissen wir, dass wir dazu beispielsweise das Präfix WinXP verwenden müssen? Dazu reicht ein Blick in das Formular Tool_Icons.

Alternative Plus-/Minuszeichen

Bild 17: Alternative Plus-/Minuszeichen

Hier können Sie durch Filtern nach dem Ausdruck *Plus für die Spalte Context alle Plus-Zeichen einblenden, die verfügbar sind (s. Bild 18).

Alle alternativen Plus-/Minuszeichen

Bild 18: Alle alternativen Plus-/Minuszeichen

Lesen Sie einfach das Präfix des gewünschten Sets aus, also den Teil vor dem Unterstrich (_) und tragen Sie diesen für die Eigenschaft IconPrefix der Objektvariablen objTreeView ein. Sie können natürlich auch eigene Sets dieser Elemente anlegen.

Mausklick auf einen Eintrag

Neben dem Aus- und Einklappen von Treeview-Einträgen ist eine der wichtigsten Funktionen natürlich der Mausklick auf einen der Einträge.

Für die folgenden Beispiele haben wir das Formular frmKategorieArtikelIcons nach frmKategorieArtikelMausklick kopiert.

Wir wollen nun zunächst erreichen, dass ein Meldungsfenster mit dem Primärschlüsselwert des angeklickten Elements erscheint.

Dazu fügen wir dem Klassenmodul des Formulars die Ereignisprozedur ItemSelected des Elements objTreeView hinzu – wie weiter oben beschrieben über die beiden Kombinationsfelder des VBA-Codefensters. Dieses füllen wir wie folgt:

Private Sub objTreeView_ItemSelected(Context As  USys_pCT_Context, _
        ByVal RefPath As String)
    MsgBox Context.SettingLong("Reference", 0)
End Sub

Wenn Sie nun auf einen der Einträge klicken und diesen so als aktiven Eintrag auswählen, wird dieser nicht nur in blauer und fetter Schrift dargestellt, sondern es erscheint auch noch ein Meldungsfenster, das den Primärschlüsselwert des aktuellen Eintrags ausgibt (s. Bild 19).

Ausgabe der ID des angeklickten Elements

Bild 19: Ausgabe der ID des angeklickten Elements

Das hilft uns natürlich noch nicht wirklich weiter, wenn wir in mehreren Ebenen die Daten aus verschiedenen Tabellen darstellen. Dann sollten wir noch auf eine der Eigenschaften zugreifen, die wir über den SQL-Ausdruck angeben – nämlich den Wert für das Feld mit dem ALIAS-Namen RefContext.

Also stellen wir der Ausgabe im Meldungsfenster noch ein Element voran, welches über die Setting-Eigenschaft den Wert der Einstellung RefContext für das angeklickte Element ausgibt (s. Bild 20):

Ausgabe der Quelle und der ID des angeklickten Elements

Bild 20: Ausgabe der Quelle und der ID des angeklickten Elements

MsgBox Context.Setting("RefContext") & " " & Context.SettingLong("Reference", 0)

Welche Möglichkeiten sich daraus ergeben, brauchen wir für Entwickler, die sich bereits mit dem MSCOMCTL-TreeView auseinandergesetzt haben, nicht zu erläutern. Meist sollen beim Anklicken von TreeView-Elementen entsprechende Unterformulare mit den Daten zu den jeweiligen Einträgen geöffnet werden.

Sie können nun über das Ergebnis von Context.Setting("RefContext") ermitteln, welche Art von Objekt anzuzeigen ist und das entsprechende Unterformular einblenden, mit Context.SettingLong("Reference", 0) ermitteln Sie den Primärschlüsselwert des darin anzuzeigenden Datensatzes der zugrunde liegenden Tabelle.

Zusammenfassung und Ausblick

Es gibt noch viele weitere Funktionen, die sich mit dem picoware-Treeview abbilden lassen. In vielen Fällen gelingt dies wesentlich einfacher als mit dem MSCOMCTL-TreeView, und auf jeden Fall haben Sie die Sicherheit, dass das picoware-Treeview nicht versagt, wenn Microsoft wieder einmal ein unzureichend getestetes Update durchführt.

Außerdem können Sie damit erstellte Treeviews auch auf Systemen nutzen, die mit der 64bit-Variante von Office arbeiten.

Mit dem picoware-Treeview können Sie noch viele weitere Anpassungen am Design vornehmen, zur Laufzeit Knoten einfügen und entfernen, den Hintergrund farbig gestalten, Status- und Checkboxen nutzen, Daten aus reflexiv verknüpften Tabellen anzeigen und mehr.

Wenn Sie uns das Feedback liefern, dass das picoware-Treeview eine Alternative für das MSCOMCTL-TreeView ist, werden wir in weiteren Ausgaben auch die übrigen Funktionen des picoware-Treeviews vorstellen.

Download

Beispieldatenbank im accde-Format für Access 2016 und Artikel als PDF

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.

  • picoware-Treeview - eine rundum gelungene Sache...

    ... auf die die Access-Welt lange gewartet hat. Sehr gut. Ich bin begeistert, wie gut sich dieses Tool integrieren lässt und wie man ihm Leben einhaucht.

    Interessant wären aus meiner Sicht noch folgende Themen.
    1. Wie werden die hierarchischen Daten einer reflexiven Tabelle (mit beliebiger Anzahl an Baumhierarchien) im TreeView eingebunden?
    2. Wie kann man Kontext-Menü-Befehle generieren, um dann Knoten hinzuzufügen, zu bearbeiten und zu löschen (Detailformular)?

    Viele Fragen, ich bin sehr gespannt auf die nächsten Artikel.

    Beste Grüße
    Raik Schillow

Passende Artikel
picoware-Treeview picoware-Treeview
ab 299,00 € *