Formulare zur Laufzeit analysieren

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

Wenn Sie selbst eine Anwendung programmieren und ein Formular nicht so funktioniert wie gewünscht, wissen Sie, wie die Steuer-elemente heißen, an welche Datenquellen sie gebunden sind und so weiter. Vielleicht ist die Entwicklung der Anwendung auch etwas länger her und Sie müssen sich erst wieder einarbeiten – oder Sie erhalten von einem Kunden eine Anwendung mit der Bitte, dort eine Funktion in einem Formular zu überprüfen. In den beiden letzteren Fällen ist es recht mühsam, zwischen Formular- und Entwurfsansicht zu wechseln, um Steuerelementnamen, Datenherkünfte und andere Informationen herauszufinden, die zur Lösung des Problems beitragen könnten. Der vorliegende Beitrag zeigt, wie Sie ein Formular schnell mithilfe eines zur Laufzeit hinzugefügten Kontextmenüs analysieren können, um schneller Lösungen zu finden.

Die üblichen Mittel, die einem zur Verfügung stehen, um Informationen über das Formular, die enthaltenen Steuer-elemente oder ihre Eigenschaften zu ermitteln, sind die Elemente der Screen-Klasse. Dieses bietet Eigenschaften wie ActiveForm für das Ermitteln eines Verweises auf das aktuelle Formular oder ActiveControl für das Ermitteln des aktuellen Steuerelements.

Den Namen des aktuellen Formulars können Sie so beispielsweise über das Direktfenster ermitteln, ohne in die Entwurfsansicht wechseln zu müssen. Dazu geben Sie den folgenden Befehl ein:

Debug.Print Screen.ActiveForm.Name

Vielleicht wollen Sie auch auf die Eigenschaften des aktuellen Steuer-elements zugreifen. Dann verwenden Sie ActiveControl:

Debug.Print Screen.ActiveControl.Name

Wenn Sie dann auf eine spezielle Eigenschaft des Formulars oder Steuerelements zugreifen wollen, die Sie nicht genau kennen, weil Sie diese sonst immer per IntelliSense eingeben, wird es allerdings schwierig, weil zumindest Screen.ActiveControl nur einige allgemeine Eigenschaften liefert.

Geplante Lösung

Was wir nun machen wollen, ist die Bereitstellung aller Eigenschaften eines Formulars oder Steuerelements über das Kontextmenü des jeweiligen Elements. Wenn der Entwickler also mit der rechten Maustaste auf ein Formular oder Steuer-element klickt, soll ein Kontextmenü erscheinen, das zusätzlich zu den eingebauten Befehlen noch weitere Einträge enthält – einen, der direkt den Namen des Elements anzeigt und einen, der in einem Untermenü alle Eigenschaften des Elements samt Werten liefert.

Das soll etwa wie in Bild 1 aussehen. Diese Kontextmenü-Einträge wollen wir für alle Elemente des Formulars liefern – also sowohl für das Formular selbst, für die Steuer-elemente als auch für die Elemente in Unterformularen, unabhängig davon, ob es sich um die Datenblatt- oder die Formularansicht handelt.

Anzeige der Eigenschaften per Kontextmenü

Bild 1: Anzeige der Eigenschaften per Kontextmenü

Realisierung

Im aufwendigsten Fall fügt man für jedes Formular und für jedes Steuer-element eine Ereignisprozedur hinzu, die durch das Ereignis Bei Maustaste ab ausgelöst wird.

In dieser Prozedur prüft man dann, ob der Benutzer die linke oder die rechte Taste gedrückt hat. Im Falle der rechten Maustaste soll dann das nun anzuzeigende Kontextmenü erweitert werden, und zwar um ein Element mit dem Namen des Formulars oder Steuerelements und mit einem Untermenü mit den Eigenschaften des Elements.

Allerdings müsste man das dann für alle Formulare und Steuer-elemente machen, die man untersuchen möchte – und das wollen wir nicht. Stattdessen arbeiten wir, wie schon des Öfteren, mit zwei Klassenmodulen, denen wir die Formulare und Steuer-elemente zuweisen und welche die notwendigen Ereignisprozeduren bereits enthalten.

Diese schauen wir uns nun an – zuerst das Klassenmodul, mit dem wir das Formular referenzieren und das die Kontextmenü-Befehle für dieses bereitstellt.

