B4J Library [B4X] lmB4XComboBox

lmB4XComboBox is a b4x library (https://www.b4x.com/android/forum/threads/100383/#content).
It works with B4A, B4J and B4i.

It is a modified version of the Erel's original B4XComboBox and allows you to store in it a value for each text item.
Not rarely (mainly handling DB data) you need a ComboBox in which an Item is made of a display value and an associated value, i.e. a "description field" of a table and the relative primary key (usually the classic Integer ID).
Note that the type of the values associated is object, not just Int; this means that you can associate any type of value to each item.

Members added to the original View:

AddItem(Text As String)
- to add a single text item
AddItem2(Text As String, Value As Object) - to add a single item with text and value
GetItems - returns the full list of texts
GetItemText(Index As Int) - returns the text of an item
GetItemValue(Index As Int) - returns the value associated to an item
GetValues - returns all the values associated
RemoveItemByIndex(Index as Int) - removes an item
RemoveItemByText(Text As String) - removes an item
RemoveItemByValue(Value As Object) - removes an item
SetItems2(Texts As List, Values as List) - to set all items with values
SetItemsFromSQLite(...) - to fill the combo from a SQLite table
SetValue(Index as Int, Value as Object) - to set the value of a specific item


B4J Example (project attached):
1.gif


To run the example project, you need to download the Chinook_Sqlite.sqlite database from:
https://www.sqlitetutorial.net/sqlite-sample-database/
(and place it in the files folder, of course).

Version: 2.03 01/16/2023
Fixed: bug in RaiseEvent Sub

Version: 2.02 07/18/2022
Fixed: bugs related to B4I code (read from post #32)

Version: 2.01 06/15/2021
Added: Method SetItems3(Data As Map)

Version: 2.00 03/05/2021
Fixed: a bug in InsertAt (B4A version only).

Version: 1.06 02/11/2021
Changed: SetItemsFromSQLiteSorted method - Added CaseSensitive parameter.

Version: 1.05 02/06/2021
Added: SetItemsFromSQLiteSorted method.

[I was wrong to remove the previous versions of the library, now I don't know how many times it has been downloaded 🤔😊
However I see that so far the example has been downloaded 185 times, so I can guess that]


Version: 1.04 02/03/2021
Added: InsertItemAt and InsertItemAt2 methods.

Version: 1.03 02/03/2021
Fixed a (small) bug.

Version: 1.02 4/25/2020
Ammended B4i errors (reported by @Andrew (Digitwell) ; thanks)
 

Attachments

  • lmB4XComboBox_example.zip
    3.6 KB · Views: 874
  • lmB4XComboBox.b4xlib
    3.4 KB · Views: 516
  • lmB4XComboBox_202.zip
    3.6 KB · Views: 284
  • lmB4XComboBox_203.zip
    3.7 KB · Views: 219
Last edited:

Daniel44

Active Member
Licensed User
Now it would remain to make an example in B4A. It would be very useful too. Any way thank you Lucas
 

Myr0n

Active Member
Licensed User
Longtime User
Greate job.

Here is the b4a example based from b4j example.

In b4a example I needed to change
B4X:
lmcbArtists.SetItemsFromSQLite(modDB.DB, "Artist", "Name", 15, "ArtistID", "Int")
to
B4X:
lmcbArtists.SetItemsFromSQLite(modDB.DB, "Artist", "Name", 15, "ArtistId", "Int")

because in the db "chinook_sqlite.sqlite" is ArtistId and not ArtistID
in b4a is case sensitive.


Also I changed the modDB.bas file to fit with b4a and b4j, I did not test in b4i because my license stopped in version 5.x
B4X:
Public Sub Init
    #if b4j
        DBDir = File.DirApp
    #End If
    #if b4a
        DBDir = File.DirDefaultExternal
    #End If
    DBFileName = "Chinook_Sqlite.sqlite"
    If Not(File.Exists(DBDir, DBFileName)) Then
        File.Copy(File.DirAssets, DBFileName, DBDir, DBFileName)
    End If
    #if b4j
        DB.InitializeSQLite(DBDir, DBFileName, False)
    #End If
    #if b4a
        DB.Initialize(DBDir, DBFileName, False)
    #End If
End Sub


Again good job.

BTW, In the zip file I am not including "Chinook_Sqlite.sqlite" see post #1
 

Attachments

  • B4A-lmB4XComboBox_example.zip
    10.5 KB · Views: 338
  • B4J-lmB4XComboBox_example.zip
    3.5 KB · Views: 323

LucaMs

Expert
Licensed User
Longtime User
because in the db "chinook_sqlite.sqlite" is ArtistId and not ArtistID
in b4a is case sensitive.
This was because I'm used to name the identifier (Primary Key) ID :)

Also I changed the modDB.bas file to fit with b4a and b4j,
That is just a "temporary utility module", not a B4X module to be reused (it was not the centerpiece of the thread).
 

Myr0n

Active Member
Licensed User
Longtime User
This was because I'm used to name the identifier (Primary Key) ID :)


That is just a "temporary utility module", not a B4X module to be reused (it was not the centerpiece of the thread).

You know, I copy & paste everything from your example to b4a example, the rest is apply the logic.
 

LucaMs

Expert
Licensed User
Longtime User
Really very useful library; who knows why I haven't used it in the project I'm developing. Maybe it's because my memory is really poor 😄 :confused: :confused: :confused:

Maybe the author could add functionality and/or improve it, who knows.



[I wonder why the example file has been downloaded more times than the library one; what do they do with the example without the library? Well, mystery]
 

LucaMs

Expert
Licensed User
Longtime User
Maybe the author could add functionality and/or improve it, who knows.
You could add an "InsertAt" method, for example.
Take advantage of a function you have, which binds SQLite data types to B4X data types.
And pass it an open ResultSet, from which to take the "two values" to fill it (a little risky but useful).
 
Last edited:

pliroforikos

Active Member
Licensed User
Dear Lucas
I'm trying to use lmcombobox in B4i project and i'm getting the errors bellow:
Syntax error.
',' expected.
Unknown member: items
Undeclared variable 'cmbbox' is used before it was assigned any value.
I believe that it has to do with lmcombobox library so i opened and had a look inside.


B4X:
Public Sub InsertItemAt(Index As Int, Text As String)
    #If Not(B4A)
        cmbBox.Items.InsertAt(Index, Text)
    #Else
        Dim lstFirst, lstLast As List
        lstFirst.Initialize
        lstLast.Initialize
        For i = 0 To Index - 1
            lstFirst.Add(cmbBox.GetItem(i))
        Next
        For i = Index To cmbBox.Size - 1
            lstLast.Add(cmbBox.GetItem(i))
        Next
        cmbBox.Clear
        For i = 0 To lstFirst.Size - 1
            cmbBox.Add(lstFirst.Get(i))
        Next
        cmbBox.Add(Text)
        For i = 0 To lstLast.Size - 1
            cmbBox.Add(lstLast.Get(i))
        Next
    #End If
    mmapValues.Put(Text, Null)
End Sub

In line 3 i see that you are using cmbBox in non B4A but its not declared in B4i. Maybe there are more errors or i am wrong so please forgive me. :)

[Edit] I also found:

B4X:
Private Sub RaiseEvent
    Dim Index As Int = getSelectedIndex
    If LastSelectedIndex = Index Then Return
    If DelayBeforeChangeEvent > 0 Then
        DelayIndex = DelayIndex + 1
        Dim MyIndex As Int = DelayIndex
        Sleep(DelayBeforeChangeEvent)
        If MyIndex <> DelayIndex Then Return
    End If
    LastSelectedIndex = Index
    If SubExists(mCallBack, mEventName & "_SelectedChanged") Then
        CallSub2(mCallBack, mEventName & "_SelectedChanged", Index)
    End If
    Dim Item As String = GetItemText(Index)
    If SubExists(mCallBack, mEventName & "_SelectedChanged2") Then
        CallSub3(mCallBack, mEventName & "_SelectedChanged2", Item, mmapValues.Get(Item))
    End If
End Sub

1657985271350.png
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Dear Lucas
I'm trying to use lmcombobox in B4i project and i'm getting the errors bellow:

I believe that it has to do with lmcombobox library so i opened and had a look inside.


B4X:
Public Sub InsertItemAt(Index As Int, Text As String)
    #If Not(B4A)
        cmbBox.Items.InsertAt(Index, Text)
    #Else
        Dim lstFirst, lstLast As List
        lstFirst.Initialize
        lstLast.Initialize
        For i = 0 To Index - 1
            lstFirst.Add(cmbBox.GetItem(i))
        Next
        For i = Index To cmbBox.Size - 1
            lstLast.Add(cmbBox.GetItem(i))
        Next
        cmbBox.Clear
        For i = 0 To lstFirst.Size - 1
            cmbBox.Add(lstFirst.Get(i))
        Next
        cmbBox.Add(Text)
        For i = 0 To lstLast.Size - 1
            cmbBox.Add(lstLast.Get(i))
        Next
    #End If
    mmapValues.Put(Text, Null)
End Sub

In line 3 i see that you are using cmbBox in non B4A but its not declared in B4i. Maybe there are more errors or i am wrong so please forgive me. :)

