Kontakt-Formular   Inhaltsverzeichnis   Druckansicht  

VisualBasic.tips

Startseite > Microsoft Access VBA > ActiveX Treeview > Teil 5 - ImageList-Control

Teil 5 - ImageList-Control

Ausgabe 03/2001

Download Beispieldatei

Im vorletzten Teil dieser Artikelfolge möchten wir Ihnen ein neues ActiveX-Steuerelement vorstellen, das ImageList-Control. Viele der ActiveX-Steuerlemente müssen auf das ImageList zurückgreifen, wenn Bilder bzw. Icons in ihnen dargestellt werden sollen. Warum zu diesem Zweck ein zusätzliches Steuerelement nötig ist, erfahren Sie in diesem Artikel.

Anwendungsbereich des ImageList-Steuerelementes

Wie der Name schon vermuten lässt, speichert das ImageList eine Liste von Bildern. Wenn ActiveX-Steuerelemente eingesetzt werden, möchte man nicht selten auch deren Fähigkeit nutzen, kleine Bilder anzuzeigen. Diese Images sehen nicht nur gut aus, sondern helfen oft Unterschiede oder bestimmte Zustände zu visualisieren. Das wohl bekannteste Beispiel ist der Windows-Explorer: Sie müssen nicht unbedingt die Detailansicht aktiviert haben, damit Sie sehen können um welchen Dateityp es sich jeweils handelt.

Das TreeView-Control bzw. das Node-Objekt stellt drei verschiedene Eigenschaften für die Darstellung solcher Icons zur Verfügung; das heißt, Sie können theoretisch jedem Knoten für jede dieser drei Eigenschaften ein eigenes Icon zuordnen. Mal angenommen die Icons würden direkt in der Nodes-Auflistung gespeichert werden, bei hundert Einträgen wären das 300 verschiedene Bilder, die bei der kleinsten Auflösung von 16 x 16 Pixel schon 822 Bytes pro Icon in Anspruch nehmen würden. Da der Inhalt eines TreeView sowieso schon im Arbeitsspeicher gehalten werden muss, würde sehr viel Rechnerleistung benötigt werden, um mit dem TreeView-Control flüssig arbeiten zu können. Außerdem müssten die Icons jedes mal von der Festplatte geladen werden.

Und ab hier betritt das ImageList-Control die Bühne. Das ImageList nimmt diese Icons einmal in sich auf und stellt Sie dem TreeView zur Verfügung; wie erfahren Sie weiter unten. Natürlich müsste auch das ImageList, analog zu unserem obigen Beispiel, alle 300 Icons laden und würde demzufolge auch denselben Speicherplatz in Anspruch nehmen. Unser Beispiel war zugegeben etwas übertrieben, aber im Bereich des Möglichen. Die Icons sollen schließlich eine Eigenschaft, einen Zustand oder Beides sofort sichtbar machen. Das könnte zum Beispiel so aussehen, dass Sie die Ebene eines Knotens sofort erkennbar machen wollen. Bei mehr als 5 Ebenen im TreeView fällt es manchmal schwer den Durchblick zu behalten. Das würde bedeuten, Sie benötigten nur etwa 6-8 Icons, für jede Ebene ein anderes. Aber warum dann ein eigenes Steuerelement? Warum ist die Image-Liste nicht direkt im TreeView eingebaut, als eigenes Collection-Objekt? Ganz einfach, es gibt, wie eingangs erwähnt, noch mehrere ActiveX-Controls, die mit Images umgehen können: z.B. das ListView (Listenansicht-Steuerelement), die ToolBar (Menüleisten), die StatusBar (Statusleiste). Jedes dieser Steuerelemente müsste die ImageList-Funktion innehaben. Viermal dieselbe Funktion, ohne diejenigen, die wir hier nicht aufgezählt haben, oder vielleicht noch entwickelt werden. Außerdem können alle diese Controls ein und dasselbe Image verwenden, ohne das es in vier verschiedene Image-Listen geladen werden muss. Die Wiederverwendbarkeit wurde hier konsequent umgesetzt.

