Listentreffer
Feststellen, welcher Listeneintrag sich an einer bestimmten Position befindet
Das ListView Steuerelement verfügt über eine praktische HitTest-Methode, mit der man ermitteln kann, ob und welcher Eintrag sich an einer bestimmten Position befindet. Für die ListBox, FileListBox und DirListBox kann man so eine Funktion ebenfalls haben...
Das ListView Steuerelement aus den Windows Common Controls verfügt über eine HitTest-Methode, die ein ListItem zurückgibt, das sich unter den angegebenen Koordinaten befindet.
Für die Standard ListBox wird eine solche Methode nicht angeboten. Aber Sie würden diesen Artikel nicht lesen, wenn es nicht doch eine Möglichkeit gäbe, eine solche HitTest Funktion der Standard ListBox zur Seite zu stellen.
Kern dieser Funktion ist die API Funktion LBItemFromPt. Diese erwartet den Handle des ListBox Steuerelements und die X und Y Koordinaten relativ zu den Bildschirmkoordinaten. Also, müssen zu den Client-Koordinaten, die man bei den MouseDown, MouseMove und MouseUp-Ereignissen erhält, über die API Funktion ClientToScreen die Bildschirmkoordinaten ermittelt werden. Als Ergebnis der LBItemFromPt-Funktion erhält man den Index des Listeneintrags an der angegebenen Position bzw. -1, wenn sich an dieser Stelle kein Eintrag befindet.
Diese Funktion lässt sich auch ohne weiteres für die FileListBox verwenden, da diese auf der ListBox basiert, wie auch die DirListBox. Bei der DirListBox muss man sich aber zunächst einmal den Index, den man über die LBItemFromPt-Funktion erhält, zurecht biegen. Denn dieser ist weiterhin 0 basiert, während bei dem DirListBox Steuerelement Verzeichnisse des aktuellen Pfades positive Indizes erhalten, begonnen bei 0 und die übergeordneten Verzeichnisse negative Indizes, -1 für das aktuell angezeigte Verzeichnis.
Der Versatz, der sich dadurch zwischen API Index und eigentlichem Index ergibt, lässt sich durch Zählung der im Pfad vorkommenden Backslashes ermitteln. Da –1 als Kennzeichen für keinen Treffer wegfällt, wird statt dessen die Gesamtzahl der Einträge zurück gegeben, die durch die ListCount-Eigenschaft ermittelt wird.
Die Funktion ListHitTest kapselt diese Aufgaben und liefert immer den getroffenen Index zurück oder -1, wenn kein Eintrag unter den angegebenen Koordinaten zu finden ist, beziehungsweise den Wert der ListCount-Eigenschaft, wenn man diese Funktion zusammen mit einer DirListBox verwendet.
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Declare Function ClientToScreen Lib "user32" ( _
ByVal hWnd As Long, _
ByRef lpPoint As POINTAPI _
) As Long
Private Declare Function LBItemFromPt Lib "comctl32" ( _
ByVal hLB As Long, _
ByVal X As Long, ByVal Y As Long, _
ByVal bAutoScroll As Boolean _
) As Long
Public Function ListHitTest(ByRef ListBox As Object, _
ByVal X As Single, _
ByVal Y As Single) As Long
Dim lPT As POINTAPI
Dim lPos As Integer
Dim lOffset As Integer
Dim lPath As String
Select Case True
Case TypeOf ListBox Is ListBox, _
TypeOf ListBox Is FileListBox, _
TypeOf ListBox Is DirListBox
Case Else
Exit Function
End Select
If (TypeOf ListBox Is DirListBox) Then
If (Left$(ListBox.Path, 2) = "\\") Then
lPath = ListBox.Path
lPos = InStr(3, lPath, "\")
Else
lPath = IIf(Right$(ListBox.Path, 1) <> "\", _
ListBox.Path & "\", _
ListBox.Path)
lPos = 3
End If
Do Until (lPos = 0)
lOffset = lOffset + 1
lPos = InStr(lPos + 1, lPath, "\")
Loop
End If
With Screen
lPT.X = X \ .TwipsPerPixelX
lPT.Y = Y \ .TwipsPerPixelY
End With
ClientToScreen ListBox.hWnd, lPT
ListHitTest = LBItemFromPt(ListBox.hWnd, lPT.X, lPT.Y, False)
If (TypeOf ListBox Is DirListBox) Then
If (ListHitTest = -1) Then
ListHitTest = ListBox.ListCount
Else
ListHitTest = ListHitTest - lOffset
End If
End If
End Function
Download
- Modul modListHitTest und Beispielprojekt (listhittest.zip - 4 KB)