The java.awt.font.TextLayout
class lets you respond
to end user mouse clicks or keyboard inputs by displaying
cursors and highlight regions in the styled text at specified
locations. This lesson explains how.
The samples in this lesson support foreign language text. In the source there is code for strong and weak carets, which appear in bidirectional foreign language text. See Lesson 4: Foreign Language Support for more information.
Hit testing is mapping a graphical location on the display
to a character position in the source text. The graphical
location is often determined by end user
mouse inputs or keyboard selections, and is
represented by a caret. A TextLayout
object
provides default caret shapes including angled carets for
italic and oblique glyphs. If you want to use your own
caret shapes, you can retrieve the angle and position of
the default carets from the TextLayout
object
and use that information to draw your own shapes.
This sample application draws the default caret wherever the
end user clicks on the TextLayout
.
The mouseClicked
method uses
TextLayout.hitTestChar
to return a
java.awt.font.TextHitInfo
object that contains the
mouse click location (the insertion index)
in the TextLayout
object.
Information returned by the TextLayout
getAscent
,
getDescent
, and
getAdvance
methods is used to compute the location of the origin for the
TextLayout
object so it is horizontally
and vertically centered.
Here is the complete HitTestSample.java source code.
public void paint(Graphics g) { Graphics2D graphics2D = (Graphics2D) g; Point2D origin = computeLayoutOrigin(); graphics2D.translate(origin.getX(), origin.getY()); textLayout.draw(graphics2D, 0, 0); Shape[] carets = textLayout.getCaretShapes(insertionIndex); graphics2D.setColor(STRONG_CARET_COLOR); graphics2D.draw(carets[0]); if (carets[1] != null) { graphics2D.setColor(WEAK_CARET_COLOR); graphics2D.draw(carets[1]); } } private class HitTestMouseListener extends MouseAdapter { public void mouseClicked(MouseEvent e) { Point2D origin = computeLayoutOrigin(); float clickX = (float) (e.getX() - origin.getX()); float clickY = (float) (e.getY() - origin.getY()); TextHitInfo currentHit = textLayout.hitTestChar(clickX, insertionIndex = currentHit.getInsertionIndex(); repaint(); } }
A TextLayout
object supports highlighting the
entire length or portion of a text string on the screen. In this
example, the text string draws with caret at the
beginning of the line. The end user can drag the mouse from
there or click somewhere else and drag to highlight the characters.
The
code uses theTextLayout.hitTestChar.
and
TextLayout.getLogicalHighlightShape
to compute the
endpoint and get a Shape
that
represents the highlight region.
Here is the complete SelectionSample.java source code.
public void paint(Graphics g) { Graphics2D graphics2D = (Graphics2D) g; Point2D origin = computeLayoutOrigin(); graphics2D.translate(origin.getX(), origin.getY()); boolean haveCaret = anchorEnd == activeEnd; if (!haveCaret) { Shape highlight = textLayout.getLogicalHighlightShape( anchorEnd, activeEnd); graphics2D.setColor(HIGHLIGHT_COLOR); graphics2D.fill(highlight); } graphics2D.setColor(TEXT_COLOR); extLayout.draw(graphics2D, 0, 0); if (haveCaret) { Shape[] carets = textLayout.getCaretShapes(anchorEnd); graphics2D.setColor(STRONG_CARET_COLOR); graphics2D.draw(carets[0]); if (carets[1] != null) { graphics2D.setColor(WEAK_CARET_COLOR); graphics2D.draw(carets[1]); } } } private class SelectionMouseMotionListener extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { Point2D origin = computeLayoutOrigin(); float clickX = (float) (e.getX() - origin.getX()); float clickY = (float) (e.getY() - origin.getY()); TextHitInfo position = textLayout.hitTestChar(clickX, clickY); int newActiveEnd = position.getInsertionIndex(); if (activeEnd != newActiveEnd) { activeEnd = newActiveEnd; repaint(); } } } private class SelectionMouseListener extends MouseAdapter { public void mousePressed(MouseEvent e) { Point2D origin = computeLayoutOrigin(); float clickX = (float) (e.getX() - origin.getX()); float clickY = (float) (e.getY() - origin.getY()); TextHitInfo position = textLayout.hitTestChar(clickX, clickY); anchorEnd = position.getInsertionIndex(); activeEnd = anchorEnd; repaint(); } }
A TextLayout
object supports moving through the
text string on the display one character at a time when the
end user presses the left and right arrow keys. In this next
example, an insertion offset is initially set to 0 and moved
by calling TextLayout.getNextRightHit
and
TextLayout.getNextLeftHit
as appropriate in response
to left and right arrow key presses.
Here is the complete ArrowKeySample.java source code.
public void paint(Graphics g) { Graphics2D graphics2D = (Graphics2D) g; Point2D origin = computeLayoutOrigin(); graphics2D.translate(origin.getX(), origin.getY()); textLayout.draw(graphics2D, 0, 0); Shape[] carets = textLayout.getCaretShapes(insertionIndex); graphics2D.setColor(STRONG_CARET_COLOR); graphics2D.draw(carets[0]); if (carets[1] != null) { graphics2D.setColor(WEAK_CARET_COLOR); graphics2D.draw(carets[1]); } } private class ArrowKeyListener extends KeyAdapter { private void handleArrowKey(boolean rightArrow) { TextHitInfo newPosition; if (rightArrow) { newPosition = textLayout.getNextRightHit(insertionIndex); } else { newPosition = textLayout.getNextLeftHit(insertionIndex); } if (newPosition != null) { insertionIndex = newPosition.getInsertionIndex(); repaint(); } } public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT) { handleArrowKey(keyCode == KeyEvent.VK_RIGHT); } }
© 1994-2005 Sun Microsystems, Inc.