Visual Basic Common Control API Routines
SendMessage: Determine Selected ListView ListItems
     
Posted:   Monday September 16, 2002
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   None
Author:   VBnet - Randy Birch
     
Related:   SendMessage: Determine a ListView's Visible Item Count
SendMessage: Clicking ListView White Space to De-select Items
SendMessage: ListView Select / Deselect All
     
 Prerequisites
This code is equally applicable to the VB4-32, VB5 and VB6 Listview controls.

A quick routine to demonstrate using SendMessage with LVM_GETSELECTEDCOUNT and LVM_GETNEXTITEM messages to traverse a listview to retrieve the indices to the selected items in a MultiSelect control. Also contains a portion of the LVM_SUBITEMHITTEST code from SendMessage: Clicking ListView White Space to De-select Items showing how to deselect items completely.

The results from the routine are used to populate an array containing the selected item indices; the list box in this demo shows the final contents of the selection array.

 BAS Module Code
None.

 Form Code
Add a command button (Command1), a listview (Listview1), a list box (List1) and a label (Label1), with the following code:

Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const LVM_FIRST As Long = &H1000
Private Const LVM_SUBITEMHITTEST As Long = (LVM_FIRST + 57)
Private Const LVM_HITTEST As Long = (LVM_FIRST + 18)

Private Const LVM_GETNEXTITEM  As Long = (LVM_FIRST + 12)
Private Const LVM_GETSELECTEDCOUNT As Long = (LVM_FIRST + 50)

Private Const LVHT_ABOVE = &H8
Private Const LVHT_BELOW = &H10
Private Const LVHT_TORIGHT = &H20
Private Const LVHT_TOLEFT = &H40
Private Const LVHT_NOWHERE As Long = &H1
Private Const LVHT_ONITEMICON As Long = &H2
Private Const LVHT_ONITEMLABEL As Long = &H4
Private Const LVHT_ONITEMSTATEICON As Long = &H8
Private Const LVHT_ONITEM As Long = (LVHT_ONITEMICON Or _
                                    LVHT_ONITEMLABEL Or _
                                    LVHT_ONITEMSTATEICON)

Private Type POINTAPI
   x As Long
   y As Long
End Type

Private Type HITTESTINFO
   pt As POINTAPI
   flags As Long
   iItem As Long
   iSubItem  As Long
End Type

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



Private Sub Form_Load()

   Dim itmx As ListItem
   Dim cnt As Long
   Dim tmp As Long
   
   Randomize Timer
   
   With ListView1
   
      .ColumnHeaders.Add , , "Name"
      .ColumnHeaders.Add , , "Size"
      .ColumnHeaders.Add , , "Type"
      .ColumnHeaders.Add , , "Created"
      .View = lvwReport
      .FullRowSelect = True 'VB6 only!
   
      For cnt = 1 To 100
      
        'create a few random entries
        'to simulate real data
         tmp = Int(Rnd(20) * 20) + 1
     
         Set itmx = .ListItems.Add(, , String(tmp, Chr$(123 - tmp)))       
         itmx.SubItems(1) = tmp & " kb"
         itmx.SubItems(2) = "winzip file"
         itmx.SubItems(3) = DateAdd("d", -Int(Rnd(365) * 365), Date)
      
      Next
   
   End With
   
End Sub


Private Sub Command1_Click()

   Const LVNI_SELECTED = &H2
   Dim nSelected() As Long
   Dim index As Long
   Dim numSelected As Long
   Dim cnt As Long
   
   List1.Clear

   numSelected = ListView_GetSelectedCount(ListView1.hwnd)

   If numSelected <> 0 Then
   
      ReDim nSelected(0 To numSelected - 1)
      
      Do
      
         index = ListView_GetNextItem(ListView1.hwnd, index, LVNI_SELECTED)
         
         If index > -1 Then          
            nSelected(cnt) = index
           cnt = cnt + 1
         End If
      
      Loop Until index = -1
   
     'debug only: print results to the list
      For cnt = 0 To numSelected - 1
         List1.AddItem nSelected(cnt)
      Next
      
   End If

End Sub


Private Sub ListView1_MouseDown(Button As Integer, _
                                Shift As Integer, _
                                x As Single, _
                                y As Single)

   Dim hti As HITTESTINFO
   Dim itemIndex As Long
      
  'Fill a HITTESTINFO structure with
  'information about the point in the
  'listview where the mouse was clicked.
   With hti
      .pt.x = (x / Screen.TwipsPerPixelX)
      .pt.y = (y / Screen.TwipsPerPixelY)
      .flags = LVHT_ABOVE Or LVHT_BELOW Or _
               LVHT_TOLEFT Or LVHT_TORIGHT Or _
               LVHT_ONITEMICON Or _
               LVHT_ONITEMLABEL Or _
               LVHT_NOWHERE
   End With
      
   itemIndex = SendMessage(ListView1.hwnd, LVM_SUBITEMHITTEST, 0, hti)
   
   If itemIndex = -1 And _
      (hti.iSubItem = -1 Or _
       hti.iSubItem = 0) Then
   
      Set ListView1.SelectedItem = Nothing
   
   End If
      
End Sub


Private Sub ListView1_MouseUp(Button As Integer, _
                              Shift As Integer, _
                              x As Single, _
                              y As Single)
 'update label
   If Not ListView1.SelectedItem Is Nothing Then
      Label1.Caption = ListView1.SelectedItem.Text
   Else
      Label1.Caption = "(no selected index)"
   End If
   
End Sub


Private Function ListView_GetNextItem(hwnd As Long, _
                                      index As Long, _
                                      flags As Long) As Long

   ListView_GetNextItem = SendMessage(hwnd, _
                                      LVM_GETNEXTITEM, _
                                      index, _
                                      ByVal flags)

End Function


Private Function ListView_GetSelectedCount(hwnd As Long) As Long

   ListView_GetSelectedCount = SendMessage(hwnd, _
                                           LVM_GETSELECTEDCOUNT, _
                                           0&, _
                                           ByVal 0&)

End Function

 Comments
Note that the code is split between the MouseDown and MouseUp events. This is due to the fact that in the MouseDown event, it is too early to retrieve the selected item information since it has not been set by the control. Similarly, the MouseDown code can not go into the MouseUp event because by that time its too late to clear the selected item.

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter