Symptomen
- De gebruiker wil een keuzelijst (Listbox) achteraf, dus bijvoorbeeld na plaatsing op een formulier, alsnog opnieuw sorteren. Dat kan niet via een relatief eenvoudige methode, zoals een eigenschap van het besturingselement.
- Eventueel moet achteraf ook op meerdere sleutels kunnen worden gesorteerd.
Remedie
Op de een of andere manier is het achteraf sorteren van een lijstelement zoals een keuzelijst in een Access-formulier geen eenvoudige taak. Men zou verwachten dat de inhoud van de Listbox met een instelling van een eigenschap als .Sort of .OrderBy te regelen zou zijn, zoals bij (sub)formulieren het geval is, maar dat is voor het besturingselement Listbox niet mogelijk. Vaak wordt een lijstelement gebruikt om de resultaten van een bepaalde selectie of filtering via andere elementen te vullen of om er bepaalde waarden aan toe te kennen. In beide gevallen zou de sortering vooraf geen problemen opleveren, want de rijbron (Rowsource) die de inhoud gaat bepalen is op dat moment nog wel gevoelig voor sorteeracties. De SQL-string die u als rijbron gebruikt, kan direct worden voorzien van sortering, eventueel zelfs op meerdere kolommen. Maar als de lijst er eenmaal staat, is sortering achteraf een probleem.
Als de Listbox maar uit één kolom bestaat (dus de sortering op één sleutel moet plaatsvinden), is er de mogelijkheid om de items van de lijst in te lezen in een array, die vervolgens te sorteren in een private sub en de gesorteerde items terug te schrijven in de Listbox. U heeft dan bijvoorbeeld procedures nodig als hieronder (de eerste om de opgehaalde lijstwaarden te verwerken, de tweede om te sorteren):
Private Sub Sorteren_Click() Dim i As Long Sorteer MijnArray, Laagste(MijnArray), Hoogste(MijnArray) lstLijst.Clear For i = 1 To Hoogste(MijnArray) lstLijst.AddItem MijnArray(i) Next i End Sub Private Sub Sorteer(strArray() As String, intLaagste As Integer, intHoogste As Integer) Dim strWissel As String, strTemp As String Dim intLaagsteTemp As Integer, intHoogsteTemp As Integer intLaagsteTemp = intLaagste intHoogsteTemp = intHoogste strWissel = strArray((intLaagste + intHoogste) \ 2) While (intLaagsteTemp <= intHoogsteTemp) While (strArray(intLaagsteTemp) < strWissel And intLaagsteTemp < intHoogste) intLaagsteTemp = intLaagsteTemp + 1 Wend While (strWissel < strArray(intHoogsteTemp) And intHoogsteTemp > intLaagste) intHoogsteTemp = intHoogsteTemp - 1 Wend If intLaagsteTemp < intHoogsteTemp Then strTemp = strArray(intLaagsteTemp) strArray(intLaagsteTemp) = strArray(intHoogsteTemp) strArray(intHoogsteTemp) = strTemp End If If intLaagsteTemp <= intHoogsteTemp Then intLaagsteTemp = intLaagsteTemp + 1 intHoogsteTemp = intHoogsteTemp - 1 End If Wend 'deze functie blijft zichzelf aanroepen totdat alles in de goede volgorde staat If (intLaagste < intHoogsteTemp) Then QuickSort strArray, intLaagste, intHoogsteTemp If (intLaagsteTemp < intHoogste) Then QuickSort strArray, intLaagsteTemp, intHoogste End Sub
Maar als de Listbox meerdere kolommen beslaat en op elke kolom gesorteerd moet kunnen worden (eventueel ook nog oplopend of aflopend, en op meerdere kolommen) wordt het wel wat problematischer. Een mogelijke oplossing die veel Access-VBA-programmeurs gebruiken om op één van de kolommen te sorteren, is de volgende:
- Plaats knopjes voor sorteren boven elke kolom, met een tekst erop of eventueel met een afbeelding van een pijltje die aangeeft in welke ‘richting’ u sorteert (op- of aflopend).
- Haal in de VBA-code achter de gebeurtenis ‘Bij klikken’ van de knopjes in een variabele de SQL-string op van de Rowsource van het lijstelement (bijvoorbeeld met tmpSQLstr = Me.lstLijst.Rowsource) en voeg aan de tekenreeks de gewenste kolomsortering toe met een string als ORDER BY <veldnaam>. Zorg ervoor dat u de puntkomma (;) eerst van die string afhaalt en voeg die er na de toevoeging van de ORDER BY-string weer aan toe.
- Ken de SQL-string opnieuw toe aan het lijstelement (bijvoorbeeld met Me.lstLijst.Rowsouce = tmpSQLstr).
Maar als de sortering achteraf ook nog over meerdere kolommen (met meerdere sleutels dus) moet gebeuren – denk aan de telefoonboeksortering op achternaam, en binnen achternaam op straatnaam, vervolgens op voorletters, et cetera – dan zult u nog andere methoden moeten bedenken én programmeren. Zo heeft u dan in plaats van twee knopjes boven een kolom voor op- of aflopend sorteren, nog andere besturingselementen nodig om de volgorde van de diverse te sorteren kolommen aan te geven. In dat geval is een extra dialoogvenster (formulier) waarin u de sortering opnieuw regelt voor de Listbox waarschijnlijk handiger. Maar al geeft dat een overzichtelijker beeld in het formulier met de Listbox, dat wordt toch een behoorlijke programmeerklus.