This
page demonstrates using the LVHITTESTINFO type along with the LVM_SUBITEMHITTEST message to determine where on the control the mouse was
clicked, regardless of the view mode or whether the FullRowSelect feature has been enabled (Label1). The code is provided in the MouseDown
event to both take advantage of the mouse coordinates passed, as well as providing a mechanism to perform an action before the corresponding
ItemClick event is fired. The MouseDown event also contains a line that will select the primary list item whenever a SubItem is
clicked, even in non-FullRowSelect mode.
Note that the illustration shows the selected list index as its
0-based API value.
This page contains all the code required to build the demonstration
app shown. It also works when an imagelist has been assigned to the control; in that case it will accurately identify and report where the
control was clicked - overtop the text or overtop the icon (Label2). |
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_HITTEST As Long = (LVM_FIRST + 18)
Private Const LVM_SUBITEMHITTEST As Long = (LVM_FIRST + 57)
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 LVHITTESTINFO
pt As POINTAPI
flags As Long
iItem As Long
iSubItem As Long 'ie3+ only .. was NOT in win95.
'Valid only for LVM_SUBITEMHITTEST
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 Check1_Click()
ListView1.FullRowSelect = Not ListView1.FullRowSelect
End Sub
Private Sub Form_Load()
Dim itmX As ListItem
Dim itmH As ColumnHeader
Dim n As Long
'Crete dummy data in the ListView
With ListView1
.View = lvwReport
.FullRowSelect = False
.LabelEdit = lvwManual
For n = 1 To 4
Set itmH = .ColumnHeaders.Add(, , "Column " & CStr(n))
itmH.Width = 1000
Next
For n = 1 To 20
Set itmX = .ListItems.Add(, , "Item " & CStr(n))
itmX.SubItems(1) = CStr(n)
itmX.SubItems(2) = CStr(n ^ 2)
itmX.SubItems(3) = CStr(n ^ 3)
Next
End With
End Sub
Private Sub ListView1_MouseDown(Button As Integer, _
Shift As Integer, _
x As Single, y As Single)
Dim HTI As LVHITTESTINFO
Dim itmX As ListItem
Dim msg1 As String
Dim msg2 As String
'----------------------------------------
'this gets the hittest info using
'the mouse co-ordinates
With HTI
.pt.x = (x \ Screen.TwipsPerPixelX)
.pt.y = (y \ Screen.TwipsPerPixelY)
.flags = LVHT_ONITEM
End With
Call SendMessage(ListView1.hwnd, LVM_SUBITEMHITTEST, 0, HTI)
'----------------------------------------
'this determines whether the hit test
'returned a main or sub item
If HTI.iSubItem = 0 Then
If HTI.iItem > -1 Then
msg1 = "User clicked over main item " & HTI.iItem
Else
msg1 = "User clicked a main item's white space"
End If
ElseIf HTI.iSubItem > 0 Then
msg1 = "User clicked main item " & HTI.iItem & _
" by clicking SubItem " & HTI.iSubItem
End If
'----------------------------------------
'this determines what part of
'the item or SubItem was clicked
If HTI.flags And LVHT_ONITEM Then
If HTI.flags And LVHT_ONITEMICON Then
msg2 = "(click occurred over the item's icon area)"
End If
If HTI.flags And LVHT_ONITEMLABEL Then
Select Case HTI.iSubItem
Case 0: msg2 = "(click occurred over the item's main text)"
Case Else: msg2 = "(click occurred over the SubItem text)"
End Select
End If
End If
'----------------------------------------
'this selects the current item if the
'control's FullRowSelect is False, and
'a SubItem was clicked. (One is added
'because the API is 0-based, and the
'ListItems collection is 1-based).
If HTI.iSubItem > 0 Then
ListView1.ListItems(HTI.iItem + 1).Selected = True
End If
Label1.Caption = msg1
Label2.Caption = msg2
End Sub
|