Home > Artikel > Ausgabe 7/2012 > Kombinations- und Listenfelder per Callback füllen

Kombinations- und Listenfelder per Callback füllen

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Es gibt verschiedene Arten, Kombinations- und Listenfelder mit Daten zu füllen: Sie können diese an Tabellen oder Abfragen binden, einfach mit einer Wertliste füllen oder die Namen der Felder einer Tabelle darin anzeigen. Es gibt jedoch noch eine weitgehend unbekannte Methode, die Nachteile der übrigen Möglichkeiten ausbügelt, aber auch etwas aufwendiger zu implementieren ist. Dabei kommt eine sogenannte Callback-Funktion zum Einsatz, welche die anzuzeigenden Daten zum Kombinationsfeld hinzufügt.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1207_KombinationsfeldCallback.mdb.

Kombinationsfelder und Listenfelder füllen

Der Optimalfall beim Füllen eines Kombinationsfeldes ist das Vorhandensein einer Tabelle oder Abfrage als Datenherkunft. In diesem Fall behalten Sie den Wert Tabelle/Abfrage für die Eigenschaft Herkunfts­typ bei.

Dies ist jedoch nicht immer gegeben: Wenn Sie beispielsweise eine Liste aller in einem Verzeichnis enthaltenen Dateien in einem Kombinationsfeld anzeigen wollen, liegen die Daten zunächst nicht in einer Tabelle vor. Nun gibt es die Möglichkeit, die Daten einfach in Form einer Wertliste aneinanderzureihen.

Dazu fügen Sie alle Dateinamen durch Semikola voneinander getrennt zu einer Zeichenkette zusammen, stellen die Eigenschaft Herkunftsart des Kombinations­feldes auf Wertliste ein und weisen die Zei­chen­kette per VBA der Eigenschaft RowSource zu. Dies hat allerdings den Nachteil, dass die Wertliste eines Kombinationsfeldes nicht beliebig lang sein darf – genau genommen sind es weniger als 40.000. Welche Anzahl genau möglich ist, können Sie mit einem kleinen Testformular ermitteln. Dieses finden Sie in der Beispieldatenbank unter dem Namen frmLangeWertliste. Beim Laden löst das Formular die folgende Prozedur aus:

Private Sub Form_Load()

     Dim l As Long

     For l = 1 To 100000

         On Error Resume Next

         Me!cboLangeWertliste.RowSource = _

             String(l, "a")

         If Not Err.Number = 0 Then

             MsgBox "Maximal " & l & " Zeichen."

             Exit Sub

         End If

     Next l

End Sub

Die Prozedur fügt schlicht und einfach eine immer längere Zeichenkette für die Eigenschaft Wertliste ein – bis dies irgendwann einen Fehler auslöst. Auf dem Testsystem lieferte dies beispielsweise eine zulässige Länge von 32.751 Zeichen. Übrigens: Unter älteren Access-Versionen war die Anzahl der Zeichen auf 2.048 festgelegt – dort war der Einsatz von Callback-Funktionen noch wesentlich öfter gefragt.

Wenn Sie nun den Inhalt von Verzeichnissen mit vielen Dateien darstellen möchten, kann dies einen Fehler auslösen, wenn die Anzahl der erlaubten Zeichen für die Eigenschaft RowSource überschritten wird.

Liste per Callback-Funktion füllen

Die in diesem Artikel vorgestellte Funktion verwendet eine weitere Alternative, bei der statt eines der verfügbaren Werte Tabelle/Abfrage, Wertliste oder Feldliste einfach der Name einer VBA-Funktion als Wert der Eigenschaft Herkunftsart angegeben wird. Die Angabe eines Wertes für die Eigenschaft Datensatzherkunft ist in diesem Fall nicht nötig.

Die verwendete Callback-Funktion hat einen speziellen Aufbau, der wie folgt aussieht:

