B4J Question Jumping to an item in a sorted listview by pressing key of its first letter

kostefar

Active Member
Licensed User
Longtime User
Dear All,

I have a listview with pure text items where these are sorted alphabetically.
Is it possible that when I´m in this listview, that I can skip down to items starting with "O", for instance, by just pressing the O key on my keyboard, like in for instance Windows Explorer?

As far as I can see, there´s no such funtionality in the standard listview. Of course it could be done in one of the events, but I was thinking that there´s a supersimple way that I have not thought of?
 

kostefar

Active Member
Licensed User
Longtime User
You can use a TextField behind of listview then could use Text Changed event.

It´s something like that I had in mind, but didn´t know that I´d need to have a textview as well. I do see though now when looking at the members of listview that it´d be necessary. Good idea, although I was hoping for a simpler solution but I think that´s the best that can be done.

Thanks a mill!
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
You can use reflection as a listview doesn't normally want input, to capture the key and scroll to the relevant item.
small example (uses Reflection and JavaObject libraries)
B4X:
Sub Process_Globals
	Private fx As JFX
	Private MainForm As Form
	Dim lv As ListView
	Dim ref As Reflector
End Sub

Sub AppStart (Form1 As Form, Args() As String)
	MainForm = Form1
	'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
	MainForm.Show
	lv.Initialize("lv")
	lv.Items.AddAll(Array("a","b","c","d","e","f","g"))
	MainForm.RootPane.AddNode(lv,10,10,-1,50) ' short height to force scrollbars
	ref.Target=lv
	ref.AddEventHandler("search","javafx.scene.input.KeyEvent.KEY_TYPED")
End Sub

Sub search_Event(e As Event)
	Dim jo As JavaObject = e
	Dim searchChar As String = jo.RunMethod("getCharacter",Null)
	Log(searchChar)
	For t = 0 To lv.Items.Size -1
		Dim ss As String = lv.Items.Get(t)
		If searchChar.EqualsIgnoreCase(ss.CharAt(0)) Then lv.ScrollTo(t)
	Next
	e.Consume
End Sub
 
Upvote 0

Eme Fibonacci

Well-Known Member
Licensed User
Longtime User
I was testing. it's better to use TextArea. It does not generate error when using RequestFocus often

B4X:
Sub ListView1_MouseClicked (EventData As MouseEvent)
    
    TextArea1.RequestFocus
    'TextField1.RequestFocus
    
End Sub
 
Upvote 0

Eme Fibonacci

Well-Known Member
Licensed User
Longtime User
You can use reflection as a listview doesn't normally want input, to capture the key and scroll to the relevant item.
small example (uses Reflection and JavaObject libraries)
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Dim lv As ListView
    Dim ref As Reflector
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    lv.Initialize("lv")
    lv.Items.AddAll(Array("a","b","c","d","e","f","g"))
    MainForm.RootPane.AddNode(lv,10,10,-1,50) ' short height to force scrollbars
    ref.Target=lv
    ref.AddEventHandler("search","javafx.scene.input.KeyEvent.KEY_TYPED")
End Sub

Sub search_Event(e As Event)
    Dim jo As JavaObject = e
    Dim searchChar As String = jo.RunMethod("getCharacter",Null)
    Log(searchChar)
    For t = 0 To lv.Items.Size -1
        Dim ss As String = lv.Items.Get(t)
        If searchChar.EqualsIgnoreCase(ss.CharAt(0)) Then lv.ScrollTo(t)
    Next
    e.Consume
End Sub

Perfect!
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Made a minor change to the code to allow for missing items and can now use 'enter' key to select the value in list
If your listview items are a,b,c,d,f,g,h and you enter 'e' as the search, it will now return 'd' as the closest below the missing one. Also you can use arrow keys up/down and hit enter to select the item.
B4X:
Sub search_Event(e As Event)
    Dim jo As JavaObject = e
    Dim searchChar As String = jo.RunMethod("getCharacter",Null)
    If Asc(searchChar) = 13 Then ' enter triggers on Action event
        lv_Action(lv.selectedindex)
        Return
    End If
    Log("looking for first "&searchChar)
    For t = 0 To lv.Items.Size -1
        Dim ss As String = lv.Items.Get(t)
        ss = ss.CharAt(0)
        If ss.CompareTo(searchChar) <= 0 Then
            lv.ScrollTo(t)
            lv.SelectedIndex = t
        Else
            Return
        End If
    Next
    e.Consume
End Sub

Sub lv_Action(Index As Int)
    Log("item : "&lv.Items.Get(Index)) ' do something with this entry
End Sub
 
Upvote 0

kostefar

Active Member
Licensed User
Longtime User
Made a minor change to the code to allow for missing items and can now use 'enter' key to select the value in list
If your listview items are a,b,c,d,f,g,h and you enter 'e' as the search, it will now return 'd' as the closest below the missing one. Also you can use arrow keys up/down and hit enter to select the item.
B4X:
Sub search_Event(e As Event)
    Dim jo As JavaObject = e
    Dim searchChar As String = jo.RunMethod("getCharacter",Null)
    If Asc(searchChar) = 13 Then ' enter triggers on Action event
        lv_Action(lv.selectedindex)
        Return
    End If
    Log("looking for first "&searchChar)
    For t = 0 To lv.Items.Size -1
        Dim ss As String = lv.Items.Get(t)
        ss = ss.CharAt(0)
        If ss.CompareTo(searchChar) <= 0 Then
            lv.ScrollTo(t)
            lv.SelectedIndex = t
        Else
            Return
        End If
    Next
    e.Consume
End Sub

Sub lv_Action(Index As Int)
    Log("item : "&lv.Items.Get(Index)) ' do something with this entry
End Sub

Wow, what an easter gift! You deserve to be more than a well-known member :)
Thanks so much!
Does it also let you type more than one letter (fast) so that searching for a specific item can be done quicker? Like, if you type "FO" it´ll go straight to "FORD" instead of "FIAT"?

I assume not, and it´s all fine how it is of course, just wondering.

Gotta try it in a few!
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Upvote 0

kostefar

Active Member
Licensed User
Longtime User
Made a minor change to the code to allow for missing items and can now use 'enter' key to select the value in list
If your listview items are a,b,c,d,f,g,h and you enter 'e' as the search, it will now return 'd' as the closest below the missing one. Also you can use arrow keys up/down and hit enter to select the item.
B4X:
Sub search_Event(e As Event)
    Dim jo As JavaObject = e
    Dim searchChar As String = jo.RunMethod("getCharacter",Null)
    If Asc(searchChar) = 13 Then ' enter triggers on Action event
        lv_Action(lv.selectedindex)
        Return
    End If
    Log("looking for first "&searchChar)
    For t = 0 To lv.Items.Size -1
        Dim ss As String = lv.Items.Get(t)
        ss = ss.CharAt(0)
        If ss.CompareTo(searchChar) <= 0 Then
            lv.ScrollTo(t)
            lv.SelectedIndex = t
        Else
            Return
        End If
    Next
    e.Consume
End Sub

Sub lv_Action(Index As Int)
    Log("item : "&lv.Items.Get(Index)) ' do something with this entry
End Sub

Ok, up and running with a few modifications. Did so it takes into account if more items start with the same letter (current code would select the last item with this letter, always) and that it´ll proceed to the next item starting with the same letter if same key is pressed again:


B4X:
Sub search_Event(e As Event)
    Dim jo As JavaObject = e
    Dim searchChar As String = jo.RunMethod("getCharacter",Null)
 
    Dim startitem As Int = 0
    If lv.SelectedIndex > -1 Then
        Dim currentfirst As String = lv.Items.Get(lv.SelectedIndex)

           If (Asc(searchChar.ToUpperCase)>= Asc(currentfirst.ToUpperCase.CharAt(0))) Then startitem = lv.SelectedIndex+1
    End If
 
    For t = startitem To lv.Items.Size -1
        Dim ss As String = lv.Items.Get(t)
        If searchChar.EqualsIgnoreCase(ss.CharAt(0)) Then
    
            lv.SelectedIndex = t
            lv.ScrollTo(t)
            Exit
        End If
    Next
    e.Consume
End Sub

Edit: Oops, I was actually using the first version of the code without the enter functionality. Anyway, the above still won´t hurt unless the list always have only one entry starting with each letter - in my case there were multiple.
 
Last edited:
Upvote 0
Top