This lesson explains how to draw simple and complex styled text using the
java.awt.font.TextLayout
class to create interesting
and pleasing visual effects.
Draw a Line of Text
The java.awt.font.TextLayout
class lets you create styled
text from combinations of strings, fonts, and attribute sets. Once
created, a TextLayout
object cannot be edited, but its
methods give you access to layout, font, caret, selection, and hit test
information.
The following code uses Font
, TextLayout
, and
FontRenderContext
objects to draw a simple text string in 24
point Times Bold. Here is the complete TimesB.java
source code.
FontRenderContext frc = g2.getFontRenderContext();
Font f = new Font("Helvetica",Font.BOLD, 24);
String s = new String("24 Pont Helvetica Bold");
TextLayout tl = new TextLayout(s, f, frc);
Dimension theSize=getSize();
g2.setColor(Color.green);
tl.draw(g2, theSize.width/30, theSize.height/2);
Java.awt.Font
represents an instance of a
font face from the available system fonts.
java.awt.TextLayout
represents unchangeable
styled character data.
java.awt.font.FontRenderContext
contains the information
needed to correctly measure and position text when it is drawn.
Draw Multiple Lines of Text
You can use the TextLayout
and java.awt.LineBreakMeasurer
classes to draw a paragraph of styled text. This next example uses a
LineBreakMeasurer
object to create and draw lines of text
(text layouts) that fit within the component's width. Information
about the font returned by the TextLayout
getAscent
and
getDescent
methods is used to position the lines in the component.
The text is stored as an AttributedCharacterIterator
so the font and point size attributes can be stored with the text.
Here is the complete source code for the
LineBreakSample.java
example. The SampleUtils.java
class contains the text displayed by the LineBreakSample
application.
Note:
The LineBreakSample
application supports foreign language
text. See Lesson 4: Foreign Language Support
for more information.
public class LineBreakSample extends Component {
private LineBreakMeasurer lineMeasurer;
private int paragraphStart;
private int paragraphEnd;
public LineBreakSample
(AttributedCharacterIterator paragraph) {
FontRenderContext frc =
SampleUtils.getDefaultFontRenderContext();
paragraphStart = paragraph.getBeginIndex();
paragraphEnd = paragraph.getEndIndex();
lineMeasurer =
new LineBreakMeasurer(paragraph, frc);
}
public void paint(Graphics g) {
Graphics2D graphics2D = (Graphics2D) g;
Dimension size = getSize();
float formatWidth = (float) size.width;
float drawPosY = 0;
lineMeasurer.setPosition(paragraphStart);
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout =
lineMeasurer.nextLayout(formatWidth);
drawPosY += layout.getAscent();
float drawPosX;
if (layout.isLeftToRight()) {
drawPosX = 0;
}
else {
drawPosX = formatWidth - layout.getAdvance();
}
layout.draw(graphics2D, drawPosX, drawPosY);
drawPosY += layout.getDescent() +
layout.getLeading();
}
}
A New Slant on Text
You can create a Font
object from a transform
object that provides information on how to
rotate, scale, move, or shear the font. This next example
uses a shear transformation to draw slanted text. First, the
string is drawn without the transform, and then it is drawn
in a different location with it. Here is the complete
StillLife.java source code.
int w = getSize().width;
int h = getSize().height;
//Create transforms
AffineTransform at = new AffineTransform();
at.setToTranslation(30, 50);
AffineTransform fontAT = new AffineTransform();
fontAT.shear(0.2, 0.0);
//Create fonts and text layouts
FontRenderContext frc = g2.getFontRenderContext();
Font theFont = new Font("Times", Font.BOLD, w/25);
String s = new String("Still Life with Text");
TextLayout tstring = new TextLayout(s, theFont, frc);
Font theDerivedFont = theFont.deriveFont(fontAT);
String str = new String("Still Life with Slanted Text");
TextLayout tstring2 = new TextLayout(str,
theDerivedFont, frc);
//Draw regular string
g2.setColor(Color.blue);
g2.transform(at);
tstring.draw(g2, (float)0, (float)0);
//Draw string with shear transformation on the font
g2.setColor(Color.green);
g2.transform(at);
tstring2.draw(g2, (float)0, (float)0);
Filling a Clipping Area with an Image
This next example creates a clipping area from the text string
The Starry Night, and uses Vincent van Gogh's painting,
The Starry Night, to fill the clipping area. Here is the
complete Starry.java source code.
The example code creates a text layout with
the string The Starry Night in Times Bold. Next, it
gets the width of the TextLayout
bounds.
The bounds
contains all the pixels the layout can draw.
Then, it gets the outline of
the text layout and uses the width of the bounds to calculate the
X and Y positions for the origins of the layout. The outline is
used to create a Shape
object, and a Rectangle
object is created from the bounds of the Shape
object.
At this point, the graphics context color is set to blue
and the Shape
object is drawn into the graphics context.
The image and code segment below show what has happened
so far.
FontRenderContext frc = g2.getFontRenderContext();
Font f = new Font("Times",Font.BOLD,w/10);
String s = new String("The Starry Night");
TextLayout tl = new TextLayout(s, f, frc);
float sw = (float) tl.getBounds().getWidth();
AffineTransform transform = new AffineTransform();
transform.setToTranslation(w/2-sw/2, h/4);
Shape shape = tl.getOutline(transform);
Rectangle r = shape.getBounds();
g2.setColor(Color.blue);
g2.draw(shape);
Lastly, a clipping area is set on the graphics context using
the Shape
object, and the starry.gif
image is drawn into the clipping area starting at the lower-left
corner of the Rectangle
object (r.x
and
r.y
) and filling the full height and width of the
Rectangle object.
g2.setClip(shape);
g2.drawImage(img, r.x, r.y, r.width, r.height, this);
Filling a Clipping Area with Lines
For a slightly different effect, this next example creates a clipping
area from the text layout By, fills the clipping area with blue,
and draws yellow lines across the clipping area over the blue fill.
Information returned by the TextLayout
getAscent
method
is used to position the line on the display.
Here is the complete
Clipping.java source code.
FontRenderContext frc = g2.getFontRenderContext();
Font f = new Font("Helvetica",Font.BOLD,w/8);
String s = new String("By");
TextLayout tl = new TextLayout(s, f, frc);
float sw = (float) tl.getBounds().getWidth();
AffineTransform transform = new AffineTransform();
transform.setToTranslation(w/2-sw/2,h/2);
Shape shape = tl.getOutline(transform);
g2.setClip(shape);
g2.setColor(Color.blue);
g2.fill(shape.getBounds());
g2.setColor(Color.yellow);
for (int j = shape.getBounds().y;
j < shape.getBounds().y +
shape.getBounds ().height; j=j+3) {
Line2D line = new Line2D.Float( 0.0f, (float) j,
(float) w, (float) j);
g2.draw(line);
}
Filling a Clipping Area with Characters
This next example creates a clipping area from the text
layout Vincent van Gogh, fills it with blue, and
draws white asterisks (*) into the clipping area over the
blue fill to give the effect of white stars in a blue sky.
Here is the complete
TextClipping.java source code.
FontRenderContext frc = g2.getFontRenderContext();
Font f =
new Font("Times New Roman Bold",Font.PLAIN,w/8);
String s = new String("Vincent van Gogh");
TextLayout tl = new TextLayout(s, f, frc);
float sw = (float) tl.getBounds().getWidth();
AffineTransform transform = new AffineTransform();
transform.setToTranslation(w/2-sw/2,h-h/6);
Shape shape = tl.getOutline(transform);
g2.setClip(shape);
g2.setColor(Color.blue);
g2.fill(shape.getBounds());
g2.setColor(Color.white);
f = new Font("Helvetica",Font.BOLD,10);
tl = new TextLayout("+", f, frc);
sw = (float) tl.getBounds().getWidth();
Rectangle r = shape.getBounds();
int x = r.x;
int y = r.y;
while ( y < (r.y + r.height+(int) tl.getAscent()) ) {
tl.draw(g2, x, y);
if ((x += (int) sw) > (r.x+r.width)) {
x = r.x;
y += (int) tl.getAscent();
}
}
Text Attributes and Replacement Graphics
The TextAttribute
class defines text attributes so
you can define an Attributed
string with text
attributes. This next example uses text attributes to define
the font and a character replacement image for the
java.awt.text.AttributedString
that contains the
text The Starry Night. An ImageGraphicAttribute
is created from an image to do this.
Here is the complete
MakeImage.java source code.
public void paint(Graphics g) {
Graphics2D g2;
g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
Font f = new Font("Times",Font.BOLD, 24);
AttributedString ats =
new AttributedString("The Starry Night");
ImageGraphicAttribute iga =
new ImageGraphicAttribute(img,
(int) BOTTOM_ALIGNMENT);
ats.addAttribute(
TextAttribute.CHAR_REPLACEMENT, iga, 4, 5);
ats.addAttribute(
TextAttribute.CHAR_REPLACEMENT, iga, 11, 12);
ats.addAttribute(TextAttribute.FONT, f, 0, 18);
AttributedCharacterIterator iter = ats.getIterator();
FontRenderContext frc = g2.getFontRenderContext();
tl = new TextLayout(iter, frc);
g2.setColor(Color.red);
tl.draw(g2, (float)20, (float)30);
}