Solved

Sorting a listview

Posted on 2001-08-23
17
614 Views
Last Modified: 2011-09-20
im trying to sort a listview box this is the code im using
ListView1.SortOrder = lvwDescending
ListView1.SortKey = ColumnHeader.Index - 1
ListView1.Sorted = True
it works but when i try to sort numbers they end up like this
13
15
24
36
54656
566

but it should be
13
15
24
36
566
54656
how can i get it to sort it this way
0
Comment
Question by:440
  • 3
  • 2
  • 2
  • +7
17 Comments
 
LVL 75

Expert Comment

by:Anthony Perkins
Comment Utility
Pad appropriately with blanks or zeros.  In other words:
00013
00015
00024
00036
00566
54856
0
 
LVL 10

Expert Comment

by:arana
Comment Utility
maybe even padding with spaces can work.
0
 
LVL 75

Expert Comment

by:Anthony Perkins
Comment Utility
arana,

Yes, that is what I meant by "blanks".  But then it has to be right-justified.

Anthony
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
Comment Utility
0
 
LVL 75

Expert Comment

by:Anthony Perkins
Comment Utility
Richie,

Interesting ...

Anthony
0
 
LVL 14

Accepted Solution

by:
wsh2 earned 50 total points
Comment Utility
Just substitute a Number comparison in place of the Date comparison

From MSDN:

HOWTO: Sort a ListView Control by Date (Q170884)
http://support.microsoft.com/support/kb/articles/Q170/8/84.asp
-------------------------------------------------------
HOWTO: Sort a ListView Control by Date

-------------------------------------------------------

The information in this article applies to:

Microsoft Visual Basic Learning Edition for Windows, versions 6.0, 5.0
Microsoft Visual Basic Professional Edition for Windows, versions 6.0, 5.0
Microsoft Visual Basic Enterprise Edition for Windows, versions 6.0, 5.0
Microsoft Visual Basic Control Creation Edition for Windows, version 5.0

--------------------------------------------------------

SUMMARY
When using a Listview control, you can set the Sorted property for the control to sort the list alphabetically. However, the Listview control does not expose a property or method for sorting a list by date. This article presents a method that you can use to sort a Listview control by date.

MORE INFORMATION

WARNING: One or more of the following functions are discussed in this article; VarPtr, VarPtrArray, VarPtrStringArray, StrPtr, ObjPtr. These functions are not supported by Microsoft Technical Support. They are not documented in the Visual Basic documentation and are provided in this Knowledge Base article "as is." Microsoft does not guarantee that they will be available in future releases of Visual Basic.

To sort data in a ListView control by date, it is necessary to provide a comparison function to the control via AddressOf.

NOTE: Using this approach, you will sort the data in the control but not the ListItems collection. Therefore, if you must read the data from the list in sorted order, it is necessary to step through the actual list rather than the ListItems collection.

Step-by-Step Example
Start a new Visual Basic project. Form1 is created by default.

On the Project menu, click Components, select the Microsoft Windows Common Controls 5.0 check box, and then click OK.

NOTE: You can also use Visual Basic 6.0 and select the Microsoft Windows Common Controls 6.0 check box with only one minor change, as noted below.

Add a Module to the project.

Draw a ListView control on Form1.

