Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 5/2015.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Spaltenbreiten optimieren mit Klasse

Wenn Sie Daten in der Datenblattansicht von Unterformularen anzeigen, stoßen Sie immer wieder auf das Problem, dass die Spaltenbreiten nicht gleich zu Beginn optimal an die Inhalte der Spalten angepasst werden – also an die Breite der angezeigten Daten. Immerhin kann der Benutzer die Breite in der Regel selbst anpassen. Praktischer aber wäre es, wenn die Spaltenbreiten gleich beim Anzeigen der Daten optimiert würden. Der vorliegende Beitrag zeigt eine kleine Klasse, mit der Sie dies bewerkstelligen können.

Für die Demonstration der in diesem Beitrag vorgestellten Klasse eignet sich am besten ein Unterformular in der Datenblattansicht, das seine Daten nach der Auswahl etwa eines Filters im Hauptformular ändert, wodurch eine erneute Optimierung der Spaltenbreiten erforderlich wird. Dazu legen wir ein Unterformular namens sfmArtikel an, das mit Feldern der Tabelle tblArtikel wie in Bild 1 gefüllt ist und seine Daten in der Datenblattansicht präsentiert.

Vorbereitung für das automatische Anpassen der Spaltenbreiten

Bild 1: Vorbereitung für das automatische Anpassen der Spaltenbreiten

Dieses Formular fügen wir in einem weiteren Formular namens frmArtikeNachKategorie ein, dem wir als Datenherkunft die Tabelle tblKategorien hinzufügen. Das Formular soll die beiden Felder KategorieID und Kategorie anzeigen. Ziehen Sie das Unterformular sfm­Artikel in den Entwurf. Dadurch sollten die beiden Eigenschaften Verknüpfen von und Verknüpfen nach automatisch auf den Wert KategorieID eingestellt werden (s. Bild 2).

Verknüpfung zwischen Haupt- und Unterformular

Bild 2: Verknüpfung zwischen Haupt- und Unterformular

Öffnen Sie das Hauptformular nun in der Formularansicht, kann es sein, dass die Spaltenbreiten entweder viel zu breit oder zu schmal für die anzuzeigenden Inhalte eingestellt sind (s. Bild 3). Dies wollen wir ändern, indem wir die Spaltenbreiten zu jeder Aktualisierung der Datenherkunft des Unterformulars neu anpassen.

Unglückliche Darstellung der Spalten

Bild 3: Unglückliche Darstellung der Spalten

Dazu sind, wenn wir die fertige Klasse, welche diese Aufgabe erledigt, als vorhanden voraussetzen, nur wenige Handgriffe nötig.

Automatische Spaltenoptimierung einbauen

Damit die Spalten automatisch angepasst werden, sind nur drei Schritte nötig:

  • Hinzufügen der Klasse clsColumnWidths
  • Schreiben einiger Zeilen Code ins Klassenmodul des Hauptformulars
  • Hinzufügen des Klassenmoduls zum Unterformular

Klasse nutzen

Nachdem Sie die Klasse clsColumnWidths zum VBA-Projekt der Datenbank hinzugefügt haben, legen Sie eine neue Ereignisprozedur für das Ereignis Beim Laden des Hauptformulars an. Diese füllen Sie wie folgt:

Private Sub Form_Load()
     Set objColumnWidths = New clsColumnWidths
     With objColumnWidths
         Set .DataSheetForm = Me!sfmArtikel.Form
        .OptimizeColumnWidths
     End With
End Sub

Außerdem benötigen Sie noch eine Deklarationszeile für das Objekt objColumnWidths, die Sie im Kopf des Klassenmoduls einfügen:

Dim objColumnWidths As clsColumnWidths

Die Prozedur instanziert zunächst ein Objekt auf Basis der Klasse clsColumnWidths. Danach übergibt sie diesem Objekt über seine Eigenschaft DataSheetForm einen Verweis auf das Unterformular, das mit der Funktion zum automatischen Anpassen der Spaltenbreiten ausgestattet werden soll. Schließlich wird die Methode OptimizeColumnWidths zum Optimieren der Spalten einmalig aufgerufen, damit das Unterformular gleich optimiert wird. Wenn Sie das Formular nun öffnen, ohne den oben genannten dritten Schritt durchzuführen, tut sich nichts – die Spaltenbreiten behalten die vorherigen Einstellungen und werden nicht optimiert.

Sie müssen also unbedingt das Klassenmodul zum Unterformular sfmArtikel hinzufügen – auch wenn Sie gar keine Ereignisprozeduren für das Unterformular benötigen. Dies erledigen Sie, indem Sie die Eigenschaft Enthält Modul des Unterformulars auf den Wert Ja einstellen. Danach sollten die Spaltenbreiten etwa wie in Bild 4 erscheinen.

Spalten mit optimierten Breiten

Bild 4: Spalten mit optimierten Breiten

Das Objekt objColumnWidths haben wir modulweit deklariert, damit es auch nach der Ausführung der Ereignisprozedur Form_Load noch erhalten bleibt. Auf diese Weise wird es nun regelmäßig ausgelöst, wenn der Benutzer den Datensatz im Unterformular wechselt oder das Unterformular gefiltert wird. Dies geschieht beispielsweise auch, wenn Sie den Kategorie-Datensatz im Hauptformular wechseln. Sie können einmal durch die Datensätze scrollen und betrachten, wie die Spaltenbreiten jeweils an die angezeigten Daten angepasst werden.

Durch die modulweite Deklaration können Sie außerdem von jeder anderen Prozedur aus die Methode OptimizeColumnWidths aufrufen, um die Spaltenbreiten zu aktualisieren.

Anpassung nur nach Wunsch

Mit der Eigenschaft OptimizeAutomatically können Sie der Klasse auch mitteilen, dass die automatische Optimierung nicht erwünscht ist:

objColumnWidths.OptimizeAutomatically = False

In diesem Fall stoßen Sie die Optimierung der Spaltenbreiten ausschließlich über die Methode OptimizeColumnWidths an. OptimizeAutomatically hat standardmäßig den Wert True.

Warum OptimizeColumnWidths beim Start?

Die automatische Optimierung erfolgt immer dann, wenn eines der Ereignisse Form_Current (Beim Anzeigen) oder Form_ApplyFilter (Bei Filter) ausgelöst wird. Allerdings wurde Form_Current für den ersten Datensatz im Unterformular bereits ausgelöst, bevor wir im Form_Load-Ereignis die Klasse instanzieren und einstellen können.

Daher müssen Sie die Methode OptimizeColumnWidths nach dem Instanzieren einmal direkt aufrufen.

Verwendung der Klasse für mehrere Formulare

Wenn Sie mehrere Unterformulare mit der Funktion der Klasse ausstatten wollen, ist dies kein Problem.

Deklarieren Sie einfach für jedes Unterformular eine eigene Objektvariable:

Dim objCWUnterformular1 As clsColumnWidths
Dim objCWUnterformular1 As clsColumnWidths

Dann schreiben Sie die entsprechenden Anweisungen für beide Objekte in das Form_Load-Ereignis des Formulars mit den Unterformularen:

Private Sub Form_Load()
     Set objCWUnterformular1 = New clsColumnWidths
     With objCWUnterformular1
         Set .DataSheetForm = Me!sfmArtikel.Form
        .OptimizeColumnWidths
     End With
    Set objCWUnterformular1 = New clsColumnWidths
     With objCWUnterformular1
         Set .DataSheetForm = Me!sfmArtikel.Form
        .OptimizeColumnWidths
     End With
End Sub

Im Falle eines Fehlers ...

Wenn bei der Arbeit mit dem Formularen ein nicht behandelter Fehler auftritt, werden Objektvariablen wie objColumnWidths gelöscht. Der Zugriff darauf führt dann zu einem Fehler. Um dies zu testen, haben wir dem Beispielformular eine Schaltfläche zum Auslösen eines Fehlers hinzugefügt:

Private Sub cmdFehler_Click()
     MsgBox 1 / 0
End Sub

Wenn Sie diesen Fehler ausgelöst haben, führt das nachfolgende Aufrufen der Methoden des Objekts objColumnWidths zu einem Fehler.

Auch dazu haben wir eine Schaltfläche hinzugefügt, die folgendes Ereignis auslöst:

Private Sub cmdSpaltenbreitenOptimieren_Click()
     objColumnWidths.OptimizeColumnWidths
End Sub

Bild 5 zeigt die Fehlermeldung nach Betätigung der beiden Schaltflächen an.

Fehler beim Versuch, ein durch einen Fehler geleertes Objekt zu nutzen

Bild 5: Fehler beim Versuch, ein durch einen Fehler geleertes Objekt zu nutzen

Dies lässt sich am einfachsten verhindern, indem Sie Fehler entsprechend behandeln.

Aufbau der Klasse clsColumnWidths