[Edit] I also found:

B4X:
Private Sub RaiseEvent
    Dim Index As Int = getSelectedIndex
    If LastSelectedIndex = Index Then Return
    If DelayBeforeChangeEvent > 0 Then
        DelayIndex = DelayIndex + 1
        Dim MyIndex As Int = DelayIndex
        Sleep(DelayBeforeChangeEvent)
        If MyIndex <> DelayIndex Then Return
    End If
    LastSelectedIndex = Index
    If SubExists(mCallBack, mEventName & "_SelectedChanged") Then
        CallSub2(mCallBack, mEventName & "_SelectedChanged", Index)
    End If
    Dim Item As String = GetItemText(Index)
    If SubExists(mCallBack, mEventName & "_SelectedChanged2") Then
        CallSub3(mCallBack, mEventName & "_SelectedChanged2", Item, mmapValues.Get(Item))
    End If
End Sub

View attachment 131473
"Unfortunately" I don't have B4I, so I couldn't test this library.

Try replacing the Sub InsertItemAt with the following code:
B4X:
' Insert a new text item at the specified Index position (its related value is automatically set to Null).
Public Sub InsertItemAt(Index As Int, Text As String)
    #If B4J
        cmbBox.Items.InsertAt(Index, Text)
    #Else ' B4A or B4I
        Dim lstFirst, lstLast As List
        lstFirst.Initialize
        lstLast.Initialize
        For i = 0 To Index - 1
            #IF B4A THEN
                lstFirst.Add(cmbBox.GetItem(i))
            #ELSE ' B4I
                lstFirst.Add(mItems.Get(i))
            #End If
        Next
        #IF B4A THEN
            For i = Index To cmbBox.Size - 1
                lstLast.Add(cmbBox.GetItem(i))
        #ELSE ' B4I
            For i = Index To mItems.Size - 1
                lstLast.Add(mItems.Get(i))
        #END IF
        Next
        #IF B4A THEN
            cmbBox.Clear
            For i = 0 To lstFirst.Size - 1
                cmbBox.Add(lstFirst.Get(i))
            Next
            cmbBox.Add(Text)
            For i = 0 To lstLast.Size - 1
                cmbBox.Add(lstLast.Get(i))
            Next
        #ELSE ' B4I
            mItems.Clear
            For i = 0 To lstFirst.Size - 1
                mItems.Add(lstFirst.Get(i))
            Next
            mItems.Add(Text)
            For i = 0 To lstLast.Size - 1
                mItems.Add(lstLast.Get(i))
            Next
        #End If
    #End If
    mmapValues.Put(Text, Null)
