list view to sort 
Author Message
 list view to sort

Hi,

I sort columns in a list view control like this :

Private Sub lsvDetail_ColumnClick(ByVal ColumnHeader As
MSComctlLib.ColumnHeader)
With lsvDetail
  .SortKey = ColumnHeader.Index - 1
  If .SortOrder = lvwAscending Then
   .SortOrder = lvwDescending
  Else
   .SortOrder = lvwAscending
  End If
 End With
End Sub

it works when I have text in my columns.
But , if i have number or date, the sort is bad. ("3" is greater than "12")
How can I sort number, or date like explorer does ?



Mon, 08 Sep 2003 18:54:14 GMT  
 list view to sort
Listview sorts everything as a string.  Thus  "11" comes before "2".
The only way to sort numbers in a listview is to pad them with leading
spaces or "0"'s as in
       "01"   or "  1"
       "02"   or "  2"
       "03"   or "  3"

Alternatively if you are open to a 3rd party control you might want to try
out our TList 6/Pro which has options for sorting Numerical vs Alphabetic,
as well as other sort options for string sorts.

If you are interested I'd be happy tos end you additional information.

* Please include a copy of this note with your reply

        Jeff Bennett                    President

        *    Bennet-Tec Information Systems, Inc
        *    50 Jericho Tpk, Jericho, NY 11753
        *    Phone 516 997 5596,  Fax - 5597
        *    RELIABLE Custom Controls Make You Look Sharp!
        *    TList/Pro    *    ALLText HT/Pro    *    MetaDraw    *
        *    Custom Software Development Services Too.
        *    WWW.Bennet-Tec.Com

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Quote:
----- Original Message -----

Newsgroups: microsoft.public.vb.controls
Sent: Thursday, March 22, 2001 5:54 AM
Subject: list view to sort

Hi,

I sort columns in a list view control like this :

Private Sub lsvDetail_ColumnClick(ByVal ColumnHeader As
 MSComctlLib.ColumnHeader)
 With lsvDetail
   .SortKey = ColumnHeader.Index - 1
   If .SortOrder = lvwAscending Then
    .SortOrder = lvwDescending
   Else
    .SortOrder = lvwAscending
   End If
  End With
 End Sub

it works when I have text in my columns.
 But , if i have number or date, the sort is bad. ("3" is greater than "12")
 How can I sort number, or date like explorer does ?



Mon, 08 Sep 2003 23:16:15 GMT  
 list view to sort
The sort is not bad; a listview sort is based on ASCII codes of the
characters, the same as a ListBox.  Unlike a listbox, however, you can use
some API to replace this default sort with your own custom sorting
procedure.  See the following Knowledge Base article for some background
information on how to do this:

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

However, this article contains some blatant errors in it.  For one, it
mentions the example code will not work with the VB6 version of the ListView
control.  Not true.  Second, the custom sorting function in the example
returns 0, 1 or 2.   This is incorrect.  If you look up the LVM_SORTITEMS
message in MSDN Library, you'll see it states "The comparison function must
return a negative value if the first item should precede the second, a
positive value if the first item should follow the second, or zero if the
two items are equivalent".

Here's my own procedure for sorting numbers:

Public Function CompareNumbers(ByVal lParam1 As Long, ByVal lParam2 As Long,
ByVal hWnd As Long) As Long

    'This is the callback procedure that gets passed to the
    'ListView control to provide the comparison function for
    'integer values (Longs).

    Dim sData           As String
    Dim lNumber1        As Long
    Dim lNumber2        As Long

    ListView_GetItemData lParam1, hWnd, sData
    If IsNumeric(sData) Then
        lNumber1 = CLng(sData)
    Else
        lNumber1 = 0
    End If

    sData = ""
    ListView_GetItemData lParam2, hWnd, sData
    If IsNumeric(sData) Then
        lNumber2 = CLng(sData)
    Else
        lNumber2 = 0
    End If

    If m_lSortOrder = lvwAscending Then
        CompareNumbers = LngComp(lNumber1, lNumber2)
    Else
        CompareNumbers = LngComp(lNumber2, lNumber1)
    End If

End Function

Private Function LngComp(ByVal Number1 As Long, ByVal Number2 As Long) As
Long

    Select Case Number1
        Case Number2
            LngComp = 0
        Case Is < Number2
            LngComp = -1
        Case Is > Number2
            LngComp = 1
    End Select

End Function

And here's a slightly modified version of ListView_GetItemData that will get
the data for whatever column is being sorted.

