donwiss
Board Regular
- Joined
- Jul 5, 2020
- Messages
- 63
- Platform
- Windows
I needed a macro to sort my ListBoxes. So I developed the following from various web sources:
I found the simplest way to implement sorting was with small sort buttons. One click for the user. Simple code for me. Bolding the sorted column title gives a simple visible indication. The ListBox is filled from Access.
The sort buttons are labels with these settings:
.Caption = "Sort"
.Height = 15
.SpecialEffect = fmSpecialEffectRaised
.TextAlign = fmTextAlignCenter
.Width = 24
Optional:
.TabStop = True
I have this code behind:
Now that has saving the sort choice to the user's Registry. All my sort choices and form locations are saved in the Registry. I recommend storing settings in the Registry. You can remove the code in my macro here.
I mentioned above filling the ListBox from Access. I have this function for that:
VBA Code:
Sub SortListBox(myListBox As Control, Optional SortCol As Integer)
' sorts a MultiColumn ListBox. always does two sorts:
' when sort is on column 0, then secondary sort is on column 1
' when sort is on a column other than 0, then secondary sort is on column 0
' if sort column VarType is Date, then sort is descending
' if sort column VarType is String, then test is case insensitive
' SortCol defaults to 0, or first column
Dim LbList As Variant
' store the list in a working array for sorting
LbList = myListBox.List
' do the sort
LbList = BubbleSort(LbList, SortCol)
' when first column, we secondary sort on second column
If SortCol = 0 Then
LbList = BubbleSort(LbList, 1, 0)
' when primary sort was another column, we secondary sort on first column
Else
LbList = BubbleSort(LbList, 0, SortCol)
End If
' remove the contents of the ListBox (needed?)
myListBox.Clear
' repopulate with the sorted list
myListBox.List = LbList
End Sub
VBA Code:
Function BubbleSort(myArray As Variant, SortCol As Integer, Optional Key1 As Variant) As Variant
' written as a sub macro to SortListBox, but can also be used stand alone. e.g. before initial fill in of ListBox
' turn on Key1 for second sort (for third sort would have to test against three keys)
Dim FirstSort, isDate, isString, test As Boolean
Dim i, j, k As Integer
Dim temp As Variant
FirstSort = IsMissing(Key1)
If FirstSort Then Key1 = 0
' when strings, we make case insensitive
isString = VarType(myArray(0, SortCol)) = vbString
' when dates, sort is descending
isDate = VarType(myArray(0, SortCol)) = vbDate
' bubble sort the array
For i = 0 To UBound(myArray, 1) - 1
For j = i + 1 To UBound(myArray, 1)
' when we are doing a secondary sort, only sort needed rows. For 3 add: And myArray(i, Key2) = myArray(j, Key2)
If FirstSort Or myArray(i, Key1) = myArray(j, Key1) Then
' capitalize when strings
If isString Then
test = UCase(myArray(i, SortCol)) > UCase(myArray(j, SortCol))
' descending when dates
ElseIf isDate Then
test = myArray(i, SortCol) < myArray(j, SortCol)
' numbers
Else
test = myArray(i, SortCol) > myArray(j, SortCol)
End If
' swap values in all columns
If test Then
For k = 0 To UBound(myArray, 2)
temp = myArray(i, k)
myArray(i, k) = myArray(j, k)
myArray(j, k) = temp
Next k
End If
End If
Next j
Next i
BubbleSort = myArray
End Function
I found the simplest way to implement sorting was with small sort buttons. One click for the user. Simple code for me. Bolding the sorted column title gives a simple visible indication. The ListBox is filled from Access.
The sort buttons are labels with these settings:
.Caption = "Sort"
.Height = 15
.SpecialEffect = fmSpecialEffectRaised
.TextAlign = fmTextAlignCenter
.Width = 24
Optional:
.TabStop = True
I have this code behind:
VBA Code:
Private Sub bnSort1_Click()
SortListBox ListBox1, 0
SortLabel 1
End Sub
VBA Code:
Private Sub SortLabel(ColOn As Integer, Optional SkipSave As Boolean)
' set SkipSave to True when initializing form
Dim i As Integer
For i = 1 To 5
Me.Controls("Label" & i).Font.Bold = i = ColOn
Next i
' save the changed new order
If SkipSave Then Exit Sub
SaveRegKeyValue "PriceSweepDisplay5", ColOn
End Sub
Now that has saving the sort choice to the user's Registry. All my sort choices and form locations are saved in the Registry. I recommend storing settings in the Registry. You can remove the code in my macro here.
I mentioned above filling the ListBox from Access. I have this function for that:
VBA Code:
Function FlipData(Mat As Variant) As Variant
' transposes data in a matrix. useful when retrieving from Access
If IsEmpty(Mat) Then Exit Function
Dim i, j, NumI, NumJ As Integer
Dim data As Variant
NumI = UBound(Mat, 1)
NumJ = UBound(Mat, 2)
ReDim data(NumJ, NumI)
For i = 0 To NumI
For j = 0 To NumJ
data(j, i) = Mat(i, j)
Next j
Next i
FlipData = data
End Function