Sort a ListView by Number or Date (Updated)

By | 2002-06-01

This code allows a ListView control to be sorted by Number or Date without having to use APIs (except to lock the screen)

Original Author: Pete Cozens

Inputs

N/A

Returns

N/A

Side Effects

No known side-effects at this time. Does not mess-up the
ListItems collection like a Custom API-implemented sort.

Code

'****************************************************************
' ListView1_ColumnClick
' Called when a column header is clicked on - sorts the data in
' that column
'----------------------------------------------------------------
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
                  MSComctlLib.ColumnHeader)
  On Error Resume Next
  
  ' Record the starting CPU time (milliseconds since boot-up)
  
  Dim lngStart As Long
  lngStart = GetTickCount
  
  ' Commence sorting
  
  With ListView1
  
    ' Display the hourglass cursor whilst sorting
    
    Dim lngCursor As Long
    lngCursor = .MousePointer
    .MousePointer = vbHourglass
    
    ' Prevent the ListView control from updating on screen -
    ' this is to hide the changes being made to the listitems
    ' and also to speed up the sort
    
    LockWindowUpdate .hWnd
    
    ' Check the data type of the column being sorted,
    ' and act accordingly
    
    Dim l As Long
    Dim strFormat As String
    Dim strData() As String
    
    Dim lngIndex As Long
    lngIndex = ColumnHeader.Index - 1
  
    Select Case UCase$(ColumnHeader.Tag)
    Case "DATE"
    
      ' Sort by date.
      
      strFormat = "YYYYMMDDHhNnSs"
    
      ' Loop through the values in this column. Re-format
      ' the dates so as they can be sorted alphabetically,
      ' having already stored their visible values in the
      ' tag, along with the tag's original value
    
      With .ListItems
        If (lngIndex > 0) Then
          For l = 1 To .Count
            With .Item(l).ListSubItems(lngIndex)
              .Tag = .Text & Chr$(0) & .Tag
              If IsDate(.Text) Then
                .Text = Format(CDate(.Text), _
                          strFormat)
              Else
                .Text = ""
              End If
            End With
          Next l
        Else
          For l = 1 To .Count
            With .Item(l)
              .Tag = .Text & Chr$(0) & .Tag
              If IsDate(.Text) Then
                .Text = Format(CDate(.Text), _
                          strFormat)
              Else
                .Text = ""
              End If
            End With
          Next l
        End If
      End With
      
      ' Sort the list alphabetically by this column
      
      .SortOrder = (.SortOrder + 1) Mod 2
      .SortKey = ColumnHeader.Index - 1
      .Sorted = True
      
      ' Restore the previous values to the 'cells' in this
      ' column of the list from the tags, and also restore
      ' the tags to their original values
      
      With .ListItems
        If (lngIndex > 0) Then
          For l = 1 To .Count
            With .Item(l).ListSubItems(lngIndex)
              strData = Split(.Tag, Chr$(0))
              .Text = strData(0)
              .Tag = strData(1)
            End With
          Next l
        Else
          For l = 1 To .Count
            With .Item(l)
              strData = Split(.Tag, Chr$(0))
              .Text = strData(0)
              .Tag = strData(1)
            End With
          Next l
        End If
      End With
      
    Case "NUMBER"
    
      ' Sort Numerically
    
      strFormat = String(30, "0") & "." & String(30, "0")
    
      ' Loop through the values in this column. Re-format the values so as they
      ' can be sorted alphabetically, having already stored their visible
      ' values in the tag, along with the tag's original value
    
      With .ListItems
        If (lngIndex > 0) Then
          For l = 1 To .Count
            With .Item(l).ListSubItems(lngIndex)
              .Tag = .Text & Chr$(0) & .Tag
              If IsNumeric(.Text) Then
                If CDbl(.Text) >= 0 Then
                  .Text = Format(CDbl(.Text), _
                    strFormat)
                Else
                  .Text = "&" & InvNumber( _
                    Format(0 - CDbl(.Text), _
                    strFormat))
                End If
              Else
                .Text = ""
              End If
            End With
          Next l
        Else
          For l = 1 To .Count
            With .Item(l)
              .Tag = .Text & Chr$(0) & .Tag
              If IsNumeric(.Text) Then
                If CDbl(.Text) >= 0 Then
                  .Text = Format(CDbl(.Text), _
                    strFormat)
                Else
                  .Text = "&" & InvNumber( _
                    Format(0 - CDbl(.Text), _
                    strFormat))
                End If
              Else
                .Text = ""
              End If
            End With
          Next l
        End If
      End With
      
      ' Sort the list alphabetically by this column
      
      .SortOrder = (.SortOrder + 1) Mod 2
      .SortKey = ColumnHeader.Index - 1
      .Sorted = True
      
      ' Restore the previous values to the 'cells' in this
      ' column of the list from the tags, and also restore
      ' the tags to their original values
      
      With .ListItems
        If (lngIndex > 0) Then
          For l = 1 To .Count
            With .Item(l).ListSubItems(lngIndex)
              strData = Split(.Tag, Chr$(0))
              .Text = strData(0)
              .Tag = strData(1)
            End With
          Next l
        Else
          For l = 1 To .Count
            With .Item(l)
              strData = Split(.Tag, Chr$(0))
              .Text = strData(0)
              .Tag = strData(1)
            End With
          Next l
        End If
      End With
    
    Case Else  ' Assume sort by string
      
      ' Sort alphabetically. This is the only sort provided
      ' by the MS ListView control (at this time), and as
      ' such we don't really need to do much here
    
      .SortOrder = (.SortOrder + 1) Mod 2
      .SortKey = ColumnHeader.Index - 1
      .Sorted = True
      
    End Select
  
    ' Unlock the list window so that the OCX can update it
    
    LockWindowUpdate 0&
    
    ' Restore the previous cursor
    
    .MousePointer = lngCursor
  
  End With
  
  ' Report time elapsed, in milliseconds
  
  Debug.Print "Time Elapsed = " & GetTickCount - lngStart & "ms"
  
End Sub
'****************************************************************
' InvNumber
' Function used to enable negative numbers to be sorted
' alphabetically by changing the characters
'----------------------------------------------------------------
Private Function InvNumber(ByVal Number As String) As String
  Static i As Integer
  For i = 1 To Len(Number)
    Select Case Mid$(Number, i, 1)
    Case "-": Mid$(Number, i, 1) = " "
    Case "0": Mid$(Number, i, 1) = "9"
    Case "1": Mid$(Number, i, 1) = "8"
    Case "2": Mid$(Number, i, 1) = "7"
    Case "3": Mid$(Number, i, 1) = "6"
    Case "4": Mid$(Number, i, 1) = "5"
    Case "5": Mid$(Number, i, 1) = "4"
    Case "6": Mid$(Number, i, 1) = "3"
    Case "7": Mid$(Number, i, 1) = "2"
    Case "8": Mid$(Number, i, 1) = "1"
    Case "9": Mid$(Number, i, 1) = "0"
    End Select
  Next
  InvNumber = Number
End Function
'****************************************************************
'
'----------------------------------------------------------------

Attachments

FileUploadedSize
CODE_UPLOAD229112141999.zip9/3/2020 3:45:00 PM4036
Author: dwirch

Derek Wirch is a seasoned IT professional with an impressive career dating back to 1986. He brings a wealth of knowledge and hands-on experience that is invaluable to those embarking on their journey in the tech industry.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.