Listbox row location on user typing a la iTunes?

Hi Folks,

Has anyone come up with a method that will allow the row selection of a listbox to update based on user typing in the manner that OS X’s iTunes works that they could share? My current KeyDown efforts are lackluster at best and fail silently at worst.


For those of us who try to avoid iTunes whenever possible, could you describe what you are looking for in another way?

The user types a key/keys and the listbox moves to the first row that matches the character(s) typed. I suspect that a timer is used to catch groups so that ‘f’ and ‘fre’ result in different rows depending on matches.

so a simple autocomplete scenario?

brute force method (might work if your listbox is not huge)
create a textfield to catch the input
in the textchanged event

for i=0 to listbox1.listcount-1
   if left(listbox1.cell(0,i),len(textfield1.text))=textfield1.text then 
   exit for
end if
next i

Maybe store the data to be searched in a dictionary or sorted array. While trapping keys in whatever way, reset a timer mode to 0 then to 1 one after the other. Set the timer period to the period to wait to see if you are going to get another keypress. Do the search when the timer finally gets a chance to fire.

Be aware that as you start getting senile ( like me ) that timer period might have to be extended. :wink:

@Dave S - Thanks - that’s what I initially tried in the KeyDown event. Using a TextField isn’t a good idea because the user has to click the header row and sort to choose which column is used for the search.

@Peter Job - That’s where I was heading in my current tests. I’ll report back this afternoon.

create a subclass of the listbox and attach that code to the keydown event… at some point you have to store a string of what the user has typed to compare to the contents of the listbox…

and for best speed a sorted array would be better than a dictionary (since you are going to have dynamic “keys”), a binary search on an array will be faster than having to scan the dictionary … but in either case it requires you to have two copies of the listbox data… one in the listbox in the order it needs to be shown, and one in either the sorted array or dictionary… and heck if you are going to that extreme, think about an in-memory database and use the LIKE operator

I use two different instances according to my needs:

  1. Detect the first char only:
    //keydown event:
    for i as Integer = 0 to me.ListCount-1
    if left(me.cell(i,0),1) = key then
    me.ListIndex = i
    me.ScrollPosition = i
    Return true
    end if

  2. a few characters

//theSearchable is a property
//listbox’s keydown event:
if timerSearch.mode = 0 then timerSearch.mode = 1
theSearchable = theSearchable + key
return true

Protected Sub getAlpha(theK as string)

dim k as integer = listbox1.SortedColumn
for i as integer = 0 to listbox1.listcount-1
dim s as string = listbox1.cell(i,k)
if left(s, len(theK)) = theK then
listbox1.listindex = i
listbox1.scrollPosition = i
end if
End Sub

//TimerSearch.period = 10
Sub Action()
theSearchable = “”
End Sub

Thanks, @Carlo Rubini your second method is very close to what I’ve ended up with except my timer’s a bit more lenient that 10ms :).

Yes, mine too. It is 1250;I dont know how I wrote 10!
Besides, strings (theSearchable, s as string) are UTF8 encoded since, If I recollect rightly, once upon a time listboxes used to hold their values in a different encoding.

OS X Finder and Windows Explorer works the same: if you type the first(s) letters of a word, the OS select the first item’s name that match.