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
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:
Serif
(generic name forTimesRoman
)SansSerif
(generic name forHelvetica
)Monospaced
(generic name forCourier
)Dialog
DialogInput
The logical font name is mapped to an actual font on the local platform. Java’s fonts.properties files map 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.print(fonts[i].getFontName( ) + " : "); System.out.print(fonts[i].getFamily( ) + " : "); System.out.print(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. You can also allow your users to configure the application by choosing fonts themselves.
The static
method Font.getFont( )
looks up a font name in the system properties list.
getFont( )
takes a String
font
property name, retrieves the font name from the
Properties
table, and returns the
Font
object that corresponds to that font. You can
use this mechanism, as with Color
s, to define
fonts with properties from outside your application.
The
Font
class defines three static
style identifiers: PLAIN
, BOLD
,
and ITALIC
. You can use these values on all fonts.
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 Graphics
object.
Subsequent text- drawing commands like 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 will 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-point 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 antialiasing, 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 17.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 f = new JFrame("FontShow"); f.setSize(420, 300); f.setLocation(100, 100); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.getContentPane( ).add(new FontShow(message)); f.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. FontShow
illustrates this 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 17.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 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.