Given a child object in nested containers, how to get a container's coordinates of where the child is within itself

I'm using Flex, but I think this question applies to anyone who is well-versed in Actionscript, which means you could be using Flash or Flex.

Let's say ContainerA has a child which is also a container, which we'll call ContainerB. Now ContainerB has a child which is not a container, which we'll call Child. So ContainerA contains ContainerB, which in turn contains Child.

If I get Child's x,y coordinates, I will get its position within ContainerB. But what if I want its position within ContainerA instead? How do i get that?

Any help on this would be immensely appreciated. Thanks.
elepilAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CarnouCommented:
var child_pt:Point = new Point( Child.x, Child.y );
var global_pt:Point = Child.localToGlobal( child_pt );
var container_a_frame:Point = ContainerA.globalToLocal( global_pt );
That should do it!  Good luck!
CarnouCommented:
Oh...
import flash.geom.Point;
if you need it.
elepilAuthor Commented:
Carnou, thanks for responding.

That is exactly how I was doing it, but it wasn't working. I kept on getting negative coordinates. You see, I needed the coordinates for ContainerA so I could set the scroll bars of ContainerA to approximately where the child was.
Expert Spotlight: Joe Anderson (DatabaseMX)

We’ve posted a new Expert Spotlight!  Joe Anderson (DatabaseMX) has been on Experts Exchange since 2006. Learn more about this database architect, guitar aficionado, and Microsoft MVP.

elepilAuthor Commented:
Actually, the results seem to change. Here is my actual code:

      var ptChild:Point = new Point(theChild.x, theChild.y);
trace("ptChild=" + ptChild);
      var ptGlobal:Point = theChild.localToGlobal(ptChild);
trace("ptGlobal=" + ptGlobal);
      var ptCanvas:Point = canvas.globalToLocal(ptGlobal);
trace("ptCanvas=" + ptCanvas);

The result I get is:

ptChild=(x=0, y=0)
ptGlobal=(x=192, y=50)
ptCanvas=(x=0, y=0)

ptCanvas is what's important to me, and I keep getting zeroes now, no matter which child I try to convert coordinates for.
elepilAuthor Commented:
Carnou, I think I know why the result of ptCanvas is always the same. It's because ptChild will always be 0,0. This causes ptGlobal to always come up with 192,50 (which could change depending on the stage).

In other words, if ptChild always produces 0,0, won't the operation always come up with the same results?
CarnouCommented:
Ok, first of all, I'm taking it that canvas correlates to "Container A" from the initial question.  If it's "Container B," then yeah, all you did was f'(f(x)), so you'll always get the same answer.
Your result would tell me that you have theChild nestled in the top left of Container B, which is nestled in the top left corner of canvas.
No matter where theChild is located within canvas, you'll get the same result each time you run, unless theChild or ContainerB is moving.  You should only get {0,0} if all your DisplayObjects are nestled together in the top left corner.
Of course, if you're looking for the mouse location, this will change with the location of the mouse.  Then you simply pass the global mouse coordinates into canvas's globalToLocal.
I remember having similar issues in one of my projects dealing with globalToLocal and localToGlobal.  Let me look around, and I'll see what I did as a solution/fix/realization, though it may take half a day before I get to report back.
elepilAuthor Commented:
Carnou, it might help to give you an idea what I'm trying to do. My post talks about ContainerA, ContainerB, and a Child. The reality is that ContainerA is a Canvas, ContainerB is a mx:Grid, and Child could be in any mx:GridItem within any mx:GridRow. My application allows users to create office appointments which are represented by VBoxes that are created inside the mx:Grid. An appointment can appear anywhere within the mx:Grid, depending on the time the appointment was set for. It is therefore my goal to move the scroll bar thumb position to make a newly set appointment appear at the approximate the center of the user's viewable area. But in order to be able to calculate the scroll thumb position, I need to know the x,y coordinates of the newly set appointment, and that's where I'm stuck.

