TreeView: Bug durch falsche Einheiten

Wenn man das TreeView-Steuerelement professioneller nutzt, programmiert man unter anderem Ereignisse, die durch das Anklicken von Elementen ausgelöst werden. Damit kann man Ereignisprozeduren auslösen, die beispielsweise Daten zum angeklickten Element in einem Unterformular anzeigen oder man blendet ein Kontextmenü zum jeweils angeklickten Element mit weiteren Optionen ein. Dazu ist es notwendig, zu identifizieren, auf welches Element der Benutzer geklickt hat. Die notwendigen Informationen liefern die Parameter der Prozeduren, das Ermitteln des angeklickten Elements erledigt man mit einer bestimmten Funktion. Seit Kurzem erreichen uns allerdings Meldungen von Lesern, bei denen dies nicht mehr zuverlässig funktioniert: Es werden keine Kontextmenüs mehr angezeigt und auch das Anklicken gelingt nicht mehr wie gewünscht. Interessanterweise tritt das Problem nur bei Verwendung von Office 365 auf. Wir schauen uns in diesem Beitrag an, woher das Problem rührt und wie Sie es lösen können.

Vorbereitung

Für die folgenden Experimente legen wir in einem neuen, leeren Formular einfach ein TreeView-Steuerelement namens ctlTreeView an.

Dazu wählen wir im Ribbon den Befehl Formularentwurf|Steuerelemente|ActiveX-Steuerelemente aus (siehe Bild 1).

ActiveX-Steuerelement hinzufügen

Bild 1: ActiveX-Steuerelement hinzufügen

Dies öffnet den Dialog ActiveX-Steuerelement einfügen, wo wir den Eintrag Microsoft TreeView Control, version 6.0 auswählen (siehe Bild 2).

TreeView-Steuerelement selektieren

Bild 2: TreeView-Steuerelement selektieren

Danach sehen wir das neue TreeView-Steuerelement im Formular und passen seine Größe entsprechend an (siehe Bild 3). Damit können wir zu den Feinheiten der Referenzierung und Programmierung übergehen.

TreeView-Steuerelement nach dem Einbau

Bild 3: TreeView-Steuerelement nach dem Einbau

Nach dem Einfügen des TreeView-Steuerelements passen wir noch seinen Namen auf ctlTreeView an.

TreeView als Steuerelement oder als Objektvariable referenzieren

Es gibt zwei Wege, wie man ein TreeView-Steuerelement per VBA referenzieren kann. Der erste ist, dieses wie bei den eingebauten Steuerelementen einfach über das Schlüsselwort Me in Verbindung mit dem Steuerelementnamen zu referenzieren, hier also ctlTreeView. Wenn wir dies im VBA-Editor erledigen und einen weiteren Punkt anfügen, um per IntelliSense auf die Methoden und Eigenschaften des TreeView-Steuerelements zuzugreifen, erhalten wir das Ergebnis aus Bild 4. Hier erkennen wir, dass wir nur die allgemeinen Eigenschaften von Steuerelementen anwählen können, nicht jedoch die speziellen Elemente des TreeView-Steuerelements.

Referenzieren des Steuerelements

Bild 4: Referenzieren des Steuerelements

Dazu müssen wir eine Objektvariable anlegen, die wir wie folgt deklarieren:

Dim objTreeView As MSCOMCTLLib.TreeView

Diese Variable füllen wir wie folgt:

Set objTreeView = Me!ctlTreeView.Object

Wir können das TreeView-Steuerelement nicht direkt über Me!ctlTreeView referenzieren, weil wir damit nur die Hülle des Steuerelements referenzieren würden. Diese hat den Datentyp CustomControl. Dies können wir belegen, indem wir zuerst den Typ von ctlTreeView ausgeben:

Debug.Print TypeName(Me!ctlTreeView)
CustomControl

Erst über das Object-Element erhalten wir den gesuchten Typ:

Debug.Print TypeName(Me!ctlTreeView.Object)
TreeView

Mit der Referenzierung über die Objektvariable objTreeView erhalten wir schließlich auch die TreeView-spezifischen Eigenschaften und Methoden per IntelliSense (siehe Bild 5).

Referenzieren des TreeView-Steuerelements per Objektvariable

Bild 5: Referenzieren des TreeView-Steuerelements per Objektvariable

Sie sehen: Ein Grund, das TreeView-Steuerelement nicht über das als Container verwendete Steuerelement CustomControl, sondern über das darin enthaltene TreeView-Steuerelement zu referenzieren, erlaubt den Zugriff auf die Eigenschaften und Methoden per IntelliSense.

Verwendung von Ereignissen

Wir wollen exemplarisch das Ereignis MouseDown verwenden, weil es das Problem verdeutlicht. Wir können das Ereignis auf zwei Arten in Form einer Ereignisprozedur implementieren. Bei der ersten verwenden wir die Ereignisse des Steuerelements ctlTreeView. Um das Ereignis anzulegen, wählen wir im Codefenster des Klassenmoduls des Formulars oben links den Eintrag für das TreeView-Steuerelement ctlTreeView aus und aus der nun aufgeklappten Liste auf der rechten Seite den Eintrag MouseDown. Die automatisch hinzugefügte Ereignisprozedur ctlTreeView_Updated können wir wieder löschen (siehe Bild 6).

