Skip to main content

[JAVA2D] Anyone got TextLayout adn TextHitInfo to work

3 replies [Last post]
Anonymous

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Doug Felt

Gregory:

The following paragraph from the class documentation for TextLayout is
pertinent:

"All graphical information returned from a TextLayout
object's methods is relative to the origin of the
TextLayout, which is the intersection of the
TextLayout> object's baseline with its left edge. Also,
coordinates passed into a TextLayout object's methods
are assumed to be relative to the TextLayout object's
origin. Clients usually need to translate between a
TextLayout object's coordinate system and the coordinate
system in another object Graphics object)."

The bounds argument to hitTestChar does not tell the call where the origin
of the TextLayout is. The bounds serves to determine whether a hit is
within the line or outside of it, and thus either before the first or after
the last logical character. (In previous releases the bounds also affected
the angle and position of carets on an italic/non-italic boundary, and thus
which character a particular point would be associated with. I believe
this latter behavior is no longer true in 1.5-- hit-testing was reworked
to deal with superscripts and subscripts-- but I need to check.)

So in your case, you need to subtract the origin at which you are rendering
the TextLayout from the x,y coordinate that you are hit testing it with, so
that the point is relative to the left/baseline of the TextLayout. If you
need to provide a different bounds from the TextLayout's default bounds,
that too should be relative to the left/baseline of the TextLayout.

Doug

At 06:54 PM 9/2/2004, Gregory Pierce wrote:
>---------------------- Information from the mail header
>-----------------------
>Sender: Discussion list for Java 2D API
>Poster: Gregory Pierce
>Subject: Anyone got TextLayout adn TextHitInfo to work
>-------------------------------------------------------------------------------
>
>Okay, here's the deal. I'm having some trouble getting TextHitInfo to return
>me valid data.
>
>I have a TextLayout that I'm drawing centered within another component
>using:
>
> textLayout.draw( g2d, (int)(bounds.getMinX() +
>bounds.getWidth()/2 - stringWidth/2), (int)(bounds.getMinY() +
>bounds.getHeight()/2 + stringHeight/2) );
>
>
>Where bounds is the bounding box of the containing object. This works great.
>The text is centered in my object.
>
>Next I try to actually perform a hit test on the text by performing:
>
> Rectangle2D hitBounds = new Rectangle2D.Double(
>textLayoutBounds.getMinX() + bounds.getMinX(),
>
>textLayoutBounds.getMinY() + bounds.getMinY(),
>
>textLayoutBounds.getWidth(),
>
>textLayoutBounds.getHeight() );
>
> textHitInfo = textLayout.hitTestChar( x, y, hitBounds );
>
>I create my own hitbounds because after confinued testing, the
>textLayout.getBounds always remains at x=0, y=0 which is just wrong and is a
>bug that I will report shortly. The bounds of the textLayout aren't at the
>origin - they never are.
>
>4508 [AWT-EventQueue-0] DEBUG PanelWidget -
>java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=56.0,h=8.0]
>4510 [AWT-EventQueue-0] DEBUG PanelWidget - x 223,161, bounds:
>java.awt.geom.Rectangle2D$Double[x=171.0,y=132.0,w=56.0,h=8.0]
>4511 [AWT-EventQueue-0] DEBUG PanelWidget - Hit text - insert at = 8
>
>Moving on. When I perform the hit test, I'm never getting the right
>character insert position (hitInfo.getInsertionIndex()) unless the text is
>sitting at the origin.
>
>
>Any ideas?
>
>===========================================================================
>To unsubscribe, send email to listserv@java.sun.com and include in the body
>of the message "signoff JAVA2D-INTEREST". For general help, send email to
>listserv@java.sun.com and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Gregory Pierce

I see, so I need to transform the (x,y) coordinates given to me my
MouseEvent -> (x - TextLayout.x, y - TextLayout.y). So basically what
I'm doing is performing the hit test as if the TextLayout was at the
origin. Now I understand why it does what it does. I will adjust my
code and make sure that works. Thank you so very much - this was
driving me nuts and I'd gone through JFC 2D Graphics and Imaging as
well as the Java Tutorial at least 15 times trying to make some sense
of it. The only thing I could tell was that the hit always seemed to
take place at (0,0) origin but that just didn't seem to make any sense
whatsoever. This might also explain why the bounds for the TextLayout
ALWAYS comes back with x and y = 0 as opposed to the x,y of the origin
of the TextLayout.

Having said that let me express that that is about as intuitive as
quantum physics. It seems to me that it would have made more sense for
the TextLayout (which should already know its origin x,y within screen
space) to perform that operation itself such that you could have just
done a normal hit with the x,y from the MouseEvent. That would be the
normal use case as best I'm able to determine.

I guess I need to fill out a request for enhancement because I just
imaging people waiting to operate from either screen space coordinates
or some normalized coordinate system - not having to do something
special for a TextLayout. It breaks the cleanness to have to treat
TextLayouts different from other arbitrary bounded shapes. It is also
bizarre for the TextLayout.getBounds() to return its origin as (0,0)
all the time. That just doesn't make a lot of sense to me and its
different from all the other Shape objects as well. :)

On Thu, 02 Sep 2004 23:17:53 -0700, Doug Felt wrote:
> Gregory:
>
> The following paragraph from the class documentation for TextLayout is
> pertinent:
>
> "All graphical information returned from a TextLayout
> object's methods is relative to the origin of the
> TextLayout, which is the intersection of the
> TextLayout> object's baseline with its left edge. Also,
> coordinates passed into a TextLayout object's methods
> are assumed to be relative to the TextLayout object's
> origin. Clients usually need to translate between a
> TextLayout object's coordinate system and the coordinate
> system in another object Graphics object)."
>
> The bounds argument to hitTestChar does not tell the call where the origin
> of the TextLayout is. The bounds serves to determine whether a hit is
> within the line or outside of it, and thus either before the first or after
> the last logical character. (In previous releases the bounds also affected
> the angle and position of carets on an italic/non-italic boundary, and thus
> which character a particular point would be associated with. I believe
> this latter behavior is no longer true in 1.5-- hit-testing was reworked
> to deal with superscripts and subscripts-- but I need to check.)
>
> So in your case, you need to subtract the origin at which you are rendering
> the TextLayout from the x,y coordinate that you are hit testing it with, so
> that the point is relative to the left/baseline of the TextLayout. If you
> need to provide a different bounds from the TextLayout's default bounds,
> that too should be relative to the left/baseline of the TextLayout.
>
> Doug
>
> At 06:54 PM 9/2/2004, Gregory Pierce wrote:
> >---------------------- Information from the mail header
> >-----------------------
> >Sender: Discussion list for Java 2D API
> >Poster: Gregory Pierce
> >Subject: Anyone got TextLayout adn TextHitInfo to work
> >-------------------------------------------------------------------------------
>
>
> >
> >Okay, here's the deal. I'm having some trouble getting TextHitInfo to return
> >me valid data.
> >
> >I have a TextLayout that I'm drawing centered within another component
> >using:
> >
> > textLayout.draw( g2d, (int)(bounds.getMinX() +
> >bounds.getWidth()/2 - stringWidth/2), (int)(bounds.getMinY() +
> >bounds.getHeight()/2 + stringHeight/2) );
> >
> >
> >Where bounds is the bounding box of the containing object. This works great.
> >The text is centered in my object.
> >
> >Next I try to actually perform a hit test on the text by performing:
> >
> > Rectangle2D hitBounds = new Rectangle2D.Double(
> >textLayoutBounds.getMinX() + bounds.getMinX(),
> >
> >textLayoutBounds.getMinY() + bounds.getMinY(),
> >
> >textLayoutBounds.getWidth(),
> >
> >textLayoutBounds.getHeight() );
> >
> > textHitInfo = textLayout.hitTestChar( x, y, hitBounds );
> >
> >I create my own hitbounds because after confinued testing, the
> >textLayout.getBounds always remains at x=0, y=0 which is just wrong and is a
> >bug that I will report shortly. The bounds of the textLayout aren't at the
> >origin - they never are.
> >
> >4508 [AWT-EventQueue-0] DEBUG PanelWidget -
> >java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=56.0,h=8.0]
> >4510 [AWT-EventQueue-0] DEBUG PanelWidget - x 223,161, bounds:
> >java.awt.geom.Rectangle2D$Double[x=171.0,y=132.0,w=56.0,h=8.0]
> >4511 [AWT-EventQueue-0] DEBUG PanelWidget - Hit text - insert at = 8
> >
> >Moving on. When I perform the hit test, I'm never getting the right
> >character insert position (hitInfo.getInsertionIndex()) unless the text is
> >sitting at the origin.
> >
> >
> >Any ideas?
> >
> >===========================================================================
> >To unsubscribe, send email to listserv@java.sun.com and include in the body
> >of the message "signoff JAVA2D-INTEREST". For general help, send email to
> >listserv@java.sun.com and include in the body of the message "help".
>
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Gregory Pierce

Much thanks to Doug Felt at Sun for helping me out with thist! Man
this was driving me nuts. Doug I own you one of whatever drink you
want whenever I see you - I'm serious! This area of code was driving
me INSANE. I couldn't take it anymore :)

Anyways, what I had to do was take the x, y where the hit was taking
place and subtract the (x,y) that is the origin of the TextLayout that
I want to check against. The TextLayout hit testing does NOT take
place in the same coordinate space as screen space. Yeah, confused the
hell out of me too. It would be nice if there was just an additional
method that took the screen space coordinate and gave back the right
thing since most people will be clearly performing the check in screen
space. Anyways, my changed code looks like

fontX = (int)(bounds.getMinX() + bounds.getWidth()/2 - stringWidth/2);
fontY = (int)(bounds.getMinY() + bounds.getHeight()/2 + stringHeight/2);
textLayout.draw( g2d, fontX, fontY );

public void onClick( int x, int y )
{
textHitInfo = textLayout.hitTestChar( x -fontX, y -fontY );

if ( textHitInfo != null )
{
logger.debug("Hit text - insert at = " +
textHitInfo.getInsertionIndex() );
}
}

Note that the bounds that I was previously using is completely
unnecessary and used by Java2D/TextLayout for something entirely
different.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".