Add the following code to Form1:

      Option Explicit

      Private Sub Form_Load()

        Dim clmAdd As ColumnHeader
        Dim itmAdd As ListItem

        'Add two Column Headers to the ListView control
        Set clmAdd = ListView1.ColumnHeaders.Add(Text:="Name")
        Set clmAdd = ListView1.ColumnHeaders.Add(Text:="Date")

        'Set the view property of the Listview control to Report view
        ListView1.View = lvwReport

        'Add data to the ListView control
        Set itmAdd = ListView1.ListItems.Add(Text:="Joe")
        itmAdd.SubItems(1) = "05/07/97"

        Set itmAdd = ListView1.ListItems.Add(Text:="Sally")
        itmAdd.SubItems(1) = "04/08/97"

        Set itmAdd = ListView1.ListItems.Add(Text:="Bill")
        itmAdd.SubItems(1) = "05/29/97"

        Set itmAdd = ListView1.ListItems.Add(Text:="Fred")
        itmAdd.SubItems(1) = "05/17/97"

        Set itmAdd = ListView1.ListItems.Add(Text:="Anne")
        itmAdd.SubItems(1) = "04/01/97"

      End Sub

      ' Use this line of code for Common Controls 5.0:
      Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
              ComctlLib.ColumnHeader)
      ' For Common Controls 6.0, uncomment the line below and comment the line above.
      'Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
              MSComctlLib.ColumnHeader)

        Dim strName As String
        Dim dDate As Date
        Dim lngItem As Long

        'Handle User click on column header
        If ColumnHeader.Text = "Name" Then  'User clicked on Name header
          ListView1.Sorted = True        'Use default sorting to sort the
          ListView1.SortKey = 0          'items in the list
        Else
          ListView1.Sorted = False       'User clicked on the Date header
                                         'Use our sort routine to sort
                                         'by date
          SendMessage ListView1.hWnd, _
                      LVM_SORTITEMS, _
                      ListView1.hWnd, _
                      AddressOf CompareDates
        End If

        'Refresh the ListView before writing the data
        ListView1.Refresh

        'Loop through the items in the List to print them out in
        'sorted order.
        'NOTE: You are looping through the ListView control because when _
        'sorting by date the ListItems collection won't be sorted.

        For lngItem = 0 To ListView1.ListItems.Count - 1
          ListView_GetListItem lngItem, ListView1.hWnd, strName, dDate
        Next

      End Sub
Add the following code to Module1:


      Option Explicit

      'Structures

      Public Type POINT
        x As Long
        y As Long
      End Type

      Public Type LV_FINDINFO
        flags As Long
        psz As String
        lParam As Long
        pt As POINT
        vkDirection As Long
      End Type

      Public Type LV_ITEM
        mask As Long
        iItem As Long
        iSubItem As Long
        State As Long
        stateMask As Long
        pszText As Long
        cchTextMax As Long
        iImage As Long
        lParam As Long
        iIndent As Long
      End Type

      'Constants
      Private Const LVFI_PARAM = 1
      Private Const LVIF_TEXT = &H1

      Private Const LVM_FIRST = &H1000
      Private Const LVM_FINDITEM = LVM_FIRST + 13
      Private Const LVM_GETITEMTEXT = LVM_FIRST + 45
      Public Const LVM_SORTITEMS = LVM_FIRST + 48

      'API declarations

      Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
        ByVal hWnd As Long, _
        ByVal wMsg As Long, _
        ByVal wParam As Long, _
        ByVal lParam As Long) As Long

      'Module Functions and Procedures

      'CompareDates: This is the sorting routine that gets passed to the
      'ListView control to provide the comparison test for date values.

      Public Function CompareDates(ByVal lngParam1 As Long, _
                                   ByVal lngParam2 As Long, _
                                   ByVal hWnd As Long) As Long

        Dim strName1 As String
        Dim strName2 As String
        Dim dDate1 As Date
        Dim dDate2 As Date

        'Obtain the item names and dates corresponding to the
        'input parameters

        ListView_GetItemData lngParam1, hWnd, strName1, dDate1
        ListView_GetItemData lngParam2, hWnd, strName2, dDate2

        'Compare the dates
        'Return 0 ==> Less Than
        '       1 ==> Equal
        '       2 ==> Greater Than

        If dDate1 < dDate2 Then
          CompareDates = 0
        ElseIf dDate1 = dDate2 Then
          CompareDates = 1
        Else
          CompareDates = 2
        End If

      End Function

      'GetItemData - Given Retrieves

      Public Sub ListView_GetItemData(lngParam As Long, _
                                      hWnd As Long, _
                                      strName As String, _
                                      dDate As Date)
        Dim objFind As LV_FINDINFO
        Dim lngIndex As Long
        Dim objItem As LV_ITEM
        Dim baBuffer(32) As Byte
        Dim lngLength As Long

        '
        ' Convert the input parameter to an index in the list view
        '
        objFind.flags = LVFI_PARAM
        objFind.lParam = lngParam
        lngIndex = SendMessage(hWnd, LVM_FINDITEM, -1, VarPtr(objFind))

        '
        ' Obtain the name of the specified list view item
        '
        objItem.mask = LVIF_TEXT
        objItem.iSubItem = 0
        objItem.pszText = VarPtr(baBuffer(0))
        objItem.cchTextMax = UBound(baBuffer)
        lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                                VarPtr(objItem))
        strName = Left$(StrConv(baBuffer, vbUnicode), lngLength)

        '
        ' Obtain the modification date of the specified list view item
        '
        objItem.mask = LVIF_TEXT
        objItem.iSubItem = 1
        objItem.pszText = VarPtr(baBuffer(0))
        objItem.cchTextMax = UBound(baBuffer)
        lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                                VarPtr(objItem))
        If lngLength > 0 Then
          dDate = CDate(Left$(StrConv(baBuffer, vbUnicode), lngLength))
        End If

      End Sub

      'GetListItem - This is a modified version of ListView_GetItemData
      ' It takes an index into the list as a parameter and returns
      ' the appropriate values in the strName and dDate parameters.

      Public Sub ListView_GetListItem(lngIndex As Long, _
                                      hWnd As Long, _
                                      strName As String, _
                                      dDate As Date)
        Dim objItem As LV_ITEM
        Dim baBuffer(32) As Byte
        Dim lngLength As Long

        '
        ' Obtain the name of the specified list view item
        '
        objItem.mask = LVIF_TEXT
        objItem.iSubItem = 0
        objItem.pszText = VarPtr(baBuffer(0))
        objItem.cchTextMax = UBound(baBuffer)
        lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                                VarPtr(objItem))
        strName = Left$(StrConv(baBuffer, vbUnicode), lngLength)

        '
        ' Obtain the modification date of the specified list view item
        '
        objItem.mask = LVIF_TEXT
        objItem.iSubItem = 1
        objItem.pszText = VarPtr(baBuffer(0))
        objItem.cchTextMax = UBound(baBuffer)
        lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                                VarPtr(objItem))
        If lngLength > 0 Then
          dDate = CDate(Left$(StrConv(baBuffer, vbUnicode), lngLength))
        End If

      End Sub
