Filtrowanie ListBox’a część 2

by Marcin on Październik 15, 2007

Pomyślałem sobie, że skoro funkcja filter, o której pisałem, działa szybko, można spróbować odfiltrować z grubsza przy jej pomocy to, co na pewno nie pasuje do podanych kryteriów, a następnie przefiltrować resztę raz jeszcze, dokładniej.

lista_nazwisk2 to przefiltrowana wstępnie funkcją FILTER tablica z nazwiskami

For i = UBound(lista_nazwisk2) To 0 Step -1 ' dla każdego nazwiska w tablicy, zaczynając od ostatniej pozycji

' jeżeli nazwisko nie pasuje do wzorca

  If Not UCase(lista_nazwisk2(i)) Like UCase(Me.TextBox2.Value) & "*" Then

     ' przesuwam wszystkie elementy lezace nizej o jedna pozycje do góry (zastępując niepasujący element)

     For licznik = i To UBound(lista_nazwisk2) - 1

        lista_nazwisk2(licznik) = lista_nazwisk2(licznik + 1)

     Next licznik

     ' i usuwam ostatni element (zmieniam wymiar tablicy)

     ReDim Preserve lista_nazwisk2(UBound(lista_nazwisk2) - 1)

End If

Next i

Na koniec sprawdziłem jeszcze tylko czy takie wstępne filtrowanie ma w ogóle sens. Przecież można po prostu przy pomocy pętli od razu przefiltrować wszystkie nazwiska.

Zmierzyłem czas wykonywania procedury z wstępnym filtrowaniem i bez niego. W przypadku listy 5600 nazwisk czas wylistowania z filtrowaniem wstępnym, po wpisaniu przypadkowej litery, wyniósł 0,05 sekundy. Bez wstępnego przefiltrowania – 0,22. Nieco bardziej konkretnie – dla litery „s” (511 nazwisk zaczynających się tą literą na mojej liście) czas wykonania wyniósł odpowiednio 0,38 i 1,23 sekundy. Prawie sekunda róznicy. Niby niewiele, ale w przypadku odświeżania ListBox’a jest to opóźnienie bardziej niż zauważalne. W przypadku róznych liter są to oczywiście różne wyniki (w zależności od tego jak wielka jest wstępnie odfiltrowana tablica) zawsze jednak jest to różnica na korzyść wstępnego przefiltrowania. Różnica ta oczywiście maleje w miarę wpisywania kolejnych liter i zawężania listy.

Na koniec, tytułem eksperymentu, zmierzyłem jeszcze czas wykonania innej procedury, która po prostu wstawia listę bezpośrednio do ListBox’a, a następnie usuwa z niego wszystkie elementy, które nie pasują do wzorca.


Private Sub TextBox1_Change()

Dim lista_nazwisk As Variant

Dim licznik As IntegerWith Worksheets("Nazwiska") ' nazwiska znajdują się w skoroszycie "Nazwiska"

   ' pobieram do tablicy listę nazwisk z arkusza.

   lista_nazwisk = Range(Range("C4"), Range("C4").End(xlDown)).Value

End With

Me.ListBox1.List = lista_nazwisk ' wypelniam ListBox’a wartościami

For licznik = Me.ListBox1.ListCount - 1 To 0 Step -1

   If Not UCase(Me.ListBox1.List(licznik)) Like UCase(Me.TextBox3.Value) & "*" Then

      Me.ListBox1.RemoveItem licznik

   End If

Next licznik

End Sub

W tym przypadku, dla wspomnianej już litery „s” czas odfiltrowania listy wyniósł 0,62 sekundy.

Przygotowując jednak projekt dla jednego z klientów chciałem przefiltrować listbox’a z kilkoma kolumnami. Wkrótce postaram się napisać o tym jaką metodę filtrowania wybrałem do projektu, dlaczego oraz jaki jest efekt.

Marcin

{ 3 comments… read them below or add one }

Karolina Styczeń 19, 2010 o 10:05 am

Jest już gdzieś to filtrowanie listboxa z kilkoma kolumnami?? Bardzo mnie interesuje jak to zrobiłeś :)

Maciej Marzec 21, 2010 o 8:38 pm

Rownież czekam niecierpliwie na wspomniane rozwiązanie :)

Maciek Maj 15, 2010 o 2:26 pm

Tez sie nie moge doczekac tego rozwiazania. Mam nadzieje, ze wkrotce sie pojawi!

Leave a Comment