Handhabung des Imagelist-Controls

Das ImageList-Control besitzt keine Benutzeroberfläche, da keine Interaktion zwischen Anwender und Steuerelement notwendig ist. Mit dem Programmierer allerdings schon, deshalb ist das Steuerelement - quasi symbolisch - nur in der Entwurfs¬ansicht eines Formulars sichtbar (Abbildung 2). Wenn Sie ein Formular im Entwurf geöffnet haben, können Sie über den Menüpunkt [Einfügen | ActiveX-Steuerelement ...] eine Dialog öffnen, im dem Sie eine Auflistung aller ActiveX-Steuerelemente Ihres Systems erhalten (Abbildung 1). Nach der Auswahl des Eintrags Microsoft ImageList Control, version 5.0 per Doppelklick, wird das Steuerelement in den Formularentwurf eingefügt. Da das Control zur Laufzeit nicht sichtbar ist, ist es vollkommen egal an welcher Stelle im Formular es sich befindet. Trotzdem positionieren wir es im Seitenfuß, wo unsichtbare Steuerelemente unserer Meinung nach hin gehören.

Durch den Kontextmenüpunkt [ImageListCtrl-Objekt | Eigenschaften] oder durch Doppelklick können Sie sich die zusätzlichen Eigenschaften des ImageList-Control anzeigen lassen. Im ersten Register stellen Sie ein, welche Größe Ihre Images in der Auflistung haben sollen. Das ListView-Control (Listenansicht-Steuerelement) arbeitet zum Beispiel mit verschiedenen Imageformaten für verschiedene Ansichtmodi: Kleine Symbole, Große Symbole oder Details. Für diesen Fall brauchen Sie auch verschiedene Image-Listen, da in einem Control nur eine Größe gespeichert werden kann. Welche Größe Ihre Images dabei tatsächlich haben, spielt keine Rolle, sie werden auf die eingestellte Größe angepasst.

Im Register Abbildungen können Sie den „Container“ zur Entwurfszeit mit Images füllen (Abbildung 3). Mit den Schaltflächen Bild einfügen und Bild entfernen können Sie Images in die Auflistung laden oder eben löschen. Außerdem können Sie für jedes Image drei Eigenschaften einstellen: die ID- bzw. Key-Eigenschaft, für die eindeutige Identifizierung und späteren Zugriff auf die einzelnen Objekte in der Auflistung, und die Marke-Eigenschaft. Die Marke-Eigenschaft, oder auch Tag im VBA, kann wiederum einen beliebigen String für zusätzliche Informationen aufnahmen.

Bei der ID-Eigenschaft müssen Sie darauf achten, dass er mit EINS beginnen und fortlaufend sein muss, d.h. keine Lücken entstehen dürfen. Deshalb eignet sich die Key-Eigenschaft besser, um flexibel auf einzelne Images zuzugreifen, dazu später mehr.

Zum Schluss möchten wir noch auf die sehr interessante Eigenschaft UseMaskColor des ersten Registers eingehen (Abbildung 1). Angenommen Sie haben ein Symbol erstellt, welches Sie im TreeView, aber auch in einer benutzdefinierten Symbolleiste benutzen möchten. Die Symbolleiste hat einen grauen und das TreeView einen weißen Hintergrund, die beide auch nicht verändert werden können. Jetzt müsste für beide Einsatzgebiete ein extra Icon erstellt werden, da sich ein weißer Hintergrund in der Symbolleiste, oder ein Grauer im TreeView, nicht gut machen würde. Die UseMaskColor-Eigenschaft des ImageList-Controls hilft dieses Problem zu umgehen. Im dritten Register Farbe können zwei zusätzliche Eigenschaften eingestellt werden: BackColor und MaskColor. Wenn die UseMaskColor-Eigenschaft aktiviert ist, wird die in MaskColor durch die in BackColor eingestellte Farbe im Image ersetzt, in der Standardeinstellung z. B. grau durch weiß. Das bedeutet wiederum, Sie brauchen für mehrere Einsatzgebiete nur ein Icon aber eventuell mehrere ImageList-Controls.Abbildung 1: Dialog zum Einfügen von ActiveX-Controls