Klassenmodul für die Kontextmenüs in Formularen

Dieses Klassenmodul nennen wir clsForm.

Das Formular verwendet die folgenden Variablen:

Private WithEvents m_frm As Form
Private WithEvents m_Detail As Section
Public colControls As Collection
Private m_IsSubform As Boolean

Die beiden Variablen m_frm und m_Detail werden mit dem Schlüsselwort WithEvents ausgestattet, wodurch wir in dem Klassenmodul, in dem die Objekte deklariert sind, Ereignisprozeduren für diese Objekte implementieren können.

Die Klasse stellt eine öffentliche Eigenschaft namens Form zur Verfügung, die das mit den Kontextmenüs auszustattende Formular entgegennimmt und die wie folgt aussieht:

Public Property Set Form(frm As Form)
     Dim objControl As clsControl
     Dim ctl As Control
     Set m_frm = frm
     With m_frm
         .OnMouseDown = "[Event Procedure]"
     End With
     Set m_Detail = Form.Section(0)
     With m_Detail
         .OnMouseDown = "[Event Procedure]"
     End With
     Set colControls = New Collection
     For Each ctl In m_frm.Controls
         Set objControl = New clsControl
         With objControl
             .IsSubform = m_IsSubform
             Set .Control = ctl
             colControls.Add objControl
         End With
     Next ctl
End Property

Diese Property Set-Prozedur speichert zunächst den mit frm übergebenen Verweis auf das betreffende Formular in der Variablen m_frm. Dann stellt es für die Ereignis-eigenschaft Bei Maustaste ab (OnMouseDown) des Formulars den Wert Ereignisprozedur ein ([Event Procedure]). Danach ermittelt die Prozedur den Detailbereich des Formulars und referenziert diesen mit der Variablen m_Detail. Auch dafür stellt sie den Wert [Event Procedure] für die Eigenschaft OnMouseDown ein. Danach durchläuft die Methode die Steuerelemente im Formular und legt für jedes Steuer-element eine neue Instanz der Klasse clsControl, die wir weiter unten erläutern, an und weist der Eigenschaft Control dieses Objekts das aktuelle Steuer-element zu. Gegebenenfalls befinden wir uns gerade in einem Unterformular, dann wird noch der Wert True für die Eigenschaft IsSubform übergeben. Schließlich landen alle Objekte auf Basis der Klasse clsControl in der Collection colControls.

Rechter Mausklick auf Formular oder Detailbereich

Wenn der Benutzer mit der rechten Maustaste auf das Formular oder den Detailbereich klickt, löst er die Prozedur m_Detail_MouseDown aus. Diese legen Sie an, indem Sie im Codefenster der Klasse clsForm im linken Kombinationsfeld den Eintrag m_Detail und im rechten den Eintrag MouseDown auswählen (siehe Bild 2).

Anlegen einer Ereignisprozedur für eine Objektvariable

Bild 2: Anlegen einer Ereignisprozedur für eine Objektvariable

Dadurch wird eine Ereignisprozedur angelegt, die wir wie in Listing 1 ergänzen. Hier deklarieren wir zunächst zwei Variablen, um eine Menüleiste und eine Menüschaltfläche zu referenzieren.

Private Sub m_Detail_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Dim cbr As CommandBar
     Dim cbb As CommandBarButton
     If m_frm.CurrentView = acCurViewDatasheet Then
         Set cbr = CommandBars("Form DataSheetCell")
     Else
         If m_IsSubform Then
             Set cbr = CommandBars("Form View Subform")
         Else
             Set cbr = CommandBars("Form View popup")
         End If
     End If
     On Error Resume Next
     Do While Err.Number = 0
         cbr.Controls("Steuerelement-Infos anzeigen").Delete
     Loop
     On Error Resume Next
     Do While Err.Number = 0
         cbr.Controls("Eigenschaften").Delete
     Loop
     Set cbb = cbr.Controls.Add(msoControlButton, , , , True)
     With cbb
         If m_IsSubform Then
             .Caption = "Unterformular: " & m_frm.Name
         Else
             .Caption = "Formular: " & m_frm.Name
         End If
     End With
     PropertiesHinzufuegen cbr
End Sub

