The header is currently approximately 32 logical points high, but that is a theme-dependent implementation detail and shouldn’t be hard-coded.
I’ve implemented a more reliable solution:
Function ListBox.RowAtPoint(x As Double, y As Double) As Integer
It returns the displayed row under the supplied ListBox-relative coordinates, or -1 when the point is over the header, a scrollbar, blank space, or outside a visible row.
Property pressedRow As Integer = -1
Sub ListBox1_MouseDown(x As Double, y As Double, button As MouseButton)
pressedRow = Me.RowAtPoint(x, y)
End Sub
Sub ListBox1_SelectionChanged()
If pressedRow >= 0 Then
Print("Pressed row: " + pressedRow.ToString())
End If
End Sub
The coordinates from MouseDown can be passed directly to RowAtPoint; it automatically accounts for the header, scrolling, and the ListBox’s position inside its window or container.
For pointer-driven selection, MouseDown will also be delivered before SelectionChanged, allowing this pattern to work reliably. This will be available in the next Studio update: https://feedback.objo.dev/feature/1312