Save your project.


Press the F5 key to run the application. Click on the Date column header to sort the items in the list by date.


 
0
 
LVL 49

Expert Comment

by:Ryan Chong
Comment Utility
Hi 440,

Take a look on this link:Sorting ListView ListItems Using Callbacks

http://www.mvps.org/vbnet/code/callback/lvsortcallback.htm

Here is another good link: http://www.codeguru.com/vb/articles/1818.shtml

'Hope will help.  
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
Comment Utility
ryancys, nice url http://www.codeguru.com/vb/articles/1818.shtml, don't you think so?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 10

Expert Comment

by:GoodJun
Comment Utility
Hi. There are a question by Sombel. And he
made a good example and thorough explaination on
the problem. This is the best discussion on
this topic so far, so take a look:
http://www.experts-exchange.com/jsp/qShow.jsp?ta=visualbasic&qid=20161504
0
 
LVL 49

Expert Comment

by:Ryan Chong
Comment Utility
Hi Richie_Simonetti,

Finally realise that post a link that what exact you had posted: http://www.codeguru.com/vb/articles/1818.shtml.

Sorry about that. This example provide a more simple algorithm rather than what show in http://www.mvps.org/vbnet/code/callback/lvsortcallback.htm.

I'd tried and modified a little (on Date section) myself on latter example and looks good also.

regards.
0
 

Author Comment

by:440
Comment Utility
Sorry it took  so loon to get back
i was trying the different code im use the code from wsh2
the problem is that it will only sort if you press on the first two columnheaders ive got a total of 7 columnheaders now one text the others are numbers it will sort the first two fine but will do nothing when clicking on the others
do any of you know how to fix this problem
0
 
LVL 14

Expert Comment

by:wsh2
Comment Utility
Please post your ListView1_ColumnClick code.. <smile>
0
 

Author Comment

by:440
Comment Utility
ok this is the code im using
its from wsh2 from above