End Sub
 
Last edited:

pliroforikos

Active Member
Licensed User
"Unfortunately" I don't have B4I, so I couldn't test this library.

Try replacing the Sub InsertItemAt with the following code:
B4X:
' Insert a new text item at the specified Index position (its related value is automatically set to Null).
Public Sub InsertItemAt(Index As Int, Text As String)
    #If B4J
        cmbBox.Items.InsertAt(Index, Text)
    #Else ' B4A or B4I
        Dim lstFirst, lstLast As List
        lstFirst.Initialize
        lstLast.Initialize
        For i = 0 To Index - 1
            #IF B4A THEN
                lstFirst.Add(cmbBox.GetItem(i))
            #ELSE
                lstFirst.Add(mItems.GetItem(i))
            #End If
        Next
        For i = Index To cmbBox.Size - 1
            #IF B4A THEN
                lstLast.Add(cmbBox.GetItem(i))
            #ELSE ' B4I
                lstLast.Add(mItems.GetItem(i))
            #END IF
        Next
        #IF B4A THEN
            cmbBox.Clear
            For i = 0 To lstFirst.Size - 1
                cmbBox.Add(lstFirst.Get(i))
            Next
            cmbBox.Add(Text)
            For i = 0 To lstLast.Size - 1
                cmbBox.Add(lstLast.Get(i))
            Next
        #ELSE ' B4I
            mItems.Clear
            For i = 0 To lstFirst.Size - 1
                mItems.Add(lstFirst.Get(i))
            Next
            mItems.Add(Text)
            For i = 0 To lstLast.Size - 1
                mItems.Add(lstLast.Get(i))
            Next
        #End If
    #End If
    mmapValues.Put(Text, Null)