So you see, mouseX and mouseY are not applicable here because when an appointment is created, it just appears without the user even getting a chance to click it yet. But I am able to get a reference to the newly added appointment, but that's all I have to work with.
CarnouCommented:
Thanks, elipii, that gives me some ideas that may help you:
You said, "child can be in any mx:GridItem within any mx:GridRow".  From this, I hear that the parent of Child is not ContainerB, but an mxGridItem.  That's great!  That explains why you always get 0,0.  Within the gridItem, the VBox is always placed at {0,0}.  So your question isn't "what's the x,y of the VBox", but "what's the x,y of the gridItem within the grid?"
That means you don't want "Child.x" and "Child.y", but "Child.parent.x" and "Child.parent.y".  You may possibly want some other parent, as well.  If you only get {0,0} for Child.parent.x, keep climbing the parent tree till you get a non-zero x,y.  Not to self-promote my article TOO much, but I wrote an aritcle that may help: http://www.experts-exchange.com/Software/Photos_Graphics/Web_Graphics/Macromedia_Flash/ActionScript/A_2517-Finding-a-DisplayObject-at-any-depth-of-the-AS3-Display-List.html .  It will tell you of any hidden levels of DisplayObject you don't know about.
Additionally, websites like http://www.actionscript.org/forums/showthread.php3?t=166687 tell me that I gave you some wrong advice up top.  You didn't want child.localToGlobal(), you wanted child.parent.localToGlobal().  Since the x, y are relative to the parent, you want to run localToGlobal on the parent.
So, currently my guess - assuming there are no other interceding DisplayObjects - is that you want the original lines to look more like this:
var ptChildParent:Point = new Point(theChild.parent.x, theChild.parent.y);
trace("ptChildParent=" + ptChildParent);
      var ptGlobal:Point = theChild.parent.parent.localToGlobal(ptChildParent);
trace("ptGlobal=" + ptGlobal);
      var ptCanvas:Point = canvas.globalToLocal(ptGlobal);
trace("ptCanvas=" + ptCanvas);
Does that make sense?  And more importantly, does that work?  *:-]
elepilAuthor Commented:
Carnou, what you said all makes a lot of sense. But my results don't make sense.

I did:

trace(theChild.parent is GridItem);
var ptChildParent:Point = new Point(theChild.parent.x, theChild.parent.y);
trace("ptChildParent=" + ptChildParent);

true
ptChildParent=(x=0, y=0)

Then I tried:

trace(theChild.parent is GridRow);
var ptChildParent:Point = new Point(theChild.parent.parent.x, theChild.parent.parent.y);
trace("ptChildParent=" + ptChildParent);

I got:

true
ptChildParent=(x=0, y=0)

The above results do not make sense at all. I did all my trace statements AFTER the canvas.addChild(grid), too, so the mx:Grid is already in the DisplayList.

I can think of only one reason why this could be so. Maybe the coordinates within the objects have somehow not been updated yet and still have their original values of 0,0??? If that is the case, I don't know where to capture the coordinates anymore. I am tending to think that all objects should've already been created, the Flex layouting algorithm has already executed, and that the coordinates should now have the correct values. But they don't seem to be so.

In your opinion, isn't putting the trace statements RIGHT AFTER the canvas.addChild(grid) a good place to put them?
CarnouCommented:
Hey, elepil,
Unfortunately, everything you've said makes perfect sense (assuming your trace(theChild.parent is GridRow); really says trace(theChild.parent.parent is GridRow); ).  I'm not certain of anything in Flex - all of my AS3 experience is in Flash.  The best I can suggest is dumping the display list with that routine in my article (or tweaking it to show x and y), and maybe you'll get some ideas.
I'm pretty much past the point of my expertise and resorting to looking up functions within the Grid class.  (You'd think there'd be a way to find out where in the grid your grid item is, without going through all this mess in the first place.)  Two things that jump out at me when I look at (inherited) public methods are: validateNow - easy way to make sure that all the layout is up-to-date, and getLayouBoundsX (and Y).  I've never used it before, but maybe it will help.
Here's an idea to avoid the issue.  Assuming the Grid has nothing but GridRows in it, and each GridRow has nothing but GridItems, this should do some useful magic:
var item:GridItem = theChild.parent;
var row:GridRow = item.parent;
var grid:Gird = row.parent;
/*
  NOTE: the following 6 lines could simply be replaced with
   var column_index:int = row.getChildIndex( item )
  if you could guarantee that the colspan for each GridItem is 1.
*/
var idx:int = row.getChildIndex( item );
var column_index:int = 0;
for (var i:int = 0; i < idx; ++i)
{
  column_index += (row.getChildAt( i ) as GridItem).colSpan;
}
var row_index:int = grid.getChildIndex( row );
That's untested pseudocode, but you get the idea.  If I can't answer the x,y issue you're having, maybe I can successfully help you avoid it.  If you can properly find the column_index and row_index, I know you can find the row_height and column_width from the grid, and the total number of columns, and you should be in good shape.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
elepilAuthor Commented:
Thanks for all your help, I'll try to figure this out somehow.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Adobe Flash

From novice to tech pro — start learning today.