How to sort a combobox using VBA (1 Viewer)

AlliCarr

Member
Local time
Today, 13:48
Joined
Feb 19, 2024
Messages
35
Hi

I have a combobox on a reporting form which uses VBA in the On Load event to pull the values from the reports that I have in the database. Although the reports always show alphabetically from a - z in the navigation pane, they don't show in alphabetical order in the combobox. Is there any way I can update the code so that the list is always alphabetical from a - z so it's easier for users to find the report they're looking for?

Here's the code:
Code:
Private Sub Form_Load()
On Error GoTo ErrorHandler

'Pulls list of reports for report combo box and updates when new reports added
    Dim NewValList As String
    NewValList = ""
    
    Dim Obj As AccessObject
    
        For Each Obj In CurrentProject.AllReports
            If Right(Obj.Name, 3) <> "Sub" Then
            NewValList = NewValList + Chr(34) + Obj.Name + Chr(34) + ";"
            End If
        Next Obj
    
    Me!ReportCombo.RowSourceType = "Value List"
    Me!ReportCombo.RowSource = NewValList
    Me!ReportCombo.value = Me!ReportCombo.ItemData(0)
    

Exit Sub

ErrorHandler:
    Dim msg As String
    msg = Err.Number & ":" & Err.Description
    MsgBox msg
    
End Sub

I have tried searching online for an answer but can't seem to find anything that I can make work so hopefully someone will be able to point me in the right direction.
 

Uncle Gizmo

Nifty Access Guy
Staff member
Local time
Today, 13:48
Joined
Jul 9, 2003
Messages
16,478
I would be inclined to collect the report names into a table and then fill the combo box with a suitable query.

The alternative way sticking with code would be as follows:-

Code:
Private Sub Form_Load()
    On Error GoTo ErrorHandler

    'Pulls list of reports for report combo box and updates when new reports added
    Dim ReportList As New Collection
    Dim Obj As AccessObject
    Dim i As Integer
    Dim SortedList() As String
    Dim NewValList As String
    
    'Collecting report names
    For Each Obj In CurrentProject.AllReports
        If Right(Obj.Name, 3) <> "Sub" Then
            ReportList.Add Obj.Name
        End If
    Next Obj

    'Sorting report names
    ReDim SortedList(ReportList.Count - 1)
    For i = 1 To ReportList.Count
        SortedList(i - 1) = ReportList(i)
    Next i
    Call QuickSort(SortedList, LBound(SortedList), UBound(SortedList))

    'Creating the value list
    NewValList = ""
    For i = LBound(SortedList) To UBound(SortedList)
        NewValList = NewValList & Chr(34) & SortedList(i) & Chr(34) & ";"
    Next i

    Me!ReportCombo.RowSourceType = "Value List"
    Me!ReportCombo.RowSource = Left(NewValList, Len(NewValList) - 1) ' Remove the last semicolon
    Me!ReportCombo.value = Me!ReportCombo.ItemData(0)

Exit Sub

ErrorHandler:
    Dim msg As String
    msg = Err.Number & ": " & Err.Description
    MsgBox msg

End Sub

'QuickSort function to sort the array
Sub QuickSort(arr() As String, ByVal first As Long, ByVal last As Long)
    Dim v As String
    Dim i As Long, j As Long
    Dim temp As String

    i = first
    j = last
    v = arr((first + last) \ 2)

    Do While i <= j
        Do While arr(i) < v
            i = i + 1
        Loop
        Do While arr(j) > v
            j = j - 1
        Loop
        If i <= j Then
            temp = arr(i)
            arr(i) = arr(j)
            arr(j) = temp
            i = i + 1
            j = j - 1
        End If
    Loop

    If first < j Then QuickSort arr, first, j
    If i < last Then QuickSort arr, i, last
End Sub
 

Uncle Gizmo

Nifty Access Guy
Staff member
Local time
Today, 13:48
Joined
Jul 9, 2003
Messages
16,478
This section would look tidier in a with block:-

Code:
Me!ReportCombo.RowSourceType = "Value List"
Me!ReportCombo.RowSource = Left(NewValList, Len(NewValList) - 1) ' Remove the last semicolon
Me!ReportCombo.value = Me!ReportCombo.ItemData(0)
 

Uncle Gizmo

Nifty Access Guy
Staff member
Local time
Today, 13:48
Joined
Jul 9, 2003
Messages
16,478
Code:
With Me!ReportCombo
    .RowSourceType = "Value List"
    .RowSource = Left(NewValList, Len(NewValList) - 1) ' Remove the last semicolon
    .value = Me!ReportCombo.ItemData(0)
End With
 

AlliCarr

Member
Local time
Today, 13:48
Joined
Feb 19, 2024
Messages
35
Thanks @Uncle Gizmo for your response and the feedback.

I like the idea of adding the report names into a table and using a query for the combobox as this seems a little cleaner. Would I need to add in the report names manually every time I create a new report or can this be done automatically?
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 20:48
Joined
May 7, 2009
Messages
19,293
also, you can try this.
add a Module and on that module, paste this code to sort your array:
Code:
' https://stackoverflow.com/questions/152319/vba-array-sort-function
'
Public Function sorted_array(ByRef InputArray As Variant) As Variant

Dim arr As Object
Dim element As Variant

'Creating a array list
Set arr = CreateObject("System.Collections.ArrayList")


'number
'InputArray = Array(6, 5, 3, 4, 2, 1)

' adding the elements in the array to array_list
For Each element In InputArray
    arr.Add element
Next

'sorting happens
arr.Sort