Abbildung 1: Dialog zum Einfügen von ActiveX-Controls

Abbildung 1: Dialog zum Einfügen von ActiveX-Controls

Abbildung 2: das ImageList-Control ist nur im Formularentwurf sichtbar

Abbildung 2: das ImageList-Control ist nur im Formularentwurf sichtbar

Abbildung 2: die Image-Auflistung kann zur Entwurfszeit bearbeitet werden

Abbildung 2: die Image-Auflistung kann zur Entwurfszeit bearbeitet werden

Das ImageList-Control zur Laufzeit

Vielleicht haben Sie es schon vermutet, das ImageList, genauer gesagt die ListItems-Auflistung, kann auch zur Laufzeit gefüllt bzw. bearbeitet werden. Auch für das ImageList-Steuerelement hat diese Vorgehensweise einige Vorteile. Der wohl größte Vorteil ist die Flexibilität. Sie können Images ändern, ohne in die Programmierung eingreifen zu müssen.

Für unser Beispiel mit der Unternehmensstruktur könnte das folgendermaßen aussehen: Für jede Unternehmensstruktur-Ebene möchten wir ein eigenes Symbol anzeigen lassen, sodass man auf den ersten Blick erkennen kann, ob der Knoten einen Standort, eine Abteilung, ein Büro, etc. repräsentiert.

Natürlich gibt es auch hier mehrere Lösungswege. Eine extrem flexible Variante möchten wir Ihnen im Folgenden vorstellen. Sie, oder der Benutzer, sollen in der Lage sein die Symbole zur Laufzeit zu verändern, ohne Eingriff in die Programmierung versteht sich.

 Die Unterscheidung der einzelnen Ebenen haben wir in der Spalte Typ der Tabelle tbl_Struktur gespeichert, die dazugehörige Liste ist in der Tabelle tbl_Typ hinterlegt (siehe Abbildung 5). Diese Typ-Tabelle erweitern wir nun um die Spalte SmallIcon vom Typ Text. Den kompletten Tabellenentwurf  können Sie der Tabelle 1 entnehmen.

In der neuen Spalte SmallIcon speichern wir die Namen der Icons (ohne Dateierweiterung), welche im TreeView jeweils die Struktur-Ebenen  repräsentieren sollen (Abbildung 6). Diese Variante bietet die Möglichkeiten entweder die Dateien auszutauschen oder die Datensätze der Tabelle tbl_Typ mit anderen Symbol-Dateien in Verbindung zu bringen. Die Symboldateien befinden sich alle in einem fest definierten Unterverzeichnis des Datenbankpfades mit dem Namen Icon. Auf diese Weise muss kein fester Verzeichnispfad für die Dateien abgespeichert werden. Bevor nun das TreeView mit Daten gefüllt werden kann bzw. die Einträge durch Icons erweitert werden können, muss die ImageList mit Bildern gefüllt werden (siehe Listing 1). Dazu wird das ImageList zuerst einmal geleert, durch die Clear-Methode, angewandt auf die ListImages-Auflistung:

ImageList.ListImages.Clear

In der zweiten Funktion ImageList_Fill wird zunächst einmal das aktuelle Datenbankverzeichnis ermittelt und auf eine Hilfsvariable geschrieben. Das aktuelle Verzeichnis kann über die Name-Eigenschaft des Database-Objektes ausgelesen werden. Da die Name-Eigenschaft neben dem Laufwerk und Pfad auch den Datenbankname zurück gibt und der Verzeichnisstring daraus extrahiert werden muss, wird  diese Aufgabe von einer separaten Funktion übernommen:

Get_DBPath (Listing 2). 

Anschließend wird die Tabelle tbl_Typ geöffnet und die Images nacheinander in das ImageList geladen:

Set img = ImageList.ListImages.Add(src![Index#] + 1, src![SmallIcon], LoadPicture(v_Path & "\" & src![SmallIcon] & ".ico"))

Die Add-Methode der ListImages-Auflistung hat folgende Syntax:

[ImageList-Objekt].ListImages.Add([Index], [Key],[Picture])

Achtung: Die Parameter sind zwar alle optional, die Eigenschaften können aber nur teilweise nach der Add-Methode für das ListImage-Objekt gesetzt werden.
Die Add-Methode liefert einen Verweis auf das angefügte ListImage-Objekt zurück. Dabei ist die letzte Eigenschaft Picture sehr interessant und ungewöhnlich. Diese Eigenschaft kann nur ein Objekt vom Typ Picture speichern. Und genau solch ein Picture-Objekt gibt die Access-Funktion LoadPicture() zurück. Dafür benötigt die Funktion im Parameter den kompletten Verzeichnispfad (v_Path) inkl. Dateinamen (src![SmallIcon]) und Extension (.ico). Außerdem werden die Eigenschaften Index und Key gesetzt, damit man später auf die Images verweisen kann.

Tabelle 1: Tabellenentwurf der Tabelle „tbl_Typ“

Feldname

Felddatentyp

Index#

Zahl [long Integer]

Typ

Text [100]

SmallIcon

Text [68]

Abbildung 5: das Beziehungsmodell in unserer Beispielanwendung

Abbildung 5: das Beziehungsmodell in unserer Beispielanwendung

Abbildung 5: die Einträge der Typ-Tabelle

Abbildung 5: die Einträge der Typ-Tabelle

Funktionen anpassen

Damit die Icons auch an der entsprechenden Stelle im TreeView angezeigt werden, müssen noch ein paar kleine Ergänzungen am „alten“ Code vorgenommen werden. Im Listing 3 sind die geänderten Code-Zeilen abgedruckt. Eigentlich muß nur die Image-Eigenschaft des aktuellen Node-Objektes gesetzt werden:

On Error Resume Next
   NodeX.Image = rstFilter![Typ#] + 1
On Error GoTo RunError

Die Fehlerbehandlungsroutine wird hier für einen Augenblick abgeschaltet, um den Code nicht wegen einer fehlenden Symbol-Datei gleich abbrechen zu lassen. Beachten Sie bitte auch die dritte Funktion im Listing 3: Create_NodeKey(), die in den beiden vorhergehenden Funktionen bei der Add-Methode und der Key-Eigenschaft zum Einsatz kommt. Die Funktion gibt in jedem Fall einen Wert zurück, der von dem Eigenschaften aufgenommen werden kann. In unserem bisherigen Code konnte unter Umständen eine Situation in der Art auftreten, dass auf die Key-Eigenschaft ein ungültiger Wert geschrieben wurde, was mit einer Fehlermeldung quittiert wurde, z.B. dann wenn das TreeView keinen Eintrag enthält und die Schaltfläche zum Hinzufügen eines Knoten betätigt wurde.

Office als Bezugsquelle für Symbole anzapfen

Im Office-Paket sind über 2000 unterschiedliche Symbole enthalten, die man alle im Anpassen-Modus des Kontextmenüs über den Kopieren-Befehl in die Zwischenablage kopieren und mit jedem beliebigen Bitmap-Programm speichern oder sogar bearbeiten kann. Eine komfortable Möglichkeit können Sie in der Rubrik Tipps und Tricks dieser Ausgabe kennenlernen. hier...

Abbildung 6: die verschiedenen Ebenen sind sofort erkennbar

Abbildung 6: die verschiedenen Ebenen sind sofort erkennbar

Listing 1: Funktionen zum Füllen des ImageList-Controls
Public Function ImageList_Initialize(ByVal ImageList As Object)
   '* Eventuelle Images in der ImageList entfernen.
   ImageList.ListImages.Clear
End Function

Public Function ImageList_Fill(ByVal ImageList As Object, _
                               ByVal p_TableName As String) As Boolean
   Dim img As ListImage    '* ImageList-Variablen definieren
   Dim dbs As Database     '* DAO-Variablen definieren
   Dim src As Recordset
   Dim v_Path As String    '* Hilfs-Variable definieren

   ImageList_Fill = False  '* Funktion initialisieren

   '* Icon-Verzeichnis ermittlen
   '* Im Unterverzeichnis "Icon" des Datenbankpfades
   v_Path = Get_DBPath() & "\Icon"
   
   '* DAO-Variablen initialisieren
   Set dbs = CurrentDb()
   Set src = dbs.OpenRecordset(p_TableName, _
                               dbOpenDynaset)
      '* Wenn kein Datensatz vorhanden, dann Abbruch!
      If src.RecordCount = 0 Then GoTo RunExit

      src.MoveFirst
      While Not src.EOF

         '* kleine Images in ImageList einfügen
         Set img = ImageList.ListImages.Add(src![Index#] + 1, _
                                            src![SmallIcon], _
                                            LoadPicture(v_Path & "\" & src![SmallIcon] & ".ico"))

         src.MoveNext
      Wend

   '* Funktion erfolgreich!
   ImageList_Fill = True

RunExit:
   '* DAO-Variablen schliessen
   src.Clone
   dbs.Close
   '* DAO-Variablen terminieren
   Set src = Nothing
   Set dbs = Nothing

End Function
Listing 2: Ermittlung des Datenbankpfades
Public Function Get_DBPath() As String
   Dim v_Character As String
   Dim v_Path As String
   Dim v_Length As Long

   v_Path = CurrentDb.Name
   v_Length = Len(v_Path)

   Do While v_Character <> "\"
      v_Length = v_Length - 1
      v_Character = Mid$(v_Path, v_Length, 1)
   Loop

   Get_DBPath = Left(v_Path, v_Length - 1)

End Function
Listing 3: angepasste Funktionen zum TreeView
Public Function TreeView_Fill(ByVal TreeView ....)
....
      Set NodeX = TreeView.Nodes.Add(p_ParentKey, tvwChild)
         '*** wird ERSETZT: NodeX.Key = CStr("A" & rstFilter(0)) ***
         NodeX.Key = Create_NodeKey(rstFilter(0), "A")
         NodeX.Text = Nz(rstFilter(2), "")

         On Error Resume Next
            '* Icon einfügen
            NodeX.Image = rstFilter![Typ#] + 1
         On Error GoTo RunError
 
         Call TreeView_Fill(TreeView, rstFilter(0))
           
....
End Function

Public Function TreeView_AddNew_Node(ByVal TreeView ....)
   TreeView_AddNew_Node = Null

   Set NodeX = TreeView.Nodes.Add(Create_NodeKey(src![Gruppe#], "A"), tvwChild)
      NodeX.Key = Create_NodeKey(src![Index#], "A")
      NodeX.Text = p_Text

      On Error Resume Next
      '* Icon einfügen
         NodeX.Image = src![Typ#] + 1
      On Error GoTo RunError

   TreeView_AddNew_Node = NodeX.Key
....
End Function

Public Function Create_NodeKey(Optional ByVal p_Index As Variant = Null, _
                               Optional ByVal p_Prefix As String = "A")
   '* Rückgabe = NULL, wenn p_Index = NULL, oder Fehler!
   Create_NodeKey = Null
   '* Wenn Parameter "p_Index" nicht NULL, ...
   If Not IsNull(p_Index) Then
      '* ..., dann korrekten NodeKey auf Funktion schreiben!
      Create_NodeKey = p_Prefix & CStr(p_Index)
   End If
End Function
Seitenanfang