Option Explicit

     Private Sub Form_Load()

       Dim clmAdd As ColumnHeader
       Dim itmAdd As ListItem

       'Add two Column Headers to the ListView control
       Set clmAdd = ListView1.ColumnHeaders.Add(Text:="Name")
       Set clmAdd = ListView1.ColumnHeaders.Add(Text:="Date")

       'Set the view property of the Listview control to Report view
       ListView1.View = lvwReport

       'Add data to the ListView control
       Set itmAdd = ListView1.ListItems.Add(Text:="Joe")
       itmAdd.SubItems(1) = "05/07/97"

       Set itmAdd = ListView1.ListItems.Add(Text:="Sally")
       itmAdd.SubItems(1) = "04/08/97"

       Set itmAdd = ListView1.ListItems.Add(Text:="Bill")
       itmAdd.SubItems(1) = "05/29/97"

       Set itmAdd = ListView1.ListItems.Add(Text:="Fred")
       itmAdd.SubItems(1) = "05/17/97"

       Set itmAdd = ListView1.ListItems.Add(Text:="Anne")
       itmAdd.SubItems(1) = "04/01/97"

     End Sub

     ' Use this line of code for Common Controls 5.0:
     Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
             ComctlLib.ColumnHeader)
     ' For Common Controls 6.0, uncomment the line below and comment the line above.
     'Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
             MSComctlLib.ColumnHeader)

       Dim strName As String
       Dim dDate As Date
       Dim lngItem As Long

       'Handle User click on column header
       If ColumnHeader.Text = "Name" Then  'User clicked on Name header
         ListView1.Sorted = True        'Use default sorting to sort the
         ListView1.SortKey = 0          'items in the list
       Else
         ListView1.Sorted = False       'User clicked on the Date header
                                        'Use our sort routine to sort
                                        'by date
         SendMessage ListView1.hWnd, _
                     LVM_SORTITEMS, _
                     ListView1.hWnd, _
                     AddressOf CompareDates
       End If

       'Refresh the ListView before writing the data
       ListView1.Refresh

       'Loop through the items in the List to print them out in
       'sorted order.
       'NOTE: You are looping through the ListView control because when _
       'sorting by date the ListItems collection won't be sorted.

       For lngItem = 0 To ListView1.ListItems.Count - 1
         ListView_GetListItem lngItem, ListView1.hWnd, strName, dDate
       Next

     End Sub
Add the following code to Module1:


     Option Explicit

     'Structures

     Public Type POINT
       x As Long
       y As Long
     End Type

     Public Type LV_FINDINFO
       flags As Long
       psz As String
       lParam As Long
       pt As POINT
       vkDirection As Long
     End Type

     Public Type LV_ITEM
       mask As Long
       iItem As Long
       iSubItem As Long
       State As Long
       stateMask As Long
       pszText As Long
       cchTextMax As Long
       iImage As Long
       lParam As Long
       iIndent As Long
     End Type

     'Constants
     Private Const LVFI_PARAM = 1
     Private Const LVIF_TEXT = &H1

     Private Const LVM_FIRST = &H1000
     Private Const LVM_FINDITEM = LVM_FIRST + 13
     Private Const LVM_GETITEMTEXT = LVM_FIRST + 45
     Public Const LVM_SORTITEMS = LVM_FIRST + 48

     'API declarations

     Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
       ByVal hWnd As Long, _
       ByVal wMsg As Long, _
       ByVal wParam As Long, _
       ByVal lParam As Long) As Long

     'Module Functions and Procedures

     'CompareDates: This is the sorting routine that gets passed to the
     'ListView control to provide the comparison test for date values.

     Public Function CompareDates(ByVal lngParam1 As Long, _
                                  ByVal lngParam2 As Long, _
                                  ByVal hWnd As Long) As Long

       Dim strName1 As String
       Dim strName2 As String
       Dim dDate1 As Date
       Dim dDate2 As Date

       'Obtain the item names and dates corresponding to the
       'input parameters

       ListView_GetItemData lngParam1, hWnd, strName1, dDate1
       ListView_GetItemData lngParam2, hWnd, strName2, dDate2

       'Compare the dates
       'Return 0 ==> Less Than
       '       1 ==> Equal
       '       2 ==> Greater Than

       If dDate1 < dDate2 Then
         CompareDates = 0
       ElseIf dDate1 = dDate2 Then
         CompareDates = 1
       Else
         CompareDates = 2
       End If

     End Function

     'GetItemData - Given Retrieves

     Public Sub ListView_GetItemData(lngParam As Long, _
                                     hWnd As Long, _
                                     strName As String, _
                                     dDate As Date)
       Dim objFind As LV_FINDINFO
       Dim lngIndex As Long
       Dim objItem As LV_ITEM
       Dim baBuffer(32) As Byte
       Dim lngLength As Long

       '
       ' Convert the input parameter to an index in the list view
       '
       objFind.flags = LVFI_PARAM
       objFind.lParam = lngParam
       lngIndex = SendMessage(hWnd, LVM_FINDITEM, -1, VarPtr(objFind))

       '
       ' Obtain the name of the specified list view item
       '
       objItem.mask = LVIF_TEXT
       objItem.iSubItem = 0
       objItem.pszText = VarPtr(baBuffer(0))
       objItem.cchTextMax = UBound(baBuffer)
       lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                               VarPtr(objItem))
       strName = Left$(StrConv(baBuffer, vbUnicode), lngLength)

       '
       ' Obtain the modification date of the specified list view item
       '
       objItem.mask = LVIF_TEXT
       objItem.iSubItem = 1
       objItem.pszText = VarPtr(baBuffer(0))
       objItem.cchTextMax = UBound(baBuffer)
       lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                               VarPtr(objItem))
       If lngLength > 0 Then
         dDate = CDate(Left$(StrConv(baBuffer, vbUnicode), lngLength))
       End If

     End Sub

     'GetListItem - This is a modified version of ListView_GetItemData
     ' It takes an index into the list as a parameter and returns
     ' the appropriate values in the strName and dDate parameters.

     Public Sub ListView_GetListItem(lngIndex As Long, _
                                     hWnd As Long, _
                                     strName As String, _
                                     dDate As Date)
       Dim objItem As LV_ITEM
       Dim baBuffer(32) As Byte
       Dim lngLength As Long

       '
       ' Obtain the name of the specified list view item
       '
       objItem.mask = LVIF_TEXT
       objItem.iSubItem = 0
       objItem.pszText = VarPtr(baBuffer(0))
       objItem.cchTextMax = UBound(baBuffer)
       lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                               VarPtr(objItem))
       strName = Left$(StrConv(baBuffer, vbUnicode), lngLength)

       '
       ' Obtain the modification date of the specified list view item
       '
       objItem.mask = LVIF_TEXT
       objItem.iSubItem = 1
       objItem.pszText = VarPtr(baBuffer(0))
       objItem.cchTextMax = UBound(baBuffer)
       lngLength = SendMessage(hWnd, LVM_GETITEMTEXT, lngIndex, _
                               VarPtr(objItem))
       If lngLength > 0 Then
         dDate = CDate(Left$(StrConv(baBuffer, vbUnicode), lngLength))
       End If

     End Sub
