Managing Text Output Using FontMetrics
As just explained, Java supports a number of fonts. For most fonts,
characters are not all the same dimension—most fonts are proportional. Also,
the height of each character, the length of descenders
(the hanging parts of letters, such as y),
and the amount of space between horizontal lines vary from font to font.
Further, the point size of a font can be changed. That these (and other)
attributes are variable would not be of too much consequence except that Java
demands that you, the programmer, manually manage virtually all text output.
Given that the size of each font may differ and that fonts may be
changed while your program is executing, there must be some way to determine
the dimensions and various other attributes of the currently selected font. For
example, to write one line of text after another implies that you have some way
of knowing how tall the font is and how many pixels are needed between lines.
To fill this need, the AWT includes the FontMetrics
class, which encapsulates various information about a font. Let’s begin by
defining the common terminology used when describing fonts:
Height : The top-to-bottom size of a line of text
Baseline : The line that the bottoms of characters are aligned to
(not counting descent)
Ascent : The distance from the baseline to the top of a character
Descent : The distance from the baseline to the bottom of a
character
Leading : The distance between the bottom of one line of text and
the top of the next
As you know, we have used the drawString(
) method in many of the previous examples. It paints a string in the
current font and color, beginning at a specified location. However, this
location is at the left edge of the baseline of the characters, not at the
upper-left corner as is usual with other drawing methods. It is a common error
to draw a string at the same coordinate that you would draw a box. For example,
if you were to draw a rectangle at coordinate 0,0, you would see a full
rectangle. If you were to draw the string “Typesetting” at 0,0, you would only
see the tails (or descenders) of the y,
p, and g. As you will see, by
using font metrics, you can determine the proper placement of each string that
you display.
FontMetrics defines several methods that
help you manage text output. Several commonly used ones are listed in Table 25-3. These methods help you
properly display text in a window. Let’s look at some examples.
Displaying Multiple Lines of Text
Perhaps the most common use of FontMetrics
is to determine the spacing between lines of text. The second most common use
is to determine the length of a string that is being displayed. Here, you will
see how to accomplish these tasks.
In general, to display multiple lines of text, your program must manually
keep track of the current output position. Each time a newline is desired, the
Y coordinate must be advanced to the beginning of the next line. Each time a
string is displayed, the X coordinate must be set to the point at which the
string ends. This allows the next string to be written so that it begins at the
end of the preceding one.
Method : Description
int bytesWidth(byte b[ ], int start, int numBytes) : Returns the width of numBytes
characters held in array b, beginning at start.
int charWidth(char c[ ], int start,
int numChars) : Returns the width of numChars characters held in array
c, beginning at start.
int charWidth(char c) : Returns the width of c.
int charWidth(int c) : Returns the width of c.
int getAscent( ) : Returns the ascent of the font.
int getDescent( ) : Returns the descent of the font.
Font getFont( ) : Returns the font.
int getHeight( ) : Returns the height of a line of text. This value
can be used to output multiple lines of text in a window.
int getLeading( ) : Returns the space between lines of text.
int getMaxAdvance( ) : Returns the width of the widest character.
–1 is returned if this value is not available.
int getMaxAscent( ) : Returns the maximum ascent.
int getMaxDescent( ) : Returns the maximum descent.
int[ ] getWidths( ) : Returns the widths of the first 256
characters.
int stringWidth(String str) : Returns the width of the string
specified by str.
String toString( ) : Returns the string equivalent of the invoking
object.
Table 25-3 A Sampling of Methods Defined by FontMetrics
To determine the spacing between lines, you can use the value
returned by getLeading( ). To
determine the total height of the font, add the value returned by getAscent( ) to the value returned by getDescent( ). You can then use these
values to position each line of text you output. However, in many cases, you
will not need to use these individual values. Often, all that you will need to
know is the total height of a line, which is the sum of the leading space and
the font’s ascent and descent values. The easiest way to obtain this value is
to call getHeight( ). Simply
increment the Y coordinate by this value each time you want to advance to the next line when outputting text.
To start output at the end of previous output on the same line, you
must know the length, in pixels, of each string that you display. To obtain
this value, call stringWidth( ). You
can use this value to advance the X coordinate each time you display a line.
The following applet shows how to output multiple lines of text in
a window. It also displays multiple sentences on the same line. Notice the
variables curX and curY. They keep track of the current
text output position.
//
Demonstrate multiline output.
import
java.applet.*;
import
java.awt.*; /*
<applet
code="MultiLine" width=300 height=100> </applet>
*/
public
class MultiLine extends Applet { int curX=0, curY=0; // current position
public
void init() {
Font f =
new Font("SansSerif", Font.PLAIN, 12); setFont(f);
}
public
void paint(Graphics g) { FontMetrics fm = g.getFontMetrics();
nextLine("This
is on line one.", g); nextLine("This is on line two.", g);
sameLine(" This is on same line.", g); sameLine(" This,
too.", g); nextLine("This is on line three.", g);
curX =
curY = 0; // Reset coordinates for each repaint.
}
//
Advance to next line.
void
nextLine(String s, Graphics g) { FontMetrics fm = g.getFontMetrics();
curY +=
fm.getHeight(); // advance to next line
curX =
0;
g.drawString(s,
curX, curY);
curX =
fm.stringWidth(s); // advance to end of line
}
//
Display on same line.
void
sameLine(String s, Graphics g) { FontMetrics fm = g.getFontMetrics();
g.drawString(s,
curX, curY);
curX +=
fm.stringWidth(s); // advance to end of line
}
}
Sample output from this program is shown here:
Centering Text
Here is an example that centers text, left to right, top to bottom,
in a window. It obtains the ascent, descent, and width of the string and
computes the position at which it must be displayed to be centered.
//
Center text.
import
java.applet.*; import java.awt.*;
/*
<applet
code="CenterText" width=200 height=100> </applet>
*/
public
class CenterText extends Applet {
final
Font f = new Font("SansSerif", Font.BOLD, 18);
public
void paint(Graphics g) { Dimension d = this.getSize();
g.setColor(Color.white);
g.fillRect(0, 0, d.width,d.height); g.setColor(Color.black); g.setFont(f);
drawCenteredString("This
is centered.", d.width, d.height, g); g.drawRect(0, 0, d.width-1,
d.height-1);
}
public
void drawCenteredString(String s, int w, int h, Graphics g) {
FontMetrics
fm = g.getFontMetrics(); int x = (w - fm.stringWidth(s)) / 2;
int y =
(fm.getAscent() + (h - (fm.getAscent() + fm.getDescent()))/2);
g.drawString(s,
x, y);
}
}
Following is a sample output from this program:
Multiline Text Alignment
When using a word processor, it is common for text to be aligned so
that one or more of the edges of the text make a straight line. For example,
most word processors can left-justify and/or right-justify text. Most can also
center text. In the following program, you will see how to accomplish these
actions.
In the program, the string to be justified is broken into
individual words. For each word, the program keeps track of its length in the
current font and automatically advances to the next line if the word will not
fit on the current line. Each completed line is displayed in the window in the
currently selected alignment style. Each time you click the mouse in the
applet’s window, the alignment style is changed. Sample output from this
program is shown here:
//
Demonstrate text alignment.
import
java.applet.*;
import
java.awt.*; import java.awt.event.*; import java.util.*;
/*
<title>Text Layout</title>
<applet
code="TextLayout" width=200 height=200>
<param
name="text" value="Output to a Java window is actually quite
easy.
As you
have seen, the AWT provides support for fonts, colors, text, and graphics.
<P> Of course, you must effectively utilize these items
if you
are to achieve professional results."> <param
name="fontname" value="Serif">
<param
name="fontSize" value="14"> </applet>
*/
public
class TextLayout extends Applet { final int LEFT = 0;
final
int RIGHT = 1; final int CENTER = 2;
final
int LEFTRIGHT =3; int align;
Dimension
d; Font f; FontMetrics fm; int fontSize; int fh, bl; int space; String text;
public
void init() { setBackground(Color.white); text =
getParameter("text"); try {
fontSize
= Integer.parseInt(getParameter("fontSize"));} catch (NumberFormatException
e) {
fontSize=14;
}
align =
LEFT;
addMouseListener(new
MyMouseAdapter(this));
}
public
void paint(Graphics g) { update(g);
}
public
void update(Graphics g) { d = getSize(); g.setColor(getBackground());
g.fillRect(0,0,d.width,
d.height);
if(f==null)
f = new Font(getParameter("fontname"), Font.PLAIN, fontSize);
g.setFont(f);
if(fm == null) {
fm =
g.getFontMetrics(); bl = fm.getAscent();
fh = bl
+ fm.getDescent(); space = fm.stringWidth(" ");
}
g.setColor(Color.black);
StringTokenizer
st = new StringTokenizer(text); int x = 0;
int
nextx; int y = 0;
String
word, sp; int wordCount = 0; String line = "";
while
(st.hasMoreTokens()) { word = st.nextToken();
if(word.equals("<P>")) {
drawString(g,
line, wordCount, fm.stringWidth(line), y+bl);
line =
""; wordCount = 0;
x = 0;
y = y +
(fh * 2);
}
else {
int w =
fm.stringWidth(word);
if((
nextx = (x+space+w)) > d.width ) { drawString(g, line, wordCount,
fm.stringWidth(line),
y+bl);
line =
""; wordCount = 0; x = 0;
y = y +
fh;
}
if(x!=0)
{sp = " ";} else {sp = "";} line = line + sp + word;
x = x +
space + w; wordCount++;
}
}
drawString(g,
line, wordCount, fm.stringWidth(line), y+bl);
}
public
void drawString(Graphics g, String line, int wc, int lineW, int y) {
switch(align)
{
case
LEFT: g.drawString(line, 0, y); break;
case
RIGHT: g.drawString(line, d.width-lineW,y); break;
case
CENTER: g.drawString(line, (d.width-lineW)/2, y); break;
case
LEFTRIGHT:
if(lineW
< (int)(d.width*.75)) { g.drawString(line, 0, y);
}
else {
int toFill
= (d.width - lineW)/wc;
int
nudge = d.width - lineW - (toFill*wc); int s = fm.stringWidth(" ");
StringTokenizer
st = new StringTokenizer(line); int x = 0;
while(st.hasMoreTokens())
{ String word = st.nextToken(); g.drawString(word, x, y); if(nudge>0) {
x = x +
fm.stringWidth(word) + space + toFill + 1; nudge--;
} else {
= x + fm.stringWidth(word) + space + toFill;
}
}
}
}
}
}
class
MyMouseAdapter extends MouseAdapter { TextLayout tl;
public
MyMouseAdapter(TextLayout tl) { this.tl = tl;
}
public
void mouseClicked(MouseEvent me) { tl.align = (tl.align + 1) % 4; tl.repaint();
}
}
Let’s take a closer look at how this applet works. The applet first
creates several constants that will be used to determine the alignment style,
and then declares several variables. The init(
) method obtains the text that will be displayed. It then initializes the
font size in a try-catch block, which will set the font
size to 14 if the fontSize parameter
is missing from the HTML. The text
parameter is a long string of text, with the HTML tag <P> as a paragraph separator.
The update( ) method is
the engine for this example. It sets the font and gets the baseline and font
height from a font metrics object. Next, it creates a StringTokenizer and uses it to retrieve the next token (a string
separated by whitespace) from the string specified by text. If the next token is <P>,
it advances the vertical spacing. Otherwise, update( ) checks to see if the length of this token in the current
font will go beyond the width of the
column. If the line is full of text or if there are no more tokens, the line is
output by a custom version of drawString(
).
The first three cases in drawString(
) are simple. Each aligns the string that is passed in line to the left or right edge or to the center of the column,
depending upon the alignment style.
The LEFTRIGHT case aligns both the
left and right sides of the string. This means that we need to calculate the
remaining whitespace (the difference between the width of the string and the width
of the column) and distribute that space between each of the words. The last
method in this class advances the alignment style each time you click the mouse
on the applet’s window.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.