Function DateienEinlesen(ctl As Control, _

         lngID As Long, lngRow As Long, _

         lngColumn As Long, intCode As Integer) _

         As Variant

     Select Case intCode

         Case acLBInitialize

             DateienEinlesen = True

         Case acLBOpen

             DateienEinlesen = Timer

         Case acLBGetRowCount

             DateienEinlesen = 1

         Case acLBGetColumnCount

             DateienEinlesen = 1

         Case acLBGetColumnWidth

             DateienEinlesen = -1

         Case acLBGetValue

             DateienEinlesen = "Test"

         Case acLBGetFormat

             DateienEinlesen = Null

         Case Else

             Debug.Print intCode

     End Select

End Function

Dies wirkt auf den ersten Blick etwas unübersichtlich, was sich aber gleich noch ändern wird – zu Ungunsten der Übersicht, denn die obige Variante enthält nur die einfachste Variante der Prozedur, die lediglich einen einzigen Wert in das Ziel-Listenfeld schreibt. Schauen wir uns jedoch zunächst den groben Aufbau an.

Die Funktion wird mehrfach aufgerufen und soll dabei verschiedene Anweisungen ausführen. Diese Anweisungen tragen Sie unter den entsprechenden Verzweigungen der Select Case-Bedingung ein. Welcher Teil der Select Case-Bedingung ausgeführt wird, entscheidet der beim Aufruf übergebene Wert für den Parameter intCode. Dieser kann einen Zahlenwert annehmen, der einer der folgenden Konstanten entspricht:

  • acLBInitialize: Dieser Wert für intCode wird beim ersten Aufruf der Callback-Funktion übergeben. Hier wird geprüft, ob das Kombinations- oder Listenfeld überhaupt mit dieser Funktion gefüllt werden soll. Falls ja, muss der Wert True als Rückgabewert der Funktion festgelegt werden.
  • acLBOpen: Beim Aufruf der Funktion mit dem Wert acLBOpen für den Parameter intCode erwartet Access eine Zahl als Rückgabewert, die das Steuerelement, von dem aus die Callback-Funktion aufgerufen wurde, eindeutig identifiziert. Hintergrund ist, das man ja theoretisch mehrere Steuerelemente mit der gleichen Callbackfunktion ausstatten kann. Wenn sichergestellt ist, dass nur ein Steuerelement diese Funktion als Wert für die Eigenschaft Herkunftsart verwendet, können Sie hier einfach den Wert 1 als Funktionswert angeben. Anderenfalls geben Sie das Ergebnis der Funktion Timer zurück, welche die Zeit in Millisekunden berechnet – dies geht nur schief, wenn die Funktion zweimal in der gleichen Millisekunde aufgerufen wird, was unwahrscheinlich ist.
  • acLBGetRowCount: Dieser Aufruf der Funktion soll die Anzahl der zu füllenden Zeilen ermitteln. Dies ist der geeignete Ort, um die anzuzeigenden Daten zusammenzustellen.
  • acLBGetColumnCount: Dieser Funktionsaufruf erwartet die Übergabe der Anzahl der zu füllenden Spalten.
  • acLBGetColumnWidth: Dieser Funktionsaufruf erwartet die Übergabe der Breiten der zu füllenden Spalten.
  • acLBGetValue: Die Callback-Funktion wird für jedes anzuzeigende Elemente einmal mit dem Wert acLBGetValue für den Parameter intCode aufgerufen. Die Anzahl der Elemente ergibt sich aus dem Produkt aus Zeilen- und Spaltenzahl. Welche Zeile und Spalte gerade abgefragt wird, können Sie den weiteren Parametern lngRow und lngColumn entnehmen.
  • acLBGetFormat: Auch der Aufruf mit diesem Parameterwert erfolgt für jedes anzuzeigende Element einmal. Hier können Sie die Formatierung der Listeneinträge vornehmen (standardmäßig -1).
  • acLBClose, acLBEnd: Diese beiden Parameter werden in weiteren Aufrufen der Callback-Funktion nach dem Füllen des Steuerelements übergeben. Damit können Sie beispielsweise den Zeitpunkt erfassen, zu dem das Steuerelement komplett gefüllt ist.

