views:

1254

answers:

2

I have some Label controls sitting on Panel controls on a Form. I want to get the labels' positions relative to the form's origin so that at run time I can hide the panel and the labels and draw some other text in their place directly onto the form.

Basically, I'm doing the following calculation: Get the absolute screen position of a label with Control.PointToScreen() and convert it back to a relative position with Control.PointToClient(), so either:

Dim newloc As Point = Me.PointToClient(ctl.PointToScreen(Point.Empty))

or

Dim newloc As Point = Me.PointToClient(ctl.Parent.PointToScreen(ctl.Location))

I have found that the two methods sometimes give me different results - putting my new point out of the visible area with negative values! - but haven't been able to determine why. I would have thought they should be identical (and they are, most of the time).

Reading the docs didn't help the first time around, but perhaps I skipped over something... Anyway, I'd be thankful for any help before I start tearing my hair out.

Or, on the other hand, is there a better way to do this?

Edit: Sample results

So, here's a real example.

Label1 at {X=4,Y=6} on Panel1; Label2 at {X=163,Y=6} on the same parent, Panel1. Obviously I'm expecting different X-positions, but Y should be identical for both.

When I run the project both

ctl.PointToScreen(Point.Empty)
and
ctl.Parent.PointToScreen(ctl.Location)
give me the same screen location for Label1 at {X=959,Y=119} (the absolute values here can vary, of course, depending on the position of the form itself) and therefore the correct location relative to the form when Me.PointToClient is applied (at {X=5,Y=32}).

The very next lines do the same calculations for Label2 (remember, same Parent, same Y-value within the parent (6)), but the results are totally off: ctl.Parent.PointToScreen() gives me {X=1114,Y=63}. X is almost correct (959-4+163=1118), but Y is nowhere near the 119 I got for Label1. And then ctl.PointToScreen() gives me {X=166,Y=29} - translated back to Form-Coordinates (Me.PointToClient) {X=-784,Y=-2}.

These numbers are calculated and printed to the debug window directly after each other, without moving anything around... Madness.

OK, this is getting rather messy, but I still hope someone has a simple explanation. Thanks!

A: 

I think it's the sleep. :) Instead of:

ctl.PointToScreen(Point.Empty)

ctl.Parent.PointToScreen(ctl.Location)

try:

ctl.PointToScreen(Point.Empty)

ctl.PointToScreen(ctl.Location) // Note no .Parent!

instead and you'll see the difference in the x/y coordinates.

Also, try using Control.TopLevelControl or Control.FindForm() to get the outermost Form when doing your PointToScreen math.

micahtan
ctl.PointToScreen(ctl.Location) // Note no .Parent! is definitely wrong, because it adds ctl.location as an offset, which is something I don't want. My methods do at least give me the correct coordinates. Your other suggestion of using TopLevelControl or FindForm is good, except that in this special case I really don't want the top level control; I'm actually looking for the position within another container.
Tom Juergens
+1  A: 

OK, I found the solution.

I happened to be calling Control.PointToScreen before the control was created: Control.IsHandleCreated = False.

If I ensure that the control is created first (Control.CreateControl) both methods work equally well.

The reason I had differing results on subsequent calls is that the first call to Control.PointToScreen also causes the control to be created (and therefore its parent and any other controls sited on the parent), meaning the second succeeds.

Well, I'm sure glad to be done with this :-)

Tom Juergens