How does someone find the X&Y of a selected row in a Listbox without clicking on the row? There is probably a very easy way but it eludes me tonight…
thanks!
How does someone find the X&Y of a selected row in a Listbox without clicking on the row? There is probably a very easy way but it eludes me tonight…
thanks!
X would be anywhere on the row… I assume you want to create a drag item?
Anway:
[code]Dim Y as Integer
If LB.Border Then Y = 1
If LB.HasHeading Then Y = Y + LB.HeaderHeight
Y = Y + (LB.ListIndex - LB.ScrollPosition)*LB.RowHeight
[/code]
Y should be at the top of the row.
Alternately
Dim Y as integer = -1, ub as integer = LB.Height - 1
For i as integer = 0 to ub
If LB.RowFromXY(10,i) = lb.ListIndex Then
Y = i
Exit
End if
Next
Karen
that was perfect. And I’m opening a graphic at the coordinates related to the selected row.
I knew someone smart like yourself would know this off the top of their heads.
I like Karen’s second version a lot, but I think it can be more efficient using a binary search. Let me try something…
This will give you the precision of Karen’s second version with fewer loops, especially if the selection is near the bottom. I tested it in the Change event so adjust as necessary.
if me.ListIndex = -1 then
lblY.Text = "-1"
return
end if
dim h as integer = me.Height -1
dim y as integer = h \\ 2
dim highY as integer = h
dim lowY as integer = 0
do
dim r as integer = me.RowFromXY( 1, y )
if r = me.ListIndex then
exit
elseif r < me.ListIndex then
lowY = y
y = y + ( ( highY - y ) \\ 2 )
else // r > me.ListIndex
highY = y
y = y - ( ( y - lowY ) \\ 2 )
end if
loop
// Find the top of the row
highY = y - 1
for y = highY downto 0
if me.RowFromXY( 1, y ) < me.ListIndex then
y = y + 1
exit
end if
next y
lblY.Text = str( y )
I don’t understand why there’s a second version. Doesn’t the first directly compute the correct Y?
Good question. It turns out, it does if there is a header. If there isn’t a header, it’s off by one. So without a header, the Y of the first row is 1 whereas the calculation will return 0. Each subsequent row is off by one too.
This means that if you use RowFromXY( 1, 0 ), you will not get back -1, not 0. I don’t know if this is a bug or not, but there you go.
(The line in the post above should have read “you will get back -1, not 0”. Need sleep )
Here is my current test code. It has additional checks to prevent an endless loop.
if me.ListIndex = -1 then
lblY.Text = "-1"
return
end if
dim h as integer = me.Height - 1
dim y as integer = h \\ 2
dim highY as integer = h
dim lowY as integer = 0
do
dim r as integer = me.RowFromXY( 1, y )
if r = me.ListIndex then
exit
elseif r < me.ListIndex then
if y = lowY then exit
lowY = y
y = y + ( ( highY - y ) \\ 2 )
else // r > me.ListIndex
if y = highY then exit
highY = y
y = y - ( ( y - lowY ) \\ 2 )
end if
loop
// Find the top of the row
highY = y - 1
for y = highY downto 0
dim r as integer = me.RowFromXY( 1, y )
if r < me.ListIndex then
y = y + 1
exit
end if
next y
// Compare
'dim calcY as integer = ( me.ListIndex * me.RowHeight ) + if( me.HasHeading, me.HeaderHeight, 0 )
'if y <> calcY then
'break
'end if
lblY.Text = str( y )
That’s the border insetting all sides by 1. Turn border off and RowFromXY(0, 0) = 0. It happens at the bottom too. With Border True the last Y pixel (lb.Height-1) is not counted as a cell so RowFromXY returns -1.
The code I wrote here was off the top of my head without testing or optimization to illustrate how to do it , but I think the first version is correct. I think your off by one comes from not considering the border, which my code above does.
I included the second way as an afterthought because years ago the listbox did not have either the RowHeight (only DefaultRow Height which returns -1 if not set) or HeaderHeight properties so I had to use RowFromXY to get the header height and row height.
BTW IMO IF Listbox.HasHeader is false, I think LB.headerHeight should return 0, but it returns the same value regardless, necessitating the If statement… Which is very unintuitive
I used the first version and havent found it to be off yet. So as far as I can tell it works as designed/expected.