Anlegen des MouseDown-Ereignisses für ctlTreeView

Bild 6: Anlegen des MouseDown-Ereignisses für ctlTreeView

Die neue Ereignisprozedur hat die folgende Signatur:

Private Sub ctlTreeView_MouseDown( _
     ByVal Button As Integer, _
     ByVal Shift As Integer, _
     ByVal x As Long, _
     ByVal y As Long)

Button liefert einen Hinweis, ob die linke oder rechte Maustaste gedrückt wurde, Shift gibt an, ob eine der Tasten Alt, Strg oder Umschalt beim Betätigen der Maustaste gehalten wurde.

Mit x und y erhalten wir die Koordinaten, an denen der Mausklick erfolgte. Wie es unter Access üblich ist, werden diese Koordinaten im Format Twips geliefert.

Ereignis für die Objektvariable anlegen

Wir können das Ereignis allerdings auch für die oben vorgestellte Objektvariable objTreeView anlegen. Dazu müssen wir die Deklaration dieser Variablen nur aus der Prozedur Form_Load herausholen und in den allgemeinen Teil des Moduls verschieben (siehe Bild 7). Außerdem fügen wir das Schlüsselwort WithEvents hinzu, damit der VBA-Editor weiß, dass wir in diesem Klassenmodul Ereignisse für dieses Element implementieren können wollen.

Änderung der Deklaration von objTreeView

Bild 7: Änderung der Deklaration von objTreeView

Damit können wir nun wie zuvor für ctlTreeView auch für objTreeView die Ereignisse über die Auswahlfelder oben im Codefenster hinzufügen (siehe Bild 8).

Anlegen des MouseDown-Ereignisses für die Objektvariable objTreeView

Bild 8: Anlegen des MouseDown-Ereignisses für die Objektvariable objTreeView

Das erledigen wir wie zuvor und sehen uns dann die Signatur des MouseDown-Ereignisses für die Objektvariable objTreeView an:

Private Sub objTreeView_MouseDown( _
     ByVal Button As Integer, _
     ByVal Shift As Integer, _
     ByVal x As stdole.OLE_XPOS_PIXELS, _
     ByVal y As stdole.OLE_YPOS_PIXELS)

Die Signatur ist bezüglich der Anzahl und der Benennung der Elemente identisch, jedoch unterscheidet sich der Datentyp bei den Parametern x und y. Während wir es zuvor mit Long-Werten zu tun hatten, finden wir nun den Datentyp stdole.OLOE_XPOS_PIXELS vor. Lassen wir uns innerhalb dieses Ereignisse jedoch einmal den Datentyp mit Typename ausgeben, erhalten wir hier ebenfalls Long als Datentyp. Allerdings sehen wir, dass der Datentyp die Zeichenkette PIXELS enthält, war darauf hindeutet, dass hier nicht Twips wie bei der gleichnamigen Ereignisprozedur für das Steuerelement geliefert werden, sondern Pixel.

Die Frage ist nun: Ist das auch der Fall?

Dazu fügen wir dem Formular vier Textfelder namens txtCtlX, txtCtlY, txtObjX und txtObjY hinzu (siehe Bild 9). Die Textfelder füllen wir beim Auslösen der Ereignisprozeduren beim Ereignis MouseDown mit den Werten für die Parameter x und y:

Steuerelemente zum Anzeigen der x- und y-Werte für die beiden Ereignisprozeduren

Bild 9: Steuerelemente zum Anzeigen der x- und y-Werte für die beiden Ereignisprozeduren

Private Sub ctlTreeView_MouseDown(_
     ByVal Button As Integer, _
         ByVal Shift As Integer, _
         ByVal x As Long, ByVal y As Long)
     Me!txtCtlX = x
     Me!txtCtlY = y
End Sub
Private Sub objTreeView_MouseDown( _
         ByVal Button As Integer, ByVal Shift As Integer, _
         ByVal x As stdole.OLE_XPOS_PIXELS, _
         ByVal y As stdole.OLE_YPOS_PIXELS)
     Me!txtObjX = x
     Me!txtObjY = y
End Sub

Und hier wird es spannend: Unter Access in der Version von Office 365 erhalten wir für beide Ereignisprozeduren beim einem Klick in die rechte, untere Ecke unterschiedliche Werte für die Parameter x und y (siehe Bild 10).

Ergebnis beim Anklicken unter Office 365

Bild 10: Ergebnis beim Anklicken unter Office 365

Das Ereignis für ctlTreeView liefert die Werte in der Einheit Twips, das Ereignis für objTreeView in der Einheit Pixel.

Richtig interessant wird es, wenn wir das gleiche Formular in Access 2010 öffnen (Gleiches gilt für Access 2013 und 2016). Hier erhalten wir für das Ereignis MouseOver des Steuerelements ctlTreeView und der Objektvariablen objTreeView beim Anklicken des Steuerelements in der rechten, unteren Ecke alle Werte in der Einheit Twips (siehe Bild 11).

Ergebnis beim Anklicken unter Access 2010

Bild 11: Ergebnis beim Anklicken unter Access 2010

Aber warum sollte das ein Problem sein? Das schauen wir uns im Anschluss an.

Probleme durch unterschiedliche Einheiten

Wir füllen nun das TreeView-Steuerelement beim Laden des Formulars mit drei einfachen Node-Elementen:

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar