Steuerelemente an Datenblatt anpassen

Datenblätter sind sehr flexibel, wenn es um die Anzeige tabellarischer Daten geht. Sie können die Daten damit sortieren und filtern und die Breite und Sortierung der Spalten anpassen. Gelegentlich platziert man jedoch um ein Unterformular mit einem Datenblatt herum noch weitere Elemente wie etwa Schaltflächen oder individuelle Steuerelemente etwa zur Eingabe von Suchbegriffen. Diese sollen sich, wenn der Benutzer die Spalten ändert, natürlich anpassen. Wie dies gelingt, zeigt der vorliegende Beitrag.

Ein Anwendungsfall für das Anpassen von Steuerelementen an die Spalten eines Datenblatts ist das Formular aus dem Beitrag Textdateien vergleichen (www.access-im-unternehmen.de/922). Dieses zeigt in jeweils drei Spalten im Datenblatt des Unterformulars die Zeilennummer, ein Kontrollkästchen und den Zeileninhalt der Zeilen einer Datei an (s. Bild 1). Der Benutzer wird hier gelegentlich die Breite der beiden Spalten Datei 1 und Datei 2 verändern, um den kompletten Inhalt einer Zeile lesen zu können.

Beispiel für Steuerelemente, die sich auf die Spalten eines Datenblatts im Unterformular beziehen

Bild 1: Beispiel für Steuerelemente, die sich auf die Spalten eines Datenblatts im Unterformular beziehen

Wir können der Abbildung schon die Vorgaben entnehmen, die wir programmieren müssen: Die Textfelder zur Eingabe des Dateinamens sollen linksbündig mit den Spalten zur Anzeige der Zeilenzahl abschließen. Die Schaltflächen sollen rechtsbündig mit der Spalte zur Anzeige der Zeileninhalte abschließen. Die Schaltflächen haben eine feste Breite. Die Breite der Textfelder zur Eingabe der Dateinamen orientiert sich an der Gesamtbreite der drei Spalten minus der Breite der Schaltfläche zur Auswahl der Textdatei.

Bild 2 zeigt, wie das Formular nach dem Vergrößern etwa der Spalten zur Anzeige der Spalteninhalte aussieht. Wie man sieht, ist eine dynamische Anpassung der darüber angeordneten Steuerelemente aus optischen Gründen dringend erforderlich. Was ist zu tun Wir müssen erstens ein Ereignis identifizieren, das durch das ändern der Spaltenbreiten ausgelöst wird. Zweitens müssen wir die Breiten ermitteln und definieren, wie die Breite der Steuerelemente im Hauptformular in Abhängigkeit davon eingestellt wird. Drittens – und das ist sehr wichtig – müssen wir in diesem Fall verhindern, dass der Benutzer die Reihenfolge der Spalten ändert. Das würde unsere Regeln für die Einstellung der Breite der Steuerelemente im Hauptformular empfindlich stören. In anderen Anwendungsfällen, wo etwa jeweils ein Steuerelemente im Hauptformular einer Spalte im Unterformular zugeordnet ist, sieht das anders aus – hier erhält einfach jedes Steuerelement die Position und die Breite der jeweils zugeordneten Spalte im Datenblatt des Unterformulars.

Nach dem ändern der Spaltenbreiten befinden sich die Steuerelemente im Hauptformular nicht mehr exakt über den Spalten.

Bild 2: Nach dem ändern der Spaltenbreiten befinden sich die Steuerelemente im Hauptformular nicht mehr exakt über den Spalten.

Ereignis identifizieren

Als Erstes wollen wir herausfinden, über welches Ereignis wir überhaupt auf änderungen der Position oder Breite der Spalten reagieren können. Dazu betrachten wir zunächst die Liste der Ereigniseigenschaften des Unterformulars. Wie ändert der Benutzer überhaupt die Breite oder Position von Spalten im Datenblatt Dies ist nur mit der Maus möglich: Zum ändern der Reihenfolge der Spalten klickt der Benutzer zunächst den Spaltenkopf der zu verschiebenden Spalte an und zieht diesen dann bei gedrückter Maustaste an die gewünschte Position. ähnlich sieht es beim Anpassen der Spaltenbreiten aus: Hier drückt der Benutzer die Maustaste herunter, wenn sich der Mauszeiger über einem der Zwischenräume zwischen zwei Spaltenköpfen befindet und zieht den Zwischenraum an die gewünschte Position. Eine weitere Möglichkeit ist ein Doppelklick auf den Zwischenraum zwischen zwei Spaltenköpfen, um die optimale Breite der Spalte entsprechend den Inhalten einzustellen.

