B4J Question List of Types Not Sorting Alphabetically. One does. One does not.

Tim Chapman

Active Member
Licensed User
Longtime User
Please run the attached code and click on the top left combo box under Select Product.
Click on the 146/437-10WBP.
Next, at the bottom left, click on the combo box under Select Part. They are sorted alphabetically.
Next, at the top right, click on the combo box under Big Part List. They are NOT sorted alphabetically.

Both lists are filled with a Type with a Name field.

Any ideas why one sorts and the other does not.

The two subs that do the sorting are highlighted. Line 354 and 360.

The attached code has the parts lists to load when the code starts so you have the same starting point as I do.

B4J code:
Sub Process_Globals
    LogColor("Sub Process_Globals started", 0xFF009901)
    ' These global variables will be declared here
    Private fx As JFX
    Private XUI As XUI
    Private MainForm As Form
    Private Dialog As DialogsX
 
    Type BigPart(Name As String, VendorPartNumber As String, Vendor As String, Products As List)
    Type Part(Name As String, Qty As String, UOM As String)
    
    ' Using a Map instead of a List to store Manufactured Items
    Private ManufacturedItems As Map  ' Key is product name, Value is List of Part items

    Private DefaultFolder As String
    
    ' UI Elements
    Private btnAddProduct As Button
    Private cmbProducts As ComboBox
    Private lblProduct As Label
    Private txtNewProduct As TextField
    
    ' Add Part
    Private btnAddPart As Button
    Private lblAddPart As Label
    Private txtPartName As TextField
    Private txtPartQty As TextField
    Private txtQtyUOM As TextField
    
    ' Parts List ComboBox
    Private lblPartList As Label
    Private cmbPartList As ComboBox
    
    ' Big Parts List
    Private cmbBigPartList As ComboBox
    Private lblBigPartList As Label

    Private BigPartsList As List
    Private ctxMenu As ContextMenu
    Private btnAddArrow As Button

    ' Panes
    Private PaneArrow As Pane
    Private PaneMain As Pane
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    LogColor("Sub AppStart started", 0xFF009901)
    ' Set the main form
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")  ' Load the layout file
    MainForm.Show
    MainForm.Title = "Arrow Antennas"
    
    Dim ps As Screen = fx.PrimaryScreen
    MainForm.SetWindowSizeLimits(ps.MaxX, ps.MaxY, ps.MaxX, ps.MaxY)
    MainForm.WindowLeft = 0
    MainForm.WindowTop = 0
    
    PaneArrow.Visible = False
    PaneMain.Visible = True
    
    ' Initialize data structures
    ManufacturedItems.Initialize
    BigPartsList.Initialize
    Dialog.Initialize
    
    lblAddPart.Text = "Select Product First"
    
    DefaultFolder = File.DirApp  ' The Objects Folder where the App is located.
    
    If File.Exists(DefaultFolder, "Products.txt") Then
        LoadProducts
    End If

    If File.Exists(DefaultFolder, "BigPartsList.txt") Then
        LoadBigPartsList
    Else If File.Exists(DefaultFolder, "Products.txt") Then
        FillBigPartsList
    End If
    
    LogColor("Sub AppStart finished", 0xFFFF7100) 
End Sub

' ADD PRODUCT
Sub btnAddProduct_MouseClicked(EventData As MouseEvent)
    LogColor("Sub btnAddProduct_Click started", 0xFF009901)
    ' Add new item to ComboBox
    Dim NewProduct As String = txtNewProduct.Text
    If NewProduct <> "" Then
        cmbProducts.Items.Add(NewProduct)  ' Add the new product name to the cmbProduct combobox.
        txtNewProduct.Text = ""  ' Clear the TextField
        cmbProducts.SelectedIndex = cmbProducts.Items.Size - 1  ' Select the new product in the combobox so it will show.
        
        Dim PartsList As List  ' of Type Part
        PartsList.Initialize
        
        ' Add a new entry in the ManufacturedItems map for the new Product
        ManufacturedItems.Put(NewProduct, PartsList)  ' Presently the PartsList is empty.
    Else
        XUI.MsgboxAsync("Please enter a product to add.", "PEBKAC Error")
    End If
    LogColor("Sub btnAddProduct_Click finished", 0xFFFF7100)