Wann wird die Callback-Funktion aufgerufen?

Wenn Sie experimentell ermitteln möchten, wann welcher Wert für den Parameter intCode übergeben wird, fügen Sie einfach für jeden Zweig der Select Case-Anweisung eine Anweisung wie die folgenden ein:

Case acLBInitialize

     Debug.Print "acLBInitialize"

     DateienEinlesen = True

Case acLBOpen

     Debug.Print "acLBOpen"

DateienEinlesen = Timer

Sie können dem Direktfenster dann die Reihenfolge der Aufrufe entnehmen. Auf diese Weise finden Sie auch leicht heraus, dass die Aufrufe mit den beiden Parametern acLBGetValue und acLBGetFormat nicht nur beim ersten Füllen des Kombinations- oder Listenfeldes erfolgen, sondern auch zu weiteren Gelegenheiten – beispielsweise, wenn das Formular den Fokus erhält, wenn Sie auf einen der Einträge im Steuerelement klicken oder wenn Sie im Falle eines Listenfeldes die Bildlaufleiste betätigen.

Im Falle eines Kombinationfeldes werden die Elemente übrigens erst beim ersten Aufklappen angelegt. Dies ändert sich auch nicht, wenn Sie das Kombinationsfeld gleich beim Öffnen des Formulars aktualisieren (mit Me!.Requery).

Beispielanwendung

Nun benötigen wir ein passendes Beispiel, um ein Kombinations- oder Listenfeld mithilfe einer Callback-Funktion mit Daten zu füllen. Um die Vorgehensweise für ein- und mehrspaltige Darstellungen zu erläutern, verwenden wir gleich zwei Beispiele. Im ersten soll ein Kombinationsfeld mit den Namen aller Formulare der aktuellen Datenbank geöffnet werden, im zweiten ein Listenfeld mit den Dateinamen eines ausgewählten Verzeichnisses und deren Dateigröße.

Formularliste

Das Formular frmCallback_KombiFormulare soll alle Formularnamen der aktuellen Datenbank zur Auswahl anbieten. Dazu fügen Sie diesem zunächst ein Kombinationsfeld namens cboFormulare hinzu. Stellen Sie für die Eigenschaft Datensatzherkunft den Wert FormulareEinlesen ein (siehe Bild 1) und legen Sie die Callback-Funktion FormulareEinlesen im Klassenmodul des Formulars an. Gegebenenfalls müssen Sie zunächst noch ein Klassenmodul erzeugen – dies erledigen Sie durch Einstellen der Eigenschaft Hat Modul auf den Wert Ja.

Einstellen der Callback-Funktion für ein Kombinationsfeld

Bild 1: Einstellen der Callback-Funktion für ein Kombinationsfeld

Die Callback-Funktion sieht wie in Listing 1 aus. Die Funktion gibt beim ersten Aufruf zunächst den Wert True als Funktionswert zurück, damit die Funktion mit den übrigen Parameterwerten aufgerufen wird.

Function FormulareEinlesen(ctl As Control, lngID As Long, lngRow As Long, lngColumn As Long, _

         intCode As Integer) As Variant

     Select Case intCode

         Case acLBInitialize

             FormulareEinlesen = True

         Case acLBOpen

             FormulareEinlesen = 1

         Case acLBGetRowCount

             FormulareEinlesen = CurrentProject.AllForms.Count

         Case acLBGetColumnCount

             FormulareEinlesen = 1

         Case acLBGetColumnWidth

             FormulareEinlesen = -1

         Case acLBGetValue

             FormulareEinlesen = CurrentProject.AllForms.Item(lngRow).Name

         Case acLBGetFormat

             FormulareEinlesen = Null

     End Select

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!