Die Mausbewegungen und Mausklicks lösen grundsätzlich die Ereignisse Bei Mausbewegung, Bei Maustaste ab und Bei Maustaste auf aus. Aber es gibt einige dieser Ereignisse in einem Formular: für das Formular selbst, für die einzelnen Bereiche und auch für jedes einzelne Steuerelement.

Um herauszufinden, ob die Ereignisse eines dieser Bereiche für uns hilfreich sind, müssen wir experimentieren. Dazu legen wir einfach entsprechende Ereignisprozeduren an und schauen, welches Ereignis wann ausgelöst wird.

Welche Kandidaten wollen wir untersuchen Wir nehmen uns die drei Ereignisse des Formulars selbst, des Detailbereichs (da keine anderen Bereiche für das Unterformular definiert wurden) und, als Beispiel für eines der Steuerelemente, das Textfeld Datei1.

Die Programmierung der Ereignisprozeduren finden Sie in Listing 1.

Private Sub Datei1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Datei1_MouseDown"
End Sub
Private Sub Datei1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Datei1_MouseMove"
End Sub
Private Sub Datei1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Datei1_MouseUp"
End Sub
Private Sub Detailbereich_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Detailbereich_MouseDown"
End Sub
Private Sub Detailbereich_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Detailbereich_MouseMove"
End Sub
Private Sub Detailbereich_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Detailbereich_MouseUp"
End Sub
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Form_MouseDown"
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Form_MouseMove"
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Debug.Print "Form_MouseUp"
End Sub

Listing 1: Prozeduren zum Ermitteln des Ereignisses zum Abfangen von Spaltenänderungen

Nun prüfen wir, welches Mausbewegung welches Ereignis auslöst. Dazu positionieren Sie das Access-Fenster mit dem zu untersuchenden Formular und das VBA-Fenster nebeneinander. Wenn Sie dann mit der Maus über die Spaltenköpfe des Unterformulars fahren, sollte sich etwas im Direktbereich des VBA-Editors tun. Wenn Sie nun noch beispielsweise die Breite einer Spalte durch Anklicken und Ziehen des Zwischenraums zwischen den Spaltenköpfen ändern, sollte das Ergebnis im Direktfenster etwa wie in Bild 3 aussehen. Bingo – wir benötigen die Ereignisse Bei Maustaste ab, Bei Mausbewegung und Bei Maustaste auf, um das ändern der Spaltenbreiten zu ermitteln.

Ereignisse im Direktbereich des VBA-Editors

Bild 3: Ereignisse im Direktbereich des VBA-Editors

Wann sollen die Steuerelemente angepasst werden

Nachdem wir die passenden Ereignisse identifiziert haben, schauen wir uns an, zu welchen Zeitpunkten die Steuerelemente im Hauptformular an die Spalten im Unterformular angepasst werden sollen. Dies ist immer dann der Fall, wenn der Benutzer die Maustaste auf den Spaltenköpfen gedrückt hat und den Mauszeiger bewegt. Wenn er ihn wieder loslässt, soll nichts mehr geschehen.

Bei einer naiven Herangehensweise verwenden wir nur das Ereignis Bei Mausbewegung: Immerhin bietet das mit dem Parameter button die Möglichkeit zu ermitteln, ob und welche Maustaste der Benutzer beim Bewegen der Maus gedrückt hält. Leider liefert und dies allerdings keine Information darüber, wann der Benutzer die Maustaste heruntergedrückt hat. Um zu prüfen, ob der Mauszeiger auf einem der Spaltenköpfe heruntergedrückt und dann bewegt wurde, bedienen wir uns einer Boolean-Variablen namens bolMausGedrueckt, die beim Eintreten des Ereignisses Bei Maustaste ab des Formulars auf den Wert True eingestellt wird. In der Prozedur, die durch das Ereignis Bei Mausbewegung ausgelöst wird, prüfen wir nun, ob bolMausGedrueckt den Wert True hat. In diesem Fall wurde der Mauszeiger auf einem der Spaltenköpfe niedergedrückt und bewegt.