End Sub

Private Sub btnAddArrow_MouseClicked(EventData As MouseEvent)
    LogColor("Sub btnAddArrow_Click started", 0xFF009901)
    
    Dim NewProduct As String = txtNewProduct.Text
    Dim BPFlag As Boolean = False
    Dim DuplexerFlag As Boolean = False
    Dim NumberOfDrivenElements As Byte
    Dim NumberOfElements As String
    Dim NumberOfSplits As String
    Dim Frequency(3) As String
    Dim Part As Part
    
    If NewProduct <> "" Then
        Dim parts() As String = Regex.Split("-", NewProduct)
        Frequency(1) = parts(0)
        Dim Suffix As String = parts(1)
        
        If Suffix.Contains("BP") Then
            BPFlag = True
            NumberOfElements = Suffix.SubString2(0, Suffix.Length-3)
            Log("BP = True")
            Log("Number Of Elements = " & NumberOfElements)
        End If
        
        If Suffix.Contains("W") Then
            DuplexerFlag = True
            NumberOfElements = Suffix.SubString2(0, Suffix.Length-3)
            Log("Duplexer = True")
            Log("Number Of Elements = " & NumberOfElements)
        End If
        
        If NewProduct.Contains("/") Then
            NumberOfDrivenElements = 2
            Dim parts() As String = Regex.Split("/", Frequency(1))
            Frequency(1) = parts(0)
            Frequency(2) = parts(1)
            Dim NumberOfElementsPerSide(3) As String
            For X = 1 To NumberOfDrivenElements
                NumberOfElementsPerSide(X) = ShowDialog("Number of Elements", "Enter Number of Elements for " & Frequency(X) & " MHz side of antenna.", "", "")
            Next
        Else
            NumberOfDrivenElements = 1
        End If
        
        ' Prepare the PartsList
        Dim PartsList As List  ' of Type Part
        PartsList.Initialize
        
        ' Initialize and add parts to PartsList
        Dim Part As Part
        Part.Initialize
        Part.Name = "Red Element Cap"
        Part.Qty = NumberOfElements * 2
        Part.UOM = "each"
        PartsList.Add(Part)

        Dim Part As Part
        Part.Initialize
        Part.Name = "Threaded Stud"
        Part.Qty = NumberOfElements
        Part.UOM = "each"
        PartsList.Add(Part)
        
        Dim Part As Part
        Part.Initialize
        Part.Name = "Boom 3/4"""
        Part.Qty = ShowDialog("Boom Length", "Enter Boom Length in decimal inches.", "", "")
        Part.UOM = "inches"
        PartsList.Add(Part)
        
        Dim Part As Part
        Part.Initialize
        Part.Name = "Insert"
        Part.Qty = NumberOfElements * 2
        Part.UOM = "each"
        PartsList.Add(Part)
        
        Dim Part As Part
        Part.Initialize
        Part.Name = "Connector Block"
        Part.Qty = NumberOfDrivenElements
        Part.UOM = "each"
        PartsList.Add(Part)
        
        Dim Part As Part
        Part.Initialize
        Part.Name = "Arrow Shorting Bar" '***Has 2 parts and a screw.
        Part.Qty = NumberOfDrivenElements
        Part.UOM = "each"
        PartsList.Add(Part)
        
        Dim Part As Part
        Part.Initialize
        Part.Name = "Boom End Cap 3/4"""
        Part.Qty = IIf(DuplexerFlag = True,1,2)
        Part.UOM = "each"
        PartsList.Add(Part)
        
        If DuplexerFlag = True Then
            Dim Part As Part
            Part.Initialize
            Part.Name = "Duplexer"
            Part.Qty = 1
            Part.UOM = "each"
            PartsList.Add(Part)
        End If
        
        If BPFlag = True Then '***Some booms have more than one split.
            
            NumberOfSplits = ShowDialog("Splits", "Enter Number of Splits", "", "")
            
            Dim Part As Part
            Part.Initialize
            Part.Name = "Copper Pipe Size M"
            Part.Qty = 3 * NumberOfSplits
            Part.UOM = "inches"
            PartsList.Add(Part)
            
            Dim Part As Part
            Part.Initialize
            Part.Name = "Pop Rivet"
            Part.Qty = 1 * NumberOfSplits
            Part.UOM = "each"
            PartsList.Add(Part)
        End If
        
        For X = 1 To NumberOfDrivenElements
            
            Dim Part As Part
            Part.Initialize
            Part.Name = "Teflon" & ", " & Frequency(X) & "-" & NumberOfElementsPerSide(X)
            Part.Qty = ShowDialog("Teflon ", "Enter Teflon length for " & Frequency(X) & " MHz in decimal inches.", "", "")
            Part.UOM = "inches"
            PartsList.Add(Part)
            
            Dim Part As Part
            Part.Initialize
            Part.Name = "Copper Wire 16 gauge" & ", " & Frequency(X) & "-" & NumberOfElementsPerSide(X)
            Part.Qty = ShowDialog("Copper Wire", "Enter Copper Wire length for " & Frequency(X) & " MHz in decimal inches.", "", "")
            Part.UOM = "inches"
            PartsList.Add(Part)
            
            Dim Part As Part
            Part.Initialize
            Part.Name = "Aluminum Gamma Match Tube" & ", " & Frequency(X) & "-" & NumberOfElementsPerSide(X)
            Part.Qty = ShowDialog("Gamma Match Tube", "Enter Gamma Match Tube length for " & Frequency(X) & " MHz in decimal inches.", "", "")
            Part.UOM = "inches"
            PartsList.Add(Part)
            
            Dim Part As Part
            Part.Initialize
            Part.Name = "Reflector Element" & Frequency(X) & "-" & NumberOfElementsPerSide(X)
            Part.Qty = ShowDialog("Reflector Element", "Enter Reflector Element Length in decimal inches for " & Frequency(X) & " MHz", "", "")
            Part.UOM = "inches"
            PartsList.Add(Part)

            Dim Part As Part
            Part.Initialize
            Part.Name = "Driven Element" & Frequency(X) & "-" & NumberOfElementsPerSide(X)
            Part.Qty = ShowDialog("Driven Element", "Enter Driven Element Length in decimal inches " & Frequency(X) & " MHz", "", "")
            Part.UOM = "inches"
            PartsList.Add(Part)
            
            For Y = 1 To NumberOfElementsPerSide(X) -2
                Dim Part As Part
                Part.Initialize
                Part.Name = "Director Element # " & Y & ", " & Frequency(X) & "-" & NumberOfElementsPerSide(X)
                Part.Qty = ShowDialog("Director Element " & Y, "Enter Director Element " & Y & " Length in decimal inches for " & Frequency(X) & " MHz", "", "")
                Part.UOM = "inches"
                PartsList.Add(Part)
            Next
        Next

        ' Add new product and its parts to the ManufacturedItems map
        ManufacturedItems.Put(NewProduct, PartsList)
        cmbProducts.Items.Add(NewProduct)  ' Add the new product name to the cmbProduct combobox.
        txtNewProduct.Text = ""  ' Clear the TextField
        cmbProducts.SelectedIndex = cmbProducts.Items.Size - 1  ' Select the new product in the combobox so it will show.
        
        ShowPartsList(PartsList)  ' Display parts list in the UI
        UpdateBigPartsList
        SaveProducts  ' Save the ManufacturedItems List
    Else
        XUI.MsgboxAsync("Please enter a product to add.", "PEBKAC Error")
    End If
    LogColor("Sub btnAddArrow_Click finished", 0xFFFF7100)
