Positioning ToolTips

When you use the ToolTipManager to create a custom ToolTip, you specify the coordinates of the ToolTip on the stage. You do this by specifying the values of the x and y parameters of the new ToolTip in the createToolTip() method. These coordinates are relative to the stage. For example, a value of 0,0 creates a ToolTip at the top left corner of the application.

In some cases, you might not know the exact position that you want the ToolTip to be drawn in; instead, you want the location of the ToolTip to be relative to the target component (the component that has a ToolTip on it). In those cases, you can use the location of the target component to calculate the values of these coordinates. For example, if you want the ToolTip to appear to a component’s right, then you set the ToolTip’s x position to be the x position of the component plus the component’s width, plus some other value for an offset.

You also set the value of the ToolTip’s y position to be the same as the target component’s y position to line the two up horizontally.

One way to get the necessary values so that you can calculate the x position of the ToolTip, is to use an event handler. Event objects passed to an event handler can give you the x position of the target component and the width of the target component.

The following example gets the value of the current target’s x, y, and width properties in the focusIn event handler, and uses them to position the ToolTip. In this case, the current target is the TextInput control, and the ToolTip appears to its right with a 10 pixel offset.

The previous example creates a ToolTip on a target component that is not inside any containers. However, in many cases, your components will be inside layout containers such as a VBox or an HBox. Under these circumstances, the coordinates you access in the event handler will be relative to the container and not the main application. But the ToolTipManager expects global coordinates when positioning the ToolTip. This will position ToolTips in unexpected locations.

To avoid this, you can use the contentToGlobal() method to convert the coordinates in the event handler from local to global. All components that subclass UIComponent have this method. It takes a single Point that is relative to the target’s enclosing container as an argument and returns a Point that is relative to the stage.

The following example calls the TextInput control’s contentToGlobal() method to convert the control’s coordinates from those that are relative to the VBox container to global coordinates.

Here’s a ZIP file with the source code from this blog entry.

7 Responses to Positioning ToolTips

  1. John says:

    This is a helpful tutorial, but I have a question about nested containers. Specifically, on the contentToGlobal(); it works when you’ve got something in ONE Box-type container (or any container that doesn’t use absolute positioning) that resides inside the application root. But when you nest a box container inside another box container then call contentToGlobal() on anything inside that inner box, everything gets knocked out of whack. I don’t know how to post code in these comments, but you can see what I mean if you run my modified version of your PlacingToolTipsInContainers.mxmlI’ve never been able to figure out how to get around this issue.

  2. Ted Hartnell says:

    I’ve also been trying to use the ToolTip Manager to create custom ToolTips. And, like the poster John, I got stuck at the section “Positioning custom ToolTips”.In frustration I wrote this code below to find the global screen location of a control from a mouseOver or FocusIn event. It seems to work fine – even when you scrunch up the containers and the browser with horizontal and vertical scrollbars. I’d be interested in getting feedback on how this solution might be improved upon.private function setLocation(event:Event):void {var point:Point = new Point(event.currentTarget.x, event.currentTarget.y);var ancestor:DisplayObject = event.currentTarget.parent;var mousePointContent:Point;var mousePointContentToLocal:Point;// Manually convert the location of the point from the local coordinate system to the global coordinate system by iterating up the display list and adjusting for each containerwhile (ancestor != ancestor.stage) {point.x += ancestor.x;point.y += ancestor.y;if (ancestor.parent != ancestor.stage) {mousePointContent = new Point(UIComponent(ancestor).contentMouseX, UIComponent(ancestor).contentMouseY);mousePointContentToLocal = UIComponent(ancestor).contentToLocal(mousePointContent);point.x = point.x + mousePointContentToLocal.x – mousePointContent.x;point.y = point.y + mousePointContentToLocal.y – mousePointContent.y;}ancestor = ancestor.parent;}location.x = point.x;location.y = point.y;}

  3. Jordan says:

    Just to shed some light on the above comments; I was having this problem too – then I read this blog (specifically the first couple of comments);http://rjria.blogspot.com/2008/05/localtoglobal-vs-contenttoglobal-in.htmlBasically, the problem is defining the right ‘co-ordiante space’ when you call ‘contentToGlobal().’In the example posted by John – ‘PlacingToolTipsInContainers.mxml’ he has the following code;————var pt:Point = new Point( event.currentTarget.x, event.currentTarget.y );pt = event.currentTarget.contentToGlobal(pt);————-But this will only work if the object is at 0,0 of the parent.Here’s an example of why this doesn’t work otherwise – draw this out if can..- say your object’s parent is at x=10, y=0 in the application- say your object is at; x=5, y=0 in its’ parentThis means that your object is at; x=15, y=0 in the application – correct?So now, when you call object.contentToGlobal(10,0) what you’re saying is you want the object’s co-ordinate in GLOBAL space PLUS the object’s co-ords in it’s PARENT’S SPACE! Looking at the numbers above, the x co-ord would turn out to be;result.x = (object x in global space) + (object x in parent’s space ) = 15 + 5 = 20This is obviously wrong! You can see that all you REALLY need is object’s global location..————event.currentTarget.contentToGlobal( new Point(0,0,) );————OR equivalently;————var pt:Point = new Point( event.currentTarget.x, event.currentTarget.y);pt = event.currentTarget.PARENT.contentToGlobal(pt);————-Why are they equivalent? Because ( object’s position in GLOBAL space ) == ( its’ PARENT’s postion in GLOBAL space + OBJECT’s position in its’ PARENTs co-ord space)

  4. Mark says:

    THANK YOU JORDAN! That works beautifully!

  5. prith says:

    Hi,

    In my app , I am having a datatiprenderer to display the tool tip in a barchart , the requirement is to get the tooltip in the extreme left no matter where the user hovers on the bar, how do i acheive this ..help !!

  6. prith says:

    also note that the datatiprenderer is a canvas container which draws my tooltip with certain custom values.

  7. John laPlante says:

    Fantastic Jordan! This is such a Flash kind of mixup where things get confusing when relative to a parent or not. You’d think they’d write that method differently or at least document the basis for calculating the position.