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)