End Sub

Private Sub ShowDialog(Title As String, Header As String, Label As String, Text As String) As String
    LogColor("Sub ShowDialog started", 0xFF009901)
    Dim content As String = Dialog.TextInputDialog(Title, Header, Label, Text)
    If content = "" Then content = Dialog.TextInputDialog(Title, Header, Label, Text)
    LogColor("Sub ShowDialog finished", 0xFFFF7100)
    Return content
End Sub

Private Sub cmbProducts_SelectedIndexChanged(Index As Int, Value As Object)
    LogColor("Sub cmbProducts_SelectedIndexChanged started", 0xFF009901)
    ' User selected a product from the list
    Dim selectedItem As String = cmbProducts.Items.Get(cmbProducts.SelectedIndex)
    lblAddPart.Text = "Add part for " & selectedItem  ' Modify the Add Part label

    ' Retrieve the PartsList for the selected product
    If ManufacturedItems.ContainsKey(selectedItem) Then
        Dim PartsList As List = ManufacturedItems.Get(selectedItem)
        ShowPartsList(PartsList)  ' Display parts list for this product
    End If
    LogColor("Sub cmbProducts_SelectedIndexChanged finished", 0xFFFF7100)
End Sub

' ADD PART
Private Sub btnAddPart_MouseClicked(EventData As MouseEvent)
    LogColor("Sub btnAddPart_Click started", 0xFF009901)
    
    If cmbProducts.SelectedIndex <> -1 Then
        Dim Part As Part
        Part.Initialize
            
        Part.Name = txtPartName.Text
        Part.Qty = txtPartQty.Text
        Part.UOM = txtQtyUOM.Text
            
        If Part.Name <> "" And Part.Qty <> "" And Part.UOM <> "" Then
            Dim ProductName As String = cmbProducts.Items.Get(cmbProducts.SelectedIndex)
            If ManufacturedItems.ContainsKey(ProductName) Then
                Dim PartsList As List = ManufacturedItems.Get(ProductName)
                PartsList.Add(Part)  ' Add the new part to the existing parts list
                ShowPartsList(PartsList)  ' Update UI

                SaveProducts  ' Save the ManufacturedItems List
                
                'Update Big Parts List with one part.
                Dim NewPart As BigPart
                NewPart.Name = Part.Name
                Dim Products As List
                Products.Initialize
                Products.Add(Part.Name)
                NewPart.Products = Products
                BigPartsList.Add(NewPart)
            End If
        End If
    End If



    LogColor("Sub btnAddPart_Click finished", 0xFFFF7100)