'Converting ArrayList to an array
'so now a sorted array of elements is stored in the array sorted_array.

sorted_array = arr.toarray
End Function

now change your code to this:

Code:
Private Sub Form_Load()
On Error GoTo ErrorHandler

'Pulls list of reports for report combo box and updates when new reports added
    Dim NewValList As String
    ' arnelgp
    Dim arr() As String, cnt As Integer, i As Integer
    ReDim arr(500)
    
    NewValList = ""
    
    Dim Obj As AccessObject
    
        For Each Obj In CurrentProject.AllReports
            If Right(Obj.Name, 3) <> "Sub" Then
                cnt = cnt + 1
                arr(cnt - 1) = Obj.Name
            End If
        Next Obj
        
        If cnt <> 0 Then
            ReDim Preserve arr(cnt - 1)
            arr = sorted_array(arr)
            
            For i = 0 To cnt
                NewValList = NewValList + Chr(34) + arr(i) + Chr(34) + ";"
            Next
            
            
    
            Me!ReportCombo.RowSourceType = "Value List"
            Me!ReportCombo.RowSource = NewValList
            Me!ReportCombo.Value = Me!ReportCombo.ItemData(0)
        
        End If

Exit Sub

ErrorHandler:
    Dim msg As String
    msg = Err.Number & ":" & Err.Description
    MsgBox msg
    
End Sub
 

theDBguy

I’m here to help
Staff member
Local time
Today, 05:48
Joined
Oct 29, 2018
Messages
21,694
Perhaps you could also consider pulling the names of your reports from the MSysObjects table, so you can sort it. I forgot the flag value but something like:
SQL:
select [name] from msysobjects where flag=xxx
Sent from phone...
 

Uncle Gizmo

Nifty Access Guy
Staff member
Local time
Today, 13:48
Joined
Jul 9, 2003
Messages
16,478
Db Guys idea is a good one. You might have to show your system tables.

(MSysObjects)

Then you could use code something like this:-

Code:
Private Sub Form_Load()
    On Error GoTo ErrorHandler

    'Set the RowSource to the query that selects and sorts report names
    Me!ReportCombo.RowSourceType = "Table/Query"
    Me!ReportCombo.RowSource = "SELECT MSysObjects.Name FROM MSysObjects WHERE MSysObjects.Type = -32764 ORDER BY MSysObjects.Name;"
    Me!ReportCombo.value = Me!ReportCombo.ItemData(0)

Exit Sub

ErrorHandler:
    Dim msg As String
    msg = Err.Number & ": " & Err.Description
    MsgBox msg

End Sub
 

Uncle Gizmo

Nifty Access Guy
Staff member
Local time
Today, 13:48
Joined
Jul 9, 2003
Messages
16,478
In a With Block

Code:
With Me!ReportCombo
    .RowSourceType = "Table/Query"
    .RowSource = "SELECT MSysObjects.Name FROM MSysObjects WHERE MSysObjects.Type = -32764 ORDER BY MSysObjects.Name;"
    .value = Me!ReportCombo.ItemData(0)
End With
 

CJ_London

Super Moderator
Staff member
Local time
Today, 13:48
Joined
Feb 19, 2013
Messages
16,786
I was going to suggest the sql route but you don’t need to make msysobjects visible to use it

I would add one further refinement to the criteria-

[name] not like ‘*sub’
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 08:48
Joined
May 21, 2018
Messages
8,751
@AlliCarr,
The original recommendations of creating and maintaining a table has some advantages. Most people do not have clean descriptive report names, you might. I never do since they are usually prefixed with "rpt" and have no spaces. You may want to display an clear, descriptive name, and it is nice to also store a long description. So you then could have a combo with the nice to read name (ReportVisibleName) and hide the ReportName. You can also show the description in the pull down.

TblReports
ReportNameReportVisibleNameReportDescription
rptDeptAccountsUser Accounts (Grouped by Department)Report contains active email accounts grouped by Departments.
rptAccountTypesUser Accounts (Grouped by Type)Report contains active email accounts grouped by account type and grouped by Departments.
 

Gasman

Enthusiastic Amateur
Local time
Today, 13:48
Joined
Sep 21, 2011
Messages
14,739
I had a table tblObject that held info that I would use to run them

1719842853835.png


1719842915976.png
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 08:48
Joined
May 21, 2018
Messages
8,751
However if not using a sorted table here is a simpler way to add items to a combo sorted.


Code:
Private Sub Command2_Click()
  Dim rpt As Access.AccessObject
  Dim idx As Integer
  For Each rpt In CurrentProject.AllReports
    If Me.cmboReports.ListCount = 0 Then
      Me.cmboReports.AddItem rpt.Name
    Else
      For idx = 0 To Me.cmboReports.ListCount - 1
        If rpt.Name < Me.cmboReports.ItemData(idx) Then
          Me.cmboReports.AddItem rpt.Name, idx
          Exit For
        End If
      Next idx
      If rpt.Name >= Me.cmboReports.ItemData(cmboReports.ListCount - 1) Then Me.cmboReports.AddItem rpt.Name
    End If
  Next rpt
End Sub
When you add a value to the combo simply add the item at the correct location.
 

CJ_London

Super Moderator
Staff member
Local time
Today, 13:48
Joined
Feb 19, 2013
Messages
16,786
Perhaps not as flexible as a separate table but I use a simple function to add back spaces and remove 'rpt'. Wouldn't work for your TWMFee for example where the alias is 'TWM fees to be invoiced'.
 

Users who are viewing this thread

Top Bottom