After
experimenting with a variety of advanced list-type controls, it seems more and more developers are turning back to the trusty listbox to
display simple data, yet want some of the functionality that other provided and third-party controls offer. Once such case is the
desire to determine the list item over which a right-mouse button was clicked, often to display a context menu tailored for the specific
item, or simply as an aid in selecting the item via either button.
By using SendMessage, CopyMemory, a couple of C-macros, and the
LB_ITEMFROMPOINT message, determining the list item is a straightforward process. |
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 Type POINTAPI
X As Long
Y As Long
End Type
Private Const LB_ITEMFROMPOINT As Long = &H1A9
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hWnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, _
ByVal Length As Long)
Private Declare Function GetCursorPos Lib "user32" _
(lpPoint As POINTAPI) As Long
Private Declare Function ScreenToClient Lib "user32" _
(ByVal hWnd As Long, _
lpPoint As POINTAPI) As Long
Private Sub Command1_Click()
Unload Me
End Sub
Private Sub Form_Load()
'Add a few items
Dim i As Integer
For i = 0 To 20
List1.AddItem "List item no" & Str$(i)
Next
End Sub
Public Function LoWord(dwValue As Long) As Integer
CopyMemory LoWord, dwValue, 2
End Function
Public Function MAKELONG(wLow As Long, wHigh As Long) As Long
MAKELONG = LoWord(wLow) Or (&H10000 * LoWord(wHigh))
End Function
Public Function MAKELPARAM(wLow As Long, wHigh As Long) As Long
'Combines two integers into a long integer
MAKELPARAM = MAKELONG(wLow, wHigh)
End Function
Private Sub List1_MouseDown(Button As Integer, _
Shift As Integer, _
X As Single, Y As Single)
If Button = vbRightButton Then
Dim lParam As Long
Dim curritem As Long
Dim r As Long
Dim pt As POINTAPI
Call GetCursorPos(pt)
Call ScreenToClient(List1.hWnd, pt)
lParam = MAKELPARAM(pt.X, pt.Y)
r = SendMessage(List1.hWnd, _
LB_ITEMFROMPOINT, _
0&, ByVal lParam)
If r > -1 Then
curritem = LoWord(r)
Text1.Text = "Right-mouse clicked over item " & _
curritem & " - " & vbTab & Chr$(34) & _
List1.List(curritem) & Chr$(34)
'this line selects the item (if desired)
'with the right-click
List1.Selected(curritem) = True
'uncomment to display a context menu which
'could be customized for the given selection
'PopupMenu mnuListOptions
End If
End If
End Sub |
Run the project and right-click a list item .... it will
become selected, and its index and text will be reflected in the listbox.
By moving or copying the code to the List1_MouseMove event, removing
the If .. Then statement, and commenting out the List1.Selected() statement, the textbox will now reflect the item the mouse is currently
over - (as opposed to selected) - great for displaying in a status bar. |