End Sub

Private Sub ShowPartsList(PartsList As List)
    LogColor("Sub ShowPartsList started", 0xFF009901)
    PartsList.SortType("Name",True)
    cmbPartList.Items.Clear  ' Clear the combo box before adding
    For Each Part As Part In PartsList
        cmbPartList.Items.Add(Part.Name)  ' Add to combo box
    Next
    LogColor("Sub ShowPartsList finished", 0xFFFF7100)
End Sub

' LOAD & SAVE LISTS
Sub LoadProducts
    LogColor("Sub LoadProducts started", 0xFF009901)
    Dim raf As RandomAccessFile
    raf.Initialize2(DefaultFolder, "Products.txt", False, False)
    ManufacturedItems = raf.ReadB4XObject(0)  ' Load the ManufacturedItems as a Map

    ' Populate products in the combo box from the map keys
    For Each ProductName As String In ManufacturedItems.Keys
        cmbProducts.Items.Add(ProductName)
    Next
    LogColor("Sub LoadProducts finished", 0xFFFF7100)
End Sub

Sub SaveProducts
    LogColor("Sub SaveProducts started", 0xFF009901)
    Dim raf As RandomAccessFile
    raf.Initialize2(DefaultFolder, "Products.txt", False, False)
    raf.WriteB4XObject(ManufacturedItems, 0)  ' Save the ManufacturedItems map as a B4XObject
    LogColor("Sub SaveProducts finished", 0xFFFF7100)
End Sub

Sub LoadBigPartsList
    LogColor("Sub LoadBigPartsList started", 0xFF009901)

    'Read all lines from the file into a list
    'ManufacturedItems = File.ReadList(DefaultFolder, "Products.txt")
    
    Dim raf As RandomAccessFile
    raf.Initialize2(DefaultFolder, "BigPartsList.txt", False, False)
    BigPartsList = raf.ReadB4XObject(0)
    
    'Iterate over each line in the list
    For Each BigPart As BigPart In BigPartsList
        cmbBigPartList.Items.Add(BigPart.Name)
    Next
    LogColor("Sub LoadBigPartsList finished", 0xFFFF7100)
End Sub

Sub SaveBigPartsList
    LogColor("Sub SaveBigPartsList started", 0xFF009901)
    'Write the ManufacturedItems list to the Products.txt file in the DefaultFolder
    
    Dim raf As RandomAccessFile
    raf.Initialize2(DefaultFolder, "BigPartsList.txt", False, False)
    raf.WriteB4XObject(BigPartsList, 0)
    
    'File.WriteList(DefaultFolder, "Products.txt", ManufacturedItems)
    LogColor("Sub SaveBigPartsList finished", 0xFFFF7100)
End Sub

Sub FillBigPartsList
    LogColor("Sub FillBigPartsList started", 0xFF009901)
    Dim NewPartFoundInBigPartListFlag As Boolean = False

    For Each ProductName As String In ManufacturedItems.Keys
            Dim PartsList As List =    ManufacturedItems.Get(ProductName) 'Get the PartsList from the current product map.
            
            For Each Part As Part In PartsList 'Loop through the parts in the product.
                If BigPartsList.Size > 0 Then
                    For Each BigPart As BigPart In BigPartsList 'Loop through the parts in the Big Parts list.
                        If BigPart.Name = Part.Name Then NewPartFoundInBigPartListFlag = True 'Set the flag to show there is a match.
                    Next
                    If NewPartFoundInBigPartListFlag = False Then
                        Dim NewPart As BigPart
                        NewPart.Name = Part.Name
                        Dim Products As List
                        Products.Initialize
                        Products.Add(ProductName)
                        NewPart.Products = Products
                        BigPartsList.Add(NewPart)
                    End If
                Else
                    Dim NewPart As BigPart
                    NewPart.Initialize
                    NewPart.Name = Part.Name
                    Dim Products As List
                    Products.Initialize
                    Products.Add(ProductName)
                    NewPart.Products = Products
                    BigPartsList.Add(NewPart)
                End If
            Next
    Next
    
    SaveBigPartsList
    ShowBigPartsList
    LogColor("Sub FillBigPartsList finished", 0xFFFF7100)
End Sub

Private Sub cmbBigPartList_SelectedIndexChanged(Index As Int, Value As Object)
    LogColor("Sub cmbBigPartList_SelectedIndexChanged started", 0xFF009901)
    AddContextMenuTocmbBigPartsList
    LogColor("Sub cmbBigPartList_SelectedIndexChanged finished", 0xFFFF7100)
End Sub

Private Sub ShowBigPartsList
    LogColor("Sub ShowBigPartsList started", 0xFF009901)
    ' Show this Big parts list in the cmbBigPartList combo box.
    
    BigPartsList.SortType("Name",True)
    
    cmbBigPartList.Items.Clear  ' Clear the combo box before adding to it.
    For Each BigPart As BigPart In BigPartsList
        cmbBigPartList.Items.Add(BigPart.Name)
    Next
    LogColor("Sub ShowBigPartsList finished", 0xFFFF7100)
End Sub

Private Sub AddContextMenuTocmbBigPartsList
    LogColor("Sub AddContextMenuTocmbBigPartsList started", 0xFF009901)
    
    'Add Context Menu for Big Parts List
    Dim SubMenuList As List
    SubMenuList.Initialize
    
    ctxMenu.Initialize("")
    Dim MT() As String = Array As String("Part Vendor", "Part Cost")
    For i = 0 To MT.Length - 1
        Dim Mi As MenuItem
        Mi.Initialize(MT(i),"ctxm")
        ctxMenu.MenuItems.Add(Mi)
    Next

    'Add a sub menu

    Dim SubMenu As Menu
    SubMenu.Initialize("Products this part is used on", "")
 
    'Make a list (SubMenuList) of each product that the part selected in the cmbBigPartList is used in.
    
    For Each ProductName As String In ManufacturedItems.Keys
            Dim PartsList As List =    ManufacturedItems.Get(ProductName) 'Get the PartsList from the current product map.
            For Each Part As Part In PartsList
                If Part.Name = cmbBigPartList.Items.Get(cmbBigPartList.SelectedIndex) Then
                    SubMenuList.Add(ProductName)
                End If
            Next
    Next
    
    'Add the list (SubMenuList) of products the part is used in to the submenu for the part selected in cmbBigPartList.
    For Each ProductName As String In SubMenuList
        Dim Mi As MenuItem
        Mi.Initialize(ProductName,"ctxm")
        SubMenu.MenuItems.Add(Mi)
    Next
 
    ctxMenu.MenuItems.Add(SubMenu)
    cmbBigPartList.As(JavaObject).RunMethod("setContextMenu",Array(ctxMenu))
    LogColor("Sub AddContextMenuTocmbBigPartsList finished", 0xFFFF7100)