Wenn der Benutzer die Maustaste wieder loslässt, soll die Variable bolMausGedrueckt wieder auf den Wert False eingestellt werden. Unsere aktuelle Konfiguration sieht also nun wie in Listing 2 aus.

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
     bolMausGedrueckt = True
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
     If bolMausGedrueckt Then
         Debug.Print "Ziehen der Spalten", Button, Shift, X, Y
     End If
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
     bolMausGedrueckt = False
End Sub

Listing 2: Das Ereignis Form_MouseMove soll nur reagieren, wenn die Maustaste gedrückt wurde.

Wenn wir dies nun testen, kommt es darauf an, alle möglichen Verhaltensweisen zu erfassen – denken Sie daran: Der Benutzer deckt alle Schwachstellen auf! Also bemühen wir uns lieber gleich selbst, dies zu erledigen. Experimentieren Sie: Klicken Sie doppelt auf die Spaltenköpfe, ziehen Sie bei gedrückter Maustaste, bewegen Sie die Maus ohne gedrückte Maustaste – es funktioniert! Ups, doch nicht: Da bin ich doch aus Versehen bei gedrückter Maustaste von der Zeile der Spaltenköpfe abgekommen und habe erst dort die Maustaste losgelassen. Das heißt, dass die Variable bolMausGedrueckt nicht wieder auf den Wert False eingestellt wird. Das ist ungünstig, weil die Prozedur Form_MouseMove so beim nächsten überfahren gleich davon ausgeht, dass wir die Maustaste bereits gedrückt haben.

Wir benötigen also doch noch die Maus-Ereignisse anderer Elemente des Formulars, um die Variable bolMausGedrueckt auf False zu setzen, wenn sich der Mauszeiger auf einem anderen Element als einem der Spaltenköpfe befindet und die Maustaste bereits wieder losgelassen wurde. Dazu müssen wir zunächst herausfinden, welche Elemente des Formulars davon betroffen sein könnten. Wir fügen also dem Detailbereich und dem Textfeld Datei1 (stellvertretend für die übrigen Steuerelemente des Datenblatts) wieder Ereignisprozeduren hinzu, die durch die drei Maus-Ereignisse ausgelöst werden. Diese enthalten nun Anweisungen wie die folgenden:

If bolMausGedrueckt Then
     Debug.Print "Datei1_MouseDown"
End If

Wir wollen also immer, wenn der Benutzer außerhalb der Spaltenköpfe die Maustaste loslässt, eine entsprechende Ausgabe im Direktbereich bewirken.

Das Ergebnis ist, dass wir allen Steuerelementen des Datenblatts eine Ereignisprozedur mitgeben müssen, welche die Variable bolMausGedrueckt auf False einstellt, wenn der Benutzer die Maustaste über einem der Steuerelemente loslässt.

In unserem Beispiel ist die Anzahl der Steuerelemente im Unterformular überschaubar – es sind nur sechs Stück. Für diese können wir die notwendigen Ereignisprozeduren, jeweils ausgelöst durch das Ereignis Bei Maustaste auf, von Hand anlegen. Eines davon sieht etwa wie in Listing 3 aus.

Private Sub Datei1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
     If bolMausGedrueckt Then
         bolMausGedrueckt = False
     End If
End Sub

Listing 3: Einstellen der Variablen bolMausGedrueckt auf den Wert False.

Fehlt noch der Fall, dass der Benutzer die Maustaste auf einem der Spaltenköpfe niederdrückt und dann den Mauszeiger außerhalb des Unterformulars mit der Datenblattansicht positioniert, bevor er die Maustaste loslässt. Für diesen Fall hat Microsoft ein für uns günstiges Verhalten definiert: Dies löst dann einfach das Ereignis Form_MouseUp des Unterformulars aus, wo als ob der Mauszeiger dieses nie verlassen hätte.

Ständiges Anpassen

Nun stellt sich die Frage, ob wir wirklich bei jedem Feuern des Ereignisses Form_MouseMove die Steuerelemente anpassen müssen, wenn bolMausGedrueckt den Wert True hat. Flackert das nicht zu sehr Hier zeigt sich mal wieder, wie wenig man (in diesem Fall zumindest ich) auf Details achtet: Die Breite eines Spaltenkopfes ändert sich nämlich gar nicht während des Ziehens mit der Maus, sondern erst, wenn der Benutzer diese loslässt! Wir brauchen also nur das Ereignis Bei Maustaste auf zu untersuchen!

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