Listing 1: Prozedur beim Mausklick auf ein Formular

Kontextmenüs identifizieren

Nun folgen wichtige Schritte, in denen wir festlegen, welches Kontextmenü überhaupt mit unseren zusätzlichen Einträgen versehen werden soll. Access zeigt nämlich immer andere Kontextmenüs an, wenn Sie unterschiedliche Elemente mit der rechten Maustaste anklicken – und deren Namen wir durch den Aufruf einer bestimmten Prozedur ermitteln können. Diese sieht wie folgt aus:

Public Sub ButtonMitNameZuKontextmenuesHinzufuegen()
     Dim cbr As CommandBar
     Dim cbb As CommandBarButton
     For Each cbr In CommandBars
         On Error Resume Next
         Set cbb = cbr.Controls.Add( msoControlButton, , , , True)
         cbb.Caption = cbr.Name
         If Not Err.Number = 0 Then
             Debug.Print cbr.Name
         End If
         On Error GoTo 0
     Next
End Sub

Die Prozedur durchläuft alle Einträge der CommandBars-Auflistung von Access und fügt jedem ein Element des Typs msoControlButton hinzu, also eine einfache Schaltfläche.

Die Beschriftung des jeweiligen Elements füllen wir mit dem Namen des aktuellen Kontextmenüs. Dadurch zeigt jedes Kontextmenü von nun an als letzten Eintrag seinen Namen an – wie am Beispiel eines Datenblatts zu erkennen (siehe Bild 3).

Anzeige des Kontextmenü-Namens im Kontextmenü

Bild 3: Anzeige des Kontextmenü-Namens im Kontextmenü

Kontextmenü im Kontext des jeweiligen Objekts anpassen

Dann prüfen wir, ob das aktuelle Formular in der Datenblattansicht angezeigt wird, was der Fall ist, wenn die Eigenschaft CurrentView den Wert acCurViewDatasheet liefert. In diesem Fall erstellen wir ein CommandBar-Objekt auf Basis des Menüs Form DataSheetCell.

Anderenfalls, also wenn das Formular nicht in der Datenblattansicht angezeigt wird, prüfen wir den Inhalt der Variablen m_IsSubform. Ist dieser True, befinden wir uns gerade in einem Unterformular. Dann zeigt der rechte Mausklick das Menü Form View Subform an, welches wir der Variablen cbr zuweisen. Ist es kein Unterformular, verwenden wir das Kontextmenü namens Form View Popup.

Danach löschen wir alle eventuell bereits aus vorherigen Anwendungen vorhandenen Schaltflächen mit den Beschriftungen Steuerelement-Infos anzeigen und Eigenschaften aus dem Kontextmenü. Das erledigen wir bei deaktivierter Fehlerbehandlung in jeweils einer Do While-Schleife, die verlassen wird, wenn ein Fehler aufgetaucht ist – und das geschieht, wenn das Löschen der genannten Elemente nicht mehr erfolgreich ist, weil kein passendes Element mehr gefunden werden konnte.

Dann fügen wir mit der Add-Methode der Controls-Auflistung der Menüleiste aus cbr ein neues Element zur Menüleiste hinzu und referenzieren dieses mit der Variablen cbb.

Für diese legen wir dann die Beschriftung fest, wobei diese wieder vom Wert der Variablen m_IsSubform abhängt. Weist diese den Wert True auf, haben wir ein Unterformular und geben den Text Unterformular gefolgt von einem Doppelpunkt und den aus m_frm.Name ermittelten Formularnamen an. Anderenfalls lautet der Text Formular: plus dem Formularnamen.

Schließlich rufen wir die Prozedur PropertiesHinzufuegen auf und übergeben dieser die Variable mit dem Verweis auf das CommandBar-Objekt.

Eigenschaften in Kontextmenü eintragen

Die Prozedur PropertiesHinzufuegen trägt die Eigenschaften des Formulars als Elemente des noch hinzuzufügenden Untermenüs Eigenschaften ein (siehe Listing 2). Sie erwartet eine Verweis auf das CommandBar-Objekt, dem das Untermenü hinzugefügt werden soll und deklariert die Variablen cbp (CommandBarPopup, für das Untermenü), prp (Property, für das Durchlaufen der Eigenschaften des Formulars) und cbb (CommandBarButton, für die anzulegenden Elemente im Untermenü).