End Sub
You are still using cmbbox in B4i. Its not declared
 

pliroforikos

Active Member
Licensed User
Thank you for yor help

B4X:
' Insert a new text item at the specified Index position (its related value is automatically set to Null).
Public Sub InsertItemAt(Index As Int, Text As String)
    #If B4J
        cmbBox.Items.InsertAt(Index, Text)
    #Else ' B4A or B4I
        Dim lstFirst, lstLast As List
        lstFirst.Initialize
        lstLast.Initialize
        For i = 0 To Index - 1
            #IF B4A THEN
                lstFirst.Add(cmbBox.GetItem(i))
            #ELSE ' B4I
                lstFirst.Add(mItems.GetItem(i))
            #End If
        Next
        #IF B4A THEN
            For i = Index To cmbBox.Size - 1
                lstLast.Add(cmbBox.GetItem(i))
        #ELSE ' B4I
            For i = Index To mItems.Size - 1
                lstLast.Add(mItems.GetItem(i))
        #END IF
        Next
        #IF B4A THEN
            cmbBox.Clear
            For i = 0 To lstFirst.Size - 1
                cmbBox.Add(lstFirst.Get(i))
            Next
            cmbBox.Add(Text)
            For i = 0 To lstLast.Size - 1
                cmbBox.Add(lstLast.Get(i))
            Next
        #ELSE ' B4I
            mItems.Clear
            For i = 0 To lstFirst.Size - 1
                mItems.Add(lstFirst.Get(i))
            Next
            mItems.Add(Text)
            For i = 0 To lstLast.Size - 1
                mItems.Add(lstLast.Get(i))
            Next
        #End If
    #End If
    mmapValues.Put(Text, Null)
End Sub

Change getItem with get.

I made a small project and combo is working but the _SelectedChanged2 event is not responding. On the other hand _SelectedChanged works as expected.
 

Attachments

  • Project.zip
    12.5 KB · Views: 120

pliroforikos

Active Member
Licensed User
Good morning Lucas. I've made one change to your code:


B4X:
Private Sub RaiseEvent
    Dim Index As Int = getSelectedIndex
    If LastSelectedIndex = Index Then Return
    If DelayBeforeChangeEvent > 0 Then
        DelayIndex = DelayIndex + 1
        Dim MyIndex As Int = DelayIndex
        Sleep(DelayBeforeChangeEvent)
        If MyIndex <> DelayIndex Then Return
    End If
    LastSelectedIndex = Index
#if B4A
    If SubExists(mCallBack, mEventName & "_SelectedChanged") Then
        CallSub2(mCallBack, mEventName & "_SelectedChanged", Index)
    End If
    Dim Item As String = GetItemText(Index)
    If SubExists(mCallBack, mEventName & "_SelectedChanged2") Then
        CallSub3(mCallBack, mEventName & "_SelectedChanged2", Item, mmapValues.Get(Item))
    End If
#else if B4i
    If SubExists(mCallBack, mEventName & "_SelectedChanged",1) Then
        CallSub2(mCallBack, mEventName & "_SelectedChanged", Index)
    End If
    Dim Item As String = GetItemText(Index)
    If SubExists(mCallBack, mEventName & "_SelectedChanged2",2) Then
        CallSub3(mCallBack, mEventName & "_SelectedChanged2", Item, mmapValues.Get(Item))
    End If
#end IF

SubExists needs one more parameter (Number of Arguments). And you have to advice to use iSQL library.

I haven't check all library but _SelectedChanged2 works now. I'm gonna use it in my project and check it.
 

klaus

Expert
Licensed User
Longtime User
Instead of writing different code for B4i, you should use the cross-platform version:
It has the third parameter which is necessary in B4i and ignored in B4A and B4J.
B4X:
If xui.SubExists(mCallBack, mEventName & "_SelectedChanged", 1) Then
Insetad of :
B4X:
If SubExists(mCallBack, mEventName & "_SelectedChanged", 1) Then
 
Top