0
 
LVL 8

Expert Comment

by:DennisBorg
Comment Utility
:ping:
0
 
LVL 12

Expert Comment

by:guidway
Comment Utility
Thank you for your interest in Expert’s Exchange. We hope that this information has assisted you in diagnosing your problem. Please award the experts who diligently helped you to find a solution (if any) or request a moderator to PAQ or delete this question. I will check back in seven days to see if a response was given. If not this will be turned over to a moderator for a decision. Thank you!

Your options are:

1. Accept a Comment As Answer (use the button next to the Expert's name).
2. Close the question if the information was not useful to you. You must tell the participants why you wish to do this, and allow for Expert response.
3. Ask Community Support to help split points between participating experts and include the details (expert name and point values to each).
4. Delete the question. Again, you must tell the other participants why you wish to do this, and only Moderators can take this action for you. Do not try to delete them directly if any comments exist, they will be pended and will not complete.

For special handling needs, please post a zero point question in the link below, include the question QID/link.
http://www.experts-exchange.com/jsp/qList.jsp?ta=commspt

Please click this Help Desk link for Member Guidelines, Member Agreement and the Question/Answer process: Click you Member Profile to view your question history and keep them all current with updates as the collaboration effort continues.
http://www.experts-exchange.com/jsp/cmtyHelpDesk.jsp


PLEASE DO NOT AWARD THE POINTS TO ME. ------------> EXPERTS: Please leave any comments regarding this question here on closing recommendations if this item remains inactive another seven (7) days.

 
0
 
LVL 12

Expert Comment

by:guidway
Comment Utility
This question appears to have been abandoned. A Moderator will be asked to
close this question after seven days, with the following recommended
disposition:

Points to wsh2

If you have any comment or objection to the recommendation, please leave it here.

guidway
EE Cleanup Volunteer

0
 
LVL 5

Expert Comment

by:Netminder
Comment Utility
Per recommendation, force-accepted.

Netminder
CS Moderator
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now