End Sub

'BIG PARTS LIST
Private Sub UpdateBigPartsList
    LogColor("Sub UpdateBigPartsList started", 0xFF009901)
    ' Clear the current BigPartsList before updating
    BigPartsList.Clear

    ' Iterate over each product name in ManufacturedItems
    For Each ProductName As String In ManufacturedItems.Keys
        
        ' Get the corresponding PartsList for this product
        Dim PartsList As List = ManufacturedItems.Get(ProductName)

        ' Iterate over each Part in the PartsList
        For Each Part As Part In PartsList
            Dim NewPart As BigPart
            NewPart.Initialize
            NewPart.Name = Part.Name
            
            Dim Products As List
            Products.Initialize
            Products.Add(ProductName) ' Add the product name the part belongs to
            NewPart.Products = Products
            
            ' Check for duplication in BigPartsList
            Dim found As Boolean = False
            For Each bigPart As BigPart In BigPartsList
                If bigPart.Name = NewPart.Name Then
                    found = True
                    Exit
                End If
            Next
            
            ' If the part is not found in BigPartsList, add it
            If Not(found) Then
                BigPartsList.Add(NewPart)
            End If
        Next
    Next

    ' Save the updated BigPartsList
    SaveBigPartsList
    ' Show the updated Big Parts List in the UI
    ShowBigPartsList
    LogColor("Sub UpdateBigPartsList finished", 0xFFFF7100)
End Sub
 

Attachments

  • Arrow.zip
    9.3 KB · Views: 26

PaulMeuris

Active Member
Licensed User
The BigPartsList was not filled with a sorted list of BigPart names.
Check out the hightlighted code lines.
TIP: also use the log to show the contents of variables, lists and maps.
LoadBigPartsList:
Sub LoadBigPartsList
    LogColor("Sub LoadBigPartsList started", 0xFF009901)

    'Read all lines from the file into a list
    'ManufacturedItems = File.ReadList(DefaultFolder, "Products.txt")
   
    Dim raf As RandomAccessFile
    raf.Initialize2(DefaultFolder, "BigPartsList.txt", False, False)
    BigPartsList = raf.ReadB4XObject(0)
    'Iterate over each line in the list
    Dim blst As List
    blst.Initialize
    For Each BigPart As BigPart In BigPartsList
'        cmbBigPartList.Items.Add(BigPart.Name)
        Log(BigPart.Name)
        blst.Add(BigPart.Name)
    Next
    BigPartsList.Clear
    BigPartsList = blst
    BigPartsList.Sort(True)
    cmbBigPartList.Items.AddAll(BigPartsList)
    Log("sorted bigpartslist: " & BigPartsList)
    LogColor("Sub LoadBigPartsList finished", 0xFFFF7100)
End Sub
1730798867625.png
 
Upvote 0

Tim Chapman

Active Member
Licensed User
Longtime User
You have made BigPartsList a flat list and removed all they type objects from it. That won't work.
I found that sorting the list when it is loaded from the file using SortType worked.
 
Upvote 0

PaulMeuris

Active Member
Licensed User
In the ShowPartsList subroutine you already used the SortType method for the Partslist (line 356).
In the BigPartsList subroutine you didn't use the SortType method for the BigPartsList (after line 394).
Any ideas why one sorts and the other does not.
This answers your question.
 
Upvote 0
Top