Die Klasse clsColumnWidths erstellen Sie, indem Sie über den Menüeintrag Einfügen|Klassenmodul des VBA-Editors ein neues Klassenmodul hinzufügen und dieses unter dem Namen clsColumnWidth speichern. Dann fügen Sie zunächst zwei Variablen zum Klassenmodul hinzu:

Dim WithEvents m_Form As Form
Dim m_OptimizeAutomatically As Boolean

Die erste soll einen Verweis auf das Formular aufnehmen, das in der Datenblattansicht erscheint und dessen Spalten automatisch optimiert werden sollen. Die zweite nimmt einen Boolean-Wert auf, mit dem die instanzierende Routine festlegt, ob die Spaltenbreiten automatisch beim Datensatzwechsel oder beim Filtern oder nur nach expliziter Aufforderung optimiert werden sollen.

Nach dem Instanzieren der Klasse weist die aufrufende Routine der Eigenschaft DataSheetForm einen Verweis auf das zu behandelnde Formular zu.

Dazu stellt die Klasse die folgende Property Set-Prozedur zur Verfügung:

Public Property Set DataSheetForm(frm As Form)
     Set m_Form = frm
     m_Form.OnCurrent = "[Event Procedure]"
     m_Form.OnApplyFilter = "[Event Procedure]"
End Property

Diese schreibt das mit frm übergebene Formular-Objekt in die Variable m_Form und legt außerdem mit den beiden Eigenschaften OnCurrent und OnApplyFilter fest, dass die Klasse auf diese beiden Ereignisse des mit m_Form referenzierten Formulars lauschen soll.

Diese beiden Ereignisse müssen wir natürlich auch implementieren. Dazu legen Sie die folgenden beiden Ereignisprozeduren an:

Private Sub m_Form_Current()
     If m_OptimizeAutomatically Then
         OptimizeColumnWidths
     End If
End Sub
Private Sub m_Form_ApplyFilter(Cancel As Integer,  ApplyType As Integer)
     If m_OptimizeAutomatically Then
         OptimizeColumnWidths
     End If
End Sub

Beide Prozeduren prüfen den Inhalt der Variablen m_OptimizeAutomatically. Hat diese den Wert True, rufen die Ereignisprozeduren die Routine OptimizeColumnWidths auf. Diese sieht wie folgt aus:

Public Sub OptimizeColumnWidths()
     Dim ctl As control
     m_Form.RowHeight = 1
     For Each ctl In m_Form.Controls
         Select Case ctl.ControlType
             Case acTextBox, acComboBox, acCheckBox,  acListBox
                 If Len(ctl.ControlSource) > 0 And  ctl.ColumnHidden = False Then
                     ctl.ColumnWidth = -2
                 End If
             Case Else
         End Select
     Next ctl
     m_Form.RowHeight = -1
End Sub

Die Prozedur stellt im Wesentlichen die Eigenschaft ColumnWidth eines der Steuerelemente Textfeld, Kontrollkästchen, Kombinationsfeld oder Listenfeld auf den Wert -2 ein, was bewirkt, dass die Breite der jeweiligen Spalte für die aktuell sichtbaren Inhalte optimiert wird. Was aber, wenn der Benutzer nach unten scrollt und dort noch Einträge auftauchen, die nicht in die so eingestellte Spalte passen?

Dazu nutzt die Prozedur einen Trick: Sie stellt die Zeilenhöhe mit RowHeight = 1 auf den minimalen Wert ein, sodass alle Zeilen direkt sichtbar sind und dementsprechend mit optimiert werden. Dann durchläuft die Prozedur alle Felder und stellt den Wert von ColumnWidth entsprechend ein. Schließlich wird die Zeilenhöhe mit der Einstellung auf den Wert -1 wieder zurückgesetzt.

Automatisch oder nicht?

Fehlt noch die Eigenschaft OptimizeAutomatically: Diese stellen Sie über die gleichnamige Property Let-Prozedur ein:

Public Property Let OptimizeAutomatically(bol As Boolean)
     m_OptimizeAutomatically = bol
End Property

Damit die automatische Optimierung standardmäßig aktiviert ist, nutzen wir das Initialize-Ereignis der Klasse, um m_OptimizeAutomatically auf den Wert True einzustellen:

Private Sub Class_Initialize()
     m_OptimizeAutomatically = True
End Sub

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Download

Download

Die .zip-Datei enthält folgende Dateien:

SpaltenbreitenOptimierenMitKlasse.mdb

Beispieldateien downloaden

© 2003-2015 André Minhorst Alle Rechte vorbehalten.