Access bietet verschiedene Möglichkeiten, um Steuerelemente auszurichten. Diese stellen wir im Beitrag Steuerelemente ausrichten (www.access-im-unternehmen.de/1431) vor. All diese Methoden haben jedoch Vor- und Nachteile. Der größte Nachteil ist, dass sie Zeit kosten – Zeit, die man in viel schönere Arbeiten investieren könnte. Deshalb schauen wir uns in diesem Beitrag an, wie wir in der Entwurfsansicht selektierte Steuerelemente einfach per VBA ausrichten können. Dabei ist nicht die Technik die entscheidende Frage, sondern die Vorgabe, nach welchen Regeln die Ausrichtung genau erfolgen soll. In diesem Beitrag beschreiben wir, wie man per VBA solche Steuerelemente wie Textfeld, Kombinationsfeld, Listenfeld und Kontrollkästchen und ihre Bezeichnungsfelder, die untereinander angeordnet sind, ausrichten kann.
Ausgangssituation im Formular
Wir gehen davon aus, dass Sie als Entwickler auch mit dem Zusammenstellen von Formularen und dem Layout der enthaltenen Steuerelemente zu tun haben.
In vielen Fällen kann man sich die Aufgabe, Steuerelemente sauber ausgerichtet anzulegen, erleichtern – zum Beispiel durch das Ziehen der gebundenen Felder aus der Feldliste in das Formular.
Aber sobald man der Datensatzquelle des Formulars ein weiteres Feld hinzugefügt hat, das nun auch im Formularentwurf landen soll, muss man seine Position an die der anderen anpassen.
Da ist man mit den im oben genannten Beitrag vorgestellten Methoden durchaus ein paar Sekunden beschäftigt – und dabei handelt es sich um eine Tätigkeit, die man während eines Access-Entwicklerlebens sehr oft wiederholt.
Wir wollen die Ausgangssituation noch ein wenig chaotischer darstellen und gehen während der Entwicklung von Steuerelementen aus, die wie in Bild 1 angeordnet sind.
Bild 1: Ausgangssituation im Formular
Vorgaben zur Anordnung von Steuerelementen
Wenn man diese nun manuell anordnen würde, wäre das Markieren aller Beschriftungsfelder durch Ausziehen eines geeigneten Rahmens wohl der erste Schritt. Dann würde man aus dem Kontextmenü den Befehl Ausrichten|Linksbündig wählen. Als Nächstes wären dann die Textfelder an der Reihe, die man auf die gleiche Weise linksbündig anordnet.
Dann bringt man diese vielleicht noch auf eine Breite und verschiebt sie so nah an die Beschriftungsfelder heran, dass der Abstand zwischen dem breitesten Beschriftungsfeld und den Textfeldern etwa so groß ausfällt wie der vertikale Abstand zwischen den Textfeldern. Das Ergebnis sieht dann beispielsweise wie in Bild 2 aus.
Bild 2: Fertig ausgerichtete Steuerelemente
Vorgang per VBA abbilden
Nun wollen wir diese ganzen Schritte per VBA erledigen. Dazu können wir grundsätzlich ähnlich vorgehen. Aber welche Rahmenbedingungen dazu wollen wir festhalten? Als Erstes benötigen wir die Position unseres Blocks vom linken und vom oberen Rand aus betrachtet. Deshalb ermitteln wir die Y-Position des obersten Steuerelements und die X-Position des am weitesten links befindlichen Steuerelements.
Danach würden wir die Position aller Bezeichnungsfelder links an der soeben ermittelten Position ausrichten.
Danach wird es schon spannend – nämlich bei der Positionierung der Steuerelemente von oben nach unten. Die erste Idee war, einfach alle markierten Steuerelemente von oben nach unten zu durchlaufen und dabei dem obersten Steuerelement den soeben ermittelten Abstand vom oberen Rand zu vergeben. Die nachfolgenden Steuerelemente würden wir dann jeweils unter dem zuvor ausgerichteten Steuerelement positionieren – mit einem kleinen zusätzlichen Abstand.
Allerdings durchläuft Access die Steuerelemente über die Controls-Auflistung in der Reihenfolge, die durch die Aktivierreihenfolge vorgegeben wurde. Hier stellt sich die Frage, ob wir die Steuerelemente nach der Aktivierreihenfolge ausrichten wollen oder nach der aktuellen vertikalen Anordnung. Intuitiver scheint es, die Steuerelemente nach der aktuellen Anordnung auszurichten.
Diese müssten wir dann erst einmal ermitteln – und das ist nicht gerade trivial. Unsere Lösung für diese Frage ist, den Steuerelementnamen und die Y-Position in einem zweidimensionalen Array zu speichern und die Daten in diesem Array nach der Y-Position zu sortieren, bevor wir sie in der so festgelegten Reihenfolge ausrichten.
Des Weiteren stellt sich die Frage, ob wir uns bei der Höhe für ein Bezeichnungsfeld-Steuerelement-Paar nach der Höhe des Bezeichnungsfeldes oder des Steuerelements richten. Es kann sowohl vorkommen, dass das Bezeichnungsfeld höher ist als das Steuerelement (bei einer längeren Bezeichnung), aber auch Textfelder kommen gelegentlich mit einer größeren Höhe, beispielsweise um mehrere Zeilen anzuzeigen.
Spätestens wenn Listenfelder ins Spiel kommen, sind diese meist höher als das jeweilige Bezeichnungsfeld.
Die einfachste Lösung für diesen Fall scheint zu sein, das jeweils höhere Element zu berücksichtigen.
Bei den Bezeichnungsfeldern stellt sich die Frage, ob diese bereits die richtige Breite aufweisen. Sicherheitshalber wollen wir die Breite auf den tatsächlich enthaltenen Bezeichnungstext anpassen. Damit ermitteln wir nun die maximale Breite der Bezeichnungsfelder und stellen alle Bezeichnungsfelder auf diese Breite ein. Dies ist eine Vorbereitung auf den Fall, dass der Benutzer seine Bezeichnungsfelder rechtsbündig ausrichten möchte.
Danach richten wir die eigentlichen Steuerelemente, in unserem Beispiel also die Textfelder, entsprechend aus. Dabei nutzen wir die X-Position der Bezeichnungsfelder plus ihre Breite plus wiederum einem kleinen Abstand, wie wir ihn auch bereits für die vertikale Anordnung genutzt haben.
Sonderfall Kontrollkästchen
Während die Höhe von Textfeldern in der Regel an die jeweiligen Bezeichnungsfelder angepasst ist, sind Kontrollkästchen etwas weniger hoch und ihr Abstand vom oberen Rand des Formulars stimmt nicht mit dem des dazugehörigen Bezeichnungsfelds überein. Hier müssen wir eine Spezialbehandlung vornehmen. Wir können das Kontrollkästchen nicht auf der gleichen Y-Position wie das Bezeichnungsfeld platzieren, da es sonst optisch etwas zu weit oben angezeigt wird.
Also bauen wir beim Ausrichten des Kontrollkästchens einen zusätzlichen Abstand von oben ein. Da es normalerweise auch noch weniger hoch als ein Textfeld oder Bezeichnungsfeld ist, müssen wir in diesem Fall die Höhe des Bezeichnungsfeldes als Maßstab für die Ausrichtung des darunter liegenden Steuerelements nutzen.
Zusätzliche Einstellungen
Neben den bereits erwähnten Vorgaben wollen wir dem Benutzer noch die Möglichkeit geben, weitere Einstellungen vorzunehmen. Dazu stellen wir der Hauptprozedur einige Parameter bereit. Damit wollen wir die folgenden Einstellungen vornehmen:
- Abstand zwischen Bezeichnungsfeld und Steuerelement in Pixeln
- Vertikaler Abstand zwischen zwei Steuerelementen
- Ausrichtung der Bezeichnungsfelder – wahlweise Standard, links, mittig oder rechts zentriert oder verteilt
- Optionales Hinzufügen von Doppelpunkten rechts von den Beschriftungen, sofern noch nicht vorhanden
Doppelpunkte hinter Beschriftungen setzen
Zum Aufwärmen wollen wir die Prozedur schreiben, mit der wir den aktuell markierten Bezeichnungsfeldern einen Doppelpunkt hinzufügen, sofern dieser noch nicht vorhanden ist. Diese Prozedur heißt AddColonToLabels und ist in Listing 1 abgebildet.
Public Sub AddColonToLabels() Dim frm As Form Dim ctl As Control Set frm = Screen.ActiveForm For Each ctl In frm.Controls If ctl.InSelection Then Select Case ctl.ControlType Case acLabel If Not Right(ctl.Caption, 1) = ":" Then ctl.Caption = ctl.Caption & ":" End If End Select End If Next ctl End Sub
Listing 1: Hinzufügen von Doppelpunkten zu den Bezeichnungsfeldern
Die Prozedur können wir auch allein aufrufen. Sie deklariert eine Form– und eine Control-Variable. Mit der Form-Variable frm referenziert sie über die Eigenschaft Screen.ActiveForm das aktuell markierte Formular. Die Variable ctl kann alle Steuerelemente referenzieren. Damit durchlaufen wir in einer For Each-Schleife alle Steuerelemente des referenzierten Formulars.
In der folgenden If…Then-Bedingung prüfen wir mit der Eigenschaft InSelection, ob das aktuelle mit ctl über die Schleife referenzierte Steuerelement derzeit markiert ist. Ist das der Fall, untersuchen wir in einer Select Case-Bedingung durch einen Vergleich der Eigenschaft ControlType mit der Konstanten acLabel, ob es sich um ein Bezeichnungsfeld handelt. Falls ja, prüfen wir schließlich noch, ob das letzte Zeichen ein Doppelpunkt ist. Ist das nicht der Fall, fügen wir der Eigenschaft Caption am Ende einen Doppelpunkt hinzu.
Diese Prozedur können Sie nun bereits ausprobieren. Dazu fügen Sie einem Formular in der Entwurfsansicht ein beliebiges Steuerelement mit einem Bezeichnungsfeld hinzu oder ein einzelnes Bezeichnungsfeld. Dieses markieren Sie nun. Anschließend rufen Sie die Prozedur AddColonToLabels auf. Sollte das Bezeichnungsfeld zu diesem Zeitpunkt noch keinen abschließenden Doppelpunkt haben, wird dieser nun hinzugefügt.
Prozedur zum Ausrichten der Steuerelemente
Nach dem Aufwärmen schauen wir uns gleich die Hauptprozedur der Lösung aus diesem Beitrag an. Diese heißt AlignControls und erwartet vier Parameter:
- lngDistanceLabelControl: Abstand zwischen Beschriftungsfeld und Steuerelement in Punkten
- lngVerticalDistance: Vertikaler Abstand zwischen Steuerelementen
- varAlignment: Ausrichtung des Textes in den Bezeichnungsfeldern (0: Standard, 1: Links, 2: Zentriert, 3: Rechts, 4: Verteilen)
- bolColons: Gibt an, ob Doppelpunkte hinzugefügt werden sollen.
Die Prozedur finden Sie in Listing 2. Die von dieser Prozedur aufgerufenen weiteren Funktionen und Prozeduren bilden wir im Verlauf ab. Die Prozedur deklariert zunächst einige Variablen.
Public Sub AlignControls(Optional lngDistanceLabelControl As Long = 100, Optional lngVerticalDistance As Long = 100, _ Optional varAlignment As Variant = 0, Optional bolColons As Boolean = False) Dim frm As Form, ctl As Control Dim lngLabelLeft As Long, lngLabelWidth As Long, lngControlLeft As Long, lngTop As Long, lngMaxHeight As Long Dim lblControl As Label, varControls() As Variant, i As Integer If Not GetFormInDesignView(frm) Then MsgBox "Es ist kein Formular in der Entwurfsansicht geöffnet.", vbOKOnly + vbExclamation Exit Sub End If If GetSelectedControlCount(frm) < 2 Then MsgBox "Es müssen mindestens zwei Steuerelemente ausgewählt sein.", vbOKOnly + vbExclamation Exit Sub End If DoCmd.Echo False If bolColons Then AddColonToLabels End If OptimizeLabelSizes frm lngLabelLeft = GetMostLeftLabel(frm) lngLabelWidth = GetMaxLabelWidth(frm) lngControlLeft = lngLabelWidth + lngDistanceLabelControl + lngLabelLeft varControls = GetControlArray(frm) SortArray varControls lngTop = varControls(0, 0) For i = 0 To UBound(varControls, 2) Set ctl = frm.Controls(varControls(1, i)) ctl.Left = lngControlLeft If Not lngTop = 0 Then ctl.Top = lngTop If ctl.ControlType = acCheckBox Then ''Korrektur für Kontrollkästchen ctl.Top = ctl.Top + 30 End If Set lblControl = ctl.Controls(0) lngMaxHeight = ctl.Height If lblControl.Height > lngMaxHeight Then lngMaxHeight = lblControl.Height End If lblControl.Top = lngTop lblControl.Left = lngLabelLeft lblControl.Width = lngLabelWidth If Not IsMissing(varAlignment) Then lblControl.TextAlign = varAlignment End If End If lngTop = lngTop + lngMaxHeight + lngVerticalDistance Next i DoCmd.Echo True End Sub
[
Listing 2: Hauptprozedur zum Ausrichten von Steuerelementen
Aktuelles Formular in der Entwurfsansicht holen
Direkt die erste Anweisung ruft eine Hilfsfunktion namens GetFormInDesignView auf, welche eine leere Rückgabevariable namens frm als Parameter erhält. Die Funktion, die wir in Listing 3 abgebildet haben, hat die Aufgabe, das aktuelle Formular zu ermitteln und gleich noch zu prüfen, ob dieses in der Entwurfsansicht geöffnet ist. Anderenfalls können wir nämlich nicht auf die aktuell markierten Steuerelemente zugreifen.
Public Function GetFormInDesignView(frm As Form) As Boolean On Error Resume Next Set frm = Screen.ActiveForm If Not frm Is Nothing Then If frm.CurrentView = 0 Then GetFormInDesignView = True End If End If On Error GoTo 0 End Function
Listing 3: Funktion zum Holen des aktuellen Formulars in der Entwurfsansicht
Die Funktion holt mit Screen.ActiveForm das Formular, welches aktuell den Fokus hat. Das kann bereits schiefgehen, wenn gerade kein Formular den Fokus hat – in diesem Fall ist frm danach leer und die Funktion wird mit dem Wert False verlassen.
Enthält frm danach jedoch ein Formular, prüfen wir seine Ansicht mit der CurrentView-Eigenschaft. Hat diese den Wert 0, ist das aktuelle Objekt ein Formular in der Entwurfsansicht und wir können den Wert True als Funktionswert zurückliefern – die Rückgabevariable frm ist ja ohnehin bereits mit einem Verweis auf das betroffene Formular gefüllt.
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