Private Sub PropertiesHinzufuegen(cbr As CommandBar)
     Dim cbp As CommandBarPopup
     Dim prp As DAO.Property
     Dim cbb As CommandBarButton
     Set cbp = cbr.Controls.Add(msoControlPopup, , , , True)
     On Error Resume Next
     Do While Err.Number = 0
         cbr.Controls("Eigenschaften").Delete
     Loop
     On Error GoTo 0
     cbp.Caption = "Eigenschaften"
     For Each prp In m_frm.Properties
         Set cbb = cbp.Controls.Add(msoControlButton, , , , True)
         On Error Resume Next
         cbb.Caption = prp.Name & ": " & prp.Value
         On Error GoTo 0
     Next prp
End Sub

Listing 2: Prozedur zum Hinzufügen der Eigenschaften samt ihrer Werte

Das CommandBarPopup-Element cbp legen wir wieder mit der Add-Methode der Controls-Auflistung des CommandBar-Objekts an, diesmal mit dem Typ msoControlPopup als Wert des ersten Parameters.

Dann entfernen wir wieder eventuell vorhandene Elemente namens Eigenschaften und weisen dem neu erstellten Element genau diesen Namen zu. Schließlich durchlaufen wir alle Eigenschaften der Properties-Auflistung des Formulars aus m_frm in einer For Each-Schleife. Dabei legen wir für jede Eigenschaft ein neues Element im Untermenü an und weisen diesem als Beschriftung den Namen der Eigenschaft (prp.Name) und den Wert der Eigenschaft zu (prp.Value).

Damit ist das Kontextmenü für das Abfragen der Eigenschaften des Formulars so erweitert, dass es die gewünschten Informationen beim Rechtsklick anzeigt.

Die Klasse clsControls für die Kontextmenüs der Steuer-elemente

In der Klasse, die für jede einzelne Steuer-element des Formulars angelegt wird – und auch für Unterformulare und die darin enthaltenen Steuer-elemente -, deklarieren wir zunächst einige Variablen. Als Erstes benötigen wir für jeden gängigen Steuerelementtyp eine Variable, mit der wir das Steuer-element referenzieren können. Diese deklarieren wir mit dem Schlüsselwort WithEvents, damit wir wieder das Ereignis Bei Maustaste ab im gleichen Klassenmodul implementieren können. Wir deklarieren deshalb für jeden Steuerelementtyp eine eigene Variable, weil diese zwar eine Menge gemeinsamer Eigenschaften aufweisen, jeder Steuerelementtyp aber auch einige individuelle Eigenschaften aufweist:

Private WithEvents txt As TextBox
Private WithEvents chk As CheckBox
Private WithEvents cbo As ComboBox
Private WithEvents cmd As CommandButton
Private WithEvents lst As ListBox
Private WithEvents lbl As Label
Private WithEvents opt As OptionButton
Private WithEvents ogr As OptionGroup
Private WithEvents tgl As ToggleButton
Private WithEvents sfm As SubForm

Wir haben hier die wichtigsten Steuerelementtypen berücksichtigt. Sie können noch weitere Steuerelementtypen hinzufügen, wenn Sie Bedarf haben.

Außerdem benötigen wie eine Variable, die wir vorübergehend mit dem Verweis auf das Steuer-element füllen:

Private m_ctl As Control

Mit objForm wollen wir die Instanz der Klasse clsForm referenzieren, welche die Steuerelement-Klasse clsControl angelegt hat:

Private objForm As clsForm

Und in m_IsSubform speichern wir wiederum die Information, ob das Steuer-element sich in einem Unterformular befindet:

Private m_IsSubform As Boolean

Zum Einstellen der Eigenschaft m_IsSubform verwenden wir die folgende Property Let-Prozedur:

Public Property Let IsSubform(bol As Boolean)
     m_IsSubform = bol
End Property

Die Property Set-Prozedur Control erlaubt das Hinzufügen des Steuerelements zur Eigenschaft m_ctl. Sie wird von der übergeordneten Klasse clsForm gefüllt, wenn diese die Steuer-elemente des Formulars durchläuft und für jedes Steuer-element ein Objekt des Typs clsControl anlegt (siehe Listing 3).

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

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar