Incremental search in a list box

Using RB2012R1 for this project (Although I have Xojo installed).
In a form, I have 2 listboxes in a master-detail configuration.
The master listbox has about 500 entries, and I want to provide the user with some kind of incremental search, but things are not working:

In the CellClick event of the master listbox there is some code to fill the detail listbox with about 4 or 5 items.
Doing so, I face the following problems:

1.) If I want to navigate the master listbox with the arrow keys, keying an arrow key displaces the focus to the detail listbox.
2.) keying a character to position the master listbox, does not change the position of the items.

So, I am thinking in to include a textbox, connected with the master listbox to key some characters and make the listbox to position to the first occurrence of those characters.
In other Windows development environments, I can use SendMessage with LB_SELECTSTRING, LB_GETCURSEL and LB_SETTOPINDEX.
How can I do this in RB ?

I use a listbox with a textfield to search for any entry in the listbox:

[code]Function FindRow(searchString as String, aListbox as Listbox) As integer
//search a file in a listbox
//return rownr when found

dim i,j as Integer
dim FoundAt as Integer

for i = 0 to aListbox .listcount -1
for j = 0 to aListbox.columnCount
if FindWholeWord( aListbox .cell(i,j), searchString) = True then
FoundAt = i
exit
end
next
next
if FoundAt >=0 then
return FoundAt
else
return -1
end if

End Function
[/code]

The FindWholeWord is a Regex…:

Function FindWholeWord(source As string, find As string) As boolean Dim rg as New RegEx Dim myMatch as RegExMatch rg.SearchPattern=find myMatch=rg.search(source) if myMatch <> Nil then return True else return False End if exception err as RegExException MsgBox err.message End Function

Please mind: it positions the listindex on the first occurance of the string it finds.
Though it searches everyrow and every column it is very fast, that is, on my laptop. 500 rows should not be of any problem I guess.

Alexander, not to be nitpicky here, you could shorten your FindRow method a bit as follows:

[code]Function FindRow(searchString as String, aListbox as Listbox) As integer
//search a file in a listbox
//return rownr when found

dim i,j as Integer
dim FoundAt as Integer = -1

for i = 0 to aListbox .listcount -1
for j = 0 to aListbox.columnCount
if FindWholeWord( aListbox .cell(i,j), searchString) = True then
FoundAt = i
exit i
end
next j
next i
return FoundAt

End Function[/code]

Hallo Harrie,

Thanks. This method was a bit quick and dirty. I think I found it at the old RB forum.

Pedro:
I use the following in a text field (with a help tag that states "Enter to Find, Enter again to Find Next) to find/find next just using the enter key. The textfield name is txt find. Escape clears/resets the text and variables.

[code]In the keydown event of a text field

Static found as integer
static beenhere as Boolean
dim I as integer

if key = chr(13) then

  if beenhere = false then found = 0

  for I = found  to listbox.ListCount -1
    	
if instrtrue(listbox.cell(i,0), txtfind.text) then

      	listbox.ScrollPosition = i
         listboxt.listindex = i
      	found = i + 1
      	beenhere = true

      	Return true
      	//exit for
    end if
 	 next
end if

if key = chr(27) then
txtFind.text = “”
beenhere = false
return True
end if

In a global module

InstrTrue
Params: start as integer =0,stringtosearch as String, stringtofind as String
Return Boolean

// returns a Boolean because rb insists on returning an integer
//this way you can write "if instrtrue(“Boolean”,“boo”) if all you want to know is:
//does “Boolean” contain “boo”

dim a as integer
a = instr(start,stringtosearch,stringtofind)
if a > 0 then return true else return false

[/code]

Thanks to all for your suggestions, finally, I shortened the routine because i do not need regex, so my code is

  Dim iK As Integer
  Dim iPos As Integer
  Dim sFind As String
  Dim iLen As Integer
  
  sFind = txtSearch.Text
  iLen = Len(sFind)

  For iK = 0 To lstMaster.ListCount - 1
    iPos = Instr(Left(lstMaster.List(iK), iLen), sFind)
    If iPos > 0 Then
      If iK > 3 Then
        lstMaster.ScrollPosition = iK-3
      End If
      lstMaster.ListIndex = iK
      FillDetailListbox (lstMaster.CellTag(iK, 0))
      Exit For
    End If
  Next 

[code]I use this on 65500 row listbox

select case Asc(Key)

case …

case 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,54,55,56,57
’ ho premuto un tasto A-Z, a-z, 0-9
’ ricerca incrementale
if self.colonna <> self.Listbox1.SortedColumn then
self.incrementale = “”
Drawheader()

end if 

if self.Listbox1.SortedColumn = -1 then 
  ' se non ho impostato la sortcolumn 
  self.incrementale = ""
  Drawheader()
  
  return true
  exit Function
else
  self.colonna = self.Listbox1.SortedColumn
  self.incrementale = self.incrementale + key
  self.Listbox1.Heading(self.colonna) = self.incrementale
  dim cursoreriga as integer '  la riga dove sto lavorando
  dim larghezzaricerca as Integer
  larghezzaricerca = len(self.incrementale)
  for cursoreriga = 0 to self.Listbox1.ListCount - 1
    if self.incrementale = left(self.Listbox1.cell(cursoreriga, self.colonna),larghezzaricerca) then 
      self.Listbox1.ListIndex = cursoreriga
      return true
      exit Function
    end if
  next
  
end if

end select
return true[/code]

Drawheader() a function for redraw column header

search for a specific column ( add a window property or listbox property )
search for match string in all cell…!

Dim iK As Integer
Dim iPos As Integer
Dim sFind As String
Dim iLen As Integer

sFind = txtBuscar.Text
iLen = Len(sFind)

if iLen = 0 then
lstGastos.ListIndex = -1
return
end if

For iK = 0 To lstGastos.ListCount - 1
iPos = Instr( Left( lstGastos.Cell( iK, self.colActual ), lstGastos.Cell(ik,self.colActual).Len ), sFind)
If iPos > 0 Then
If iK > 3 Then
lstGastos.ScrollPosition = iK-3
End If
lstGastos.ListIndex = iK
Exit For
End If
Next

Pedro, thanks for sharing your final solution.

I am brand new to Xojo, and I too am looking for a good incremental search method for a Xojo ListBox, one that will hopefully work as quick as the web-based JavaScript and JQuery methods.

May I ask how your final method worked out for you? Find anything better?
Would you mind sharing your Xojo Project that uses this method?

Thanks.

self.colActual is unknow ?

self.colActual is unknow ?

It will be an integer property of the window, which is used to specifiy which column is being searched

Yes.

I set it to 0 (in a ListBox with only one column) and run the code. It displays only the first found entry, as is. :wink:

Remember, this code (conversation) have 7 years old…