Text fonts in Java are represented by instances of the
java.awt.Font
class. A
Font
object is constructed from a name,
style identifier, and a point size. We can create a Font
object at any time, but it’s meaningful
only when applied to a particular component on a given display device.
Here are a couple of fonts:
Font
smallFont
=
new
Font
(
"Monospaced"
,
Font
.
PLAIN
,
10
);
Font
bigFont
=
new
Font
(
"Serif"
,
Font
.
BOLD
,
18
);
Font names come in three varieties: family names, face names (also called font names), and logical names. Family and font names are closely related. For example, Garamond Italic is a font name for a font whose family name is Garamond.
A logical name is a generic name for the font family. The following logical font names should be available on all platforms:
The logical font name is mapped to an actual font on the local platform. Java’s fonts.properties file maps the font names to the available fonts, covering as much of the Unicode character set as possible. If you request a font that doesn’t exist, you get the default font.
One of the big wins in the 2D API is that it can use most of the fonts you have installed on your computer. The following program prints out a full list of the fonts that are available to the 2D API:
//file: ShowFonts.java
import
java.awt.*
;
public
class
ShowFonts
{
public
static
void
main
(
String
[]
args
)
{
Font
[]
fonts
;
fonts
=
GraphicsEnvironment
.
getLocalGraphicsEnvironment
().
getAllFonts
();
for
(
int
i
=
0
;
i
<
fonts
.
length
;
i
++)
{
System
.
out
.
(
fonts
[
i
].
getFontName
()
+
" : "
);
System
.
out
.
(
fonts
[
i
].
getFamily
()
+
" : "
);
System
.
out
.
(
fonts
[
i
].
getName
());
System
.
out
.
println
();
}
}
}
Note, however, that the fonts installed on your system may not match the fonts installed on someone else’s system. For true portability, you can use one of the logical names (although your application won’t look exactly the same on all platforms) or go with the defaults. Alternatively, you can test for the existence of your preferred font and fall back on a logical font, or you can allow your users to configure the application by choosing fonts themselves.
The static
method Font.getFont()
looks up a
font by name in the system properties list just like Color.getColor()
. And as
with Color.getColor()
, this is
interesting but useless. Normally, you’ll either choose a Font
from one that is available in the
environment (as in the ShowFonts
example) or use identifiers to describe the font you want in the Font
constructor.
The Font
class defines three
static
style identifiers: PLAIN
, BOLD
, and ITALIC
. You can use these
values on all fonts, although some fonts may not provide bold or italic
versions. The point size determines the size of the font on a display. If
a given point size isn’t available, Font
substitutes a default size.
You can retrieve information about an existing Font
with a number of routines. The getName()
, getSize()
, and getStyle()
methods
retrieve the logical name, point size, and style, respectively. You can
use the getFamily()
method to
find out the family name, while getFontName()
returns the
face name of the font.
Finally, to actually use a Font
object, you can simply specify it as an argument to the setFont()
method of a
Component
or Graphics2D
object. Subsequent text drawing
commands such as drawString()
for that
component or in that graphics context use the specified font.
To get detailed size and spacing information for text rendered in
a font, we can ask for a java.awt.font.LineMetrics
object. Different
systems have different real fonts available; the available fonts may not
match the font you request. Furthermore, the measurements of different
characters within a single font may be different, especially in
multilingual text. Thus, a LineMetrics
object presents information about
a particular set of text in a particular font on a particular system,
not general information about a font. For example, if you ask for the
metrics of a nine-point Monospaced
font, what you get isn’t some abstract truth about Monospaced
fonts; you get the metrics of the
font that the particular system uses for nine-point Monospaced
—which may not be exactly nine
points or even fixed width.
Use the getLineMetrics()
method
for a Font
to retrieve the metrics
for text as it would appear for that component. This method also needs
to know some information about how you plan to render the text—if you’re
planning to use anti-aliasing, for instance, which affects the text
measurements. This extra information is encapsulated in the FontRenderContext
class. Fortunately, you can just ask Graphics2D
for its current FontRenderContext
rather than having to create
one yourself:
public
void
paint
(
Graphics
g
)
{
Graphics2D
g2
=
(
Graphics2D
)
g
;
...
FontRenderContext
frc
=
g2
.
getFontRenderContext
();
LineMetrics
metrics
=
font
.
getLineMetrics
(
"Monkey"
,
frc
);
...
}
The Font
class also has a
getStringBounds()
method that returns the bounding box of a piece of text:
public
void
paint
(
Graphics
g
)
{
Graphics2D
g2
=
(
Graphics2D
)
g
;
...
FontRenderContext
frc
=
g2
.
getFontRenderContext
();
float
messageWidth
=
(
float
)
font
.
getStringBounds
(
"Monkey"
,
frc
).
getWidth
();
...
}
The following application, FontShow
, displays a word and draws reference
lines showing certain characteristics of its font, as shown in Figure 20-3. Clicking in the application window
toggles the point size between a small and a large value.
//file: FontShow.java
import
java.awt.*
;
import
java.awt.event.*
;
import
java.awt.font.*
;
import
javax.swing.*
;
public
class
FontShow
extends
JComponent
{
private
static
final
int
PAD
=
25
;
// frilly line padding
private
boolean
bigFont
=
true
;
private
String
message
;
public
FontShow
(
String
message
)
{
this
.
message
=
message
;
addMouseListener
(
new
MouseAdapter
()
{
public
void
mouseClicked
(
MouseEvent
e
)
{
bigFont
=
!
bigFont
;
repaint
();
}
});
}
public
void
paint
(
Graphics
g
)
{
Graphics2D
g2
=
(
Graphics2D
)
g
;
g2
.
setRenderingHint
(
RenderingHints
.
KEY_ANTIALIASING
,
RenderingHints
.
VALUE_ANTIALIAS_ON
);
int
size
=
bigFont
?
96
:
64
;
Font
font
=
new
Font
(
"Dialog"
,
Font
.
PLAIN
,
size
);
g2
.
setFont
(
font
);
int
width
=
getSize
().
width
;
int
height
=
getSize
().
height
;
FontRenderContext
frc
=
g2
.
getFontRenderContext
();
LineMetrics
metrics
=
font
.
getLineMetrics
(
message
,
frc
);
float
messageWidth
=
(
float
)
font
.
getStringBounds
(
message
,
frc
).
getWidth
();
// center text
float
ascent
=
metrics
.
getAscent
();
float
descent
=
metrics
.
getDescent
();
float
x
=
(
width
-
messageWidth
)
/
2
;
float
y
=
(
height
+
metrics
.
getHeight
())
/
2
-
descent
;
g2
.
setPaint
(
getBackground
());
g2
.
fillRect
(
0
,
0
,
width
,
height
);
g2
.
setPaint
(
getForeground
());
g2
.
drawString
(
message
,
x
,
y
);
g2
.
setPaint
(
Color
.
white
);
// Base lines
drawLine
(
g2
,
x
-
PAD
,
y
,
x
+
messageWidth
+
PAD
,
y
);
drawLine
(
g2
,
x
,
y
+
PAD
,
x
,
y
-
ascent
-
PAD
);
g2
.
setPaint
(
Color
.
green
);
// Ascent line
drawLine
(
g2
,
x
-
PAD
,
y
-
ascent
,
x
+
messageWidth
+
PAD
,
y
-
ascent
);
g2
.
setPaint
(
Color
.
red
);
// Descent line
drawLine
(
g2
,
x
-
PAD
,
y
+
descent
,
x
+
messageWidth
+
PAD
,
y
+
descent
);
}
private
void
drawLine
(
Graphics2D
g2
,
double
x0
,
double
y0
,
double
x1
,
double
y1
)
{
Shape
line
=
new
java
.
awt
.
geom
.
Line2D
.
Double
(
x0
,
y0
,
x1
,
y1
);
g2
.
draw
(
line
);
}
public
static
void
main
(
String
args
[])
{
String
message
=
"Lemming"
;
if
(
args
.
length
>
0
)
message
=
args
[
0
];
JFrame
frame
=
new
JFrame
(
"FontShow"
);
frame
.
setSize
(
420
,
300
);
frame
.
setDefaultCloseOperation
(
JFrame
.
EXIT_ON_CLOSE
);
frame
.
getContentPane
().
add
(
new
FontShow
(
message
));
frame
.
setVisible
(
true
);
}
}
You can specify the text to be displayed as a command-line argument:
%
java
FontShow
"When in the course of human events ..."
FontShow
may look a bit
complicated, but there’s really not much to it. The bulk of the code is
in paint()
, which sets the font,
draws the text, and adds a few lines to illustrate some of the font’s
characteristics (metrics). For fun, we also catch mouse clicks (using an
event handler defined in the constructor) and alternate the font size by
setting the bigFont
toggle variable
and repainting.
By default, text is rendered above and to the right of the
coordinates specified in the drawString()
method. Think of that starting
point as the origin of a coordinate system; the axes are the baselines of the font. FontShow
draws these lines in white. The
greatest height the characters stretch above the baseline is called the
ascent and is shown by a green line.
Some fonts also have parts of letters that fall below the baseline. The
farthest distance any character reaches below the baseline is called the
descent, which is illustrated with a
red line.
We ask for the ascent and descent of our font with the LineMetrics
class’s getAscent()
and getDescent()
methods. We also ask for the
width of our string (when rendered in this font) with Font
’s getStringBounds()
method. This information is used to center the word in the display area.
To center the word vertically, we use the height and adjust with the
descent to calculate the baseline location. Table 20-2 provides a short list of methods
that return useful font metrics.
Leading space is the padding between lines of
text. The getHeight()
method reports
the total height of a line of text, including the leading
space.
Get Learning Java, 4th Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.