Public Sub ListView_GetItemData(lParam As Long, hWnd As Long, sData As
String)

    Dim objFind             As LV_FINDINFO
    Dim lIndex              As Long
    Dim objItem             As LV_ITEM
    Dim baBuffer(32)        As Byte
    Dim lLength             As Long

    'Convert the input parameter to an index in the list view
    With objFind
        .Flags = LVFI_PARAM
        .lParam = lParam
    End With
    lIndex = SendMessageLong(hWnd, LVM_FINDITEM, -1, VarPtr(objFind))

    'Get the data for this list item.
    With objItem
        .mask = LVIF_TEXT
        'SubItems are 0-based in the API
        .isubitem = m_lSortKey - 1
        .pszText = VarPtr(baBuffer(0))
        .cchTextMax = UBound(baBuffer)
    End With

    lLength = SendMessageLong(hWnd, LVM_GETITEMTEXT, lIndex,
VarPtr(objItem))

    If lLength > 0 Then
        'On Error Resume Next
        sData = Left$(StrConv(baBuffer, vbUnicode), lLength)
    End If

End Sub

Note that m_lSortKey and m_lSortOrder are module-level variables in the .bas
file in which this code exists.  m_lSortKey is ColumnHeader.Index and
m_lSortOrder is either lvwAscending or lvwDescending.  I used Public
Property Let procedures to pass these two values from the listview control's
ColumnClick event. You may or may not want to do it the same way.

Also note that when you custom sort items in a ListView in this way, the
ListItems collection does not get sorted, so refering to an item by its
index is useless (always use a key).  This also means that certain methods
won't work at all or won't work correctly.  One example is the EnsureVisible
method.  Here's a replacement procedure you can call.

Public Function EnsureVisible(ByVal hListView As Long, ByVal ItemText As
String) As Boolean

    'Replacement procedure for a ListItem's EnsureVisible method.
    'This is necessary because the EnsureVisible method will
    'not work correctly if we've done our own sorting because
    'the indexes of items in the ListItems collection are not
    'correct.  Return value is True if successful; False otherwise.

    Dim lvfi        As LV_FINDINFO
    Dim lRet        As Long
    Dim Index       As Long

    'We first need to find the item in order to get its
    'correct index

    With lvfi
        .psz = ItemText & vbNullChar
        .Flags = LVFI_STRING
    End With

    'Specify -1 for wParam to start search from beginning
    Index = SendMessage(hListView, LVM_FINDITEM, -1, lvfi)

    If Index = -1 Then
        'not found or unsuccessful
        Exit Function
    End If

    'Now we can send the LVM_ENSUREVISIBLE message
    'wParam is the index of the item
    'lParam is either 0 or 1.
    '   0 - scroll if item is not entirely visible
    '   1 - no scrolling occurs if the item is at least
    '       partially visible
    lRet = SendMessage(hListView, LVM_ENSUREVISIBLE, Index, ByVal 0&)

    EnsureVisible = CBool(lRet)

End Function

Example of calling this procedure:

With ListView1
        If Not .SelectedItem Is Nothing Then
            EnsureVisible .hWnd, .SelectedItem.Text
        End If
End With

Furthermore, in the ItemClick event, the Item object passed to this event
won't be the correct item.  To work around this, immediately in this event,
Set Item = ListView1.SelectedItem.

Finally, let me just say that while custom sorting a ListView is entirely
possible, you need to work-around quite a few things and I did not cover
them all in this post.  You might determine it's not really worth it,
particularly if you're not too familiar with the API.  If there are a lot of
items to be sorted, you will also notice a severe performance hit.

Mike


Quote:
> Hi,

> I sort columns in a list view control like this :

> Private Sub lsvDetail_ColumnClick(ByVal ColumnHeader As
> MSComctlLib.ColumnHeader)
> With lsvDetail
>   .SortKey = ColumnHeader.Index - 1
>   If .SortOrder = lvwAscending Then
>    .SortOrder = lvwDescending
>   Else
>    .SortOrder = lvwAscending
>   End If
>  End With
> End Sub

> it works when I have text in my columns.
> But , if i have number or date, the sort is bad. ("3" is greater than
"12")
> How can I sort number, or date like explorer does ?



Tue, 09 Sep 2003 00:52:30 GMT  
 list view to sort
Thanks for all that !!
I test...


Quote:
> The sort is not bad; a listview sort is based on ASCII codes of the
> characters, the same as a ListBox.  Unlike a listbox, however, you can use
> some API to replace this default sort with your own custom sorting
> procedure.  See the following Knowledge Base article for some background
> information on how to do this:

> HOWTO: Sort a ListView Control by Date
> Article ID: Q170884
> http://support.microsoft.com/support/kb/articles/Q170/8/84.asp

.
.
.


Tue, 09 Sep 2003 01:14:16 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. List view and sorting

2. List View Column Sorting

3. Help:list view control sorting

4. List view date sort

5. slow list view sorting - help needed

6. Sorting the content of list view on clicking column headers

7. List View Sort Question

8. List View Sort order

9. Logical sorting in List View (date and/or time)

10. List View click on header to sort date column

11. List View - Sort by Clicking Header

12. LIST VIEW - FILE SIZE SORT

 

 
Powered by phpBB® Forum Software