10. Strings and String Processing

10.11. Handling Text in a Graphics Context (Optional)

In order to create attractive GUIs, it is often necessary to be able to select and control the font that is used. Even a simple drawing task, such as being able to center a message in a panel, requires that we know the font’s dimensions and be able to manipulate them. In this section, we learn how

to work with Java’s fonts and font control methods.

Each graphics context has an associated Font and FontMetrics ob-

 

Figure 7.18: Methods to access the Font and FontMetrics objects associated with each Graphics context.


ject, and the Graphics class (Fig. 7.18) provides several methods to ac- cess them. A FontMetrics is an object that encapsulates important data about a font, such as its height and width. Java assigns a default font to each Graphics object. For example, this is the font used by the

 

drawString() method, which we used in our very first Java programs back in Chapter 1. The particular font used is system dependent, but to override the default one can simply invoke the setFont() method:

,,

 

J

In this case, the Font() constructor is used to specify a 12-point, itali- cized, TimesRoman font. Once the font is set, it will be used in all subse- quent drawings.

 

The Font and FontMetrics Classes

The Font class (Fig. 7.19) provides a platform-independent representa- tion of an individual font. A font is distinguished by its name, size, and style, and the Font class includes protected instance variables for these properties, as well as a constructor method that allows these three characteristics to be specified.

In order to understand how fonts work, it is necessary to distinguish

between a character, which is a symbol that represents a certain letter or

 

digit, and a glyph, which is a shape used to display the character. When you display a string, such as “Hello”, Java maps each individual charac- ter into a corresponding shape, as defined by the particular font that is selected.

Java distinguishes between physical and logical fonts. A physical font is an actual font library that contains the data and tables needed to associate the correct glyph with a given character. Generally speaking, a given plat- form (host computer plus operating system) will have a collection of such fonts available on it.

A logical font is one of five font families that are supported by the Java runtime environment. These include Serif, SansSerif, Monospaced, Dia- log, and DialogInput. Java also supports the following font styles: PLAIN, BOLD, ITALIC, and BOLD+ITALIC. Whereas the physical fonts are plat- form dependent, the logical fonts and styles are platform independent. When used in a program, they are mapped to real fonts available on the host system. If the host system does not have an exact match for the speci- fied font, it will supply a substitute. For example, if you specify a 48-point, italic, Monospaced font,

,,


Figure 7.19: The Font class.

 

 

J

the system may map this to a 24-point, italic Courier font, if that is the largest fixed-spaced font available.

The Font() constructor is designed to work with any set of arguments. Thus, if you supply the name of a font that is not available, the system will supply a default font as a substitute. For example, on my system, specifying a nonexistent font named Random,

,,

 

;

J

 

produces the same font used as the mapping for a font named Dialog.

The Component.setFont() method can be used to assign a specific font to a button or window or other graphics component. All AWT and JFC components have an associated font, which can be accessed using the Component.setFont() and Component.getFont() methods. For example, the following code could be used to override a Button’s font:

,,

 

 

 

 

 

Problem statement

 

 

 

Advance

 

 

Height


 

 

 

 

 

 

 

 

 

 

 

 

 

 

Leading Baseline

 

Descent


J

If 14-point, italic, Times font is not available on the host system, a substi- tute will be supplied.

Font Metrics

To illustrate how to use the FontMetrics class, let’s write a “Hello, World!” application that centers its message both horizontally and ver- tically in its window. The message should be centered regardless of the size of the application window. Thus, we will have to position the text relative to the window size, which is something we learned in positioning geometric shapes. The message should also be centered no matter what font is used. This will require us to know certain characteristics of the font itself, such as the height and width of its characters, whether the charac- ters have a fixed or variable width, and so on. In order to get access to these properties, we will use the FontMetrics class.

Figure 7.20 illustrates the various properties that are associated with a font. The baseline of a font refers to the line on which the bottom of

 

Figure 7.20: An illustration of the various font measurements.


most characters occurs. When drawing a string, the x- and y-coordinates determine the baseline of the string’s first character. Thus, in

,,

 

 

J

the bottom left of the H in “Hello, World!” would be located at (10, 40).

All characters ascend some distance above the baseline. This is known as the character’s ascent. Some characters, such as y, may extend below the baseline, into what’s known as the descent. Each font has a maximum descent. Similarly, some characters, such as accent characters, may extend above the maximum ascent into a space known as the leading.

The height of a font is defined as the sum (in pixels) of the ascent, de- scent, and leading values. The height is a property of the font itself rather than of any individual character. Except for fixed-width fonts, in which the width of all characters is the same, the characters that make up a font have varying widths. The width of an individual character is known as its advance.

The FontMetrics class (Fig. 7.21) provides methods for accessing a

 

Figure 7.21: The FontMetrics

class.

 

font’s properties. These can be useful to control the layout of text on a GUI. For example, when drawing multiple lines of text, the getHeight() method is useful for determining how much space should be left between lines. When drawing character by character, the charWidth() method can be used to determine how much space must be left between charac- ters. Alternatively, the stringWidth() method can be used to determine the number of pixels required to draw the entire string.

 

 

Example: Centering a Line of Text

 

Given this background, let’s take on the task of centering a message in an application window. In order for this application to work for any font, we

must take care not to base its design on characteristics of the particularAlgorithm design: Generality

font that we happen to be using. To underscore this point, let’s design it to work for a font named Random, which, as we noted earlier, will be mapped to some font by the system on which the application is run. In other words, we will let the system pick a font for this application’s message. An interesting experiment would be to run the application on different platforms to see what fonts are chosen.

The only method we need for this application is the paint() method. Let’s begin by setting the font used by the graphics context to a random font. To get the characteristics of this font, we create a FontMetrics object and get the font metrics for the font we just created:

,,

 

J

The next step is to determine the JFrame’s dimensions using the getSize() method. This method returns an object of type Dimension. The java.awt.Dimension class (Fig. 7.22) represents the size (width and height) of a GUI component. A Dimension makes it possible to ma- nipulate an object’s width and height as a single entity. Note that the height and width variables are defined as public, which is an excep- tion from the usual convention of defining instances variables as private or protected. The justification for this exception is probably to simplify the syntax of referring to an object’s width and height. For example, the following syntax can be used to refer to a component’s dimensions:

,,

 

 

J

Note the redundancy built into the Dimension class. For example, in addition to being able to set a Dimension’s instance variables directly,

public access methods are provided. Also, by defining more than one ver-

sion of some access methods, the class achieves a higher level of flexibility.

 

The same can be said for providing several different constructors, includ- ing a copy constructor. Finally, note how it overrides the equals() and


Figure 7.22:The Dimension

class.

 

toString() methods. These are all examples of good object-oriented design.

 

 

 

 

 

Centering text


The Dimension object is used to calculate the x- and y-coordinates for the string. In order to center the string horizontally, we need to know its width, which is supplied by the metrics object. If the JFrame is d.width pixels wide, then the following expression subtracts the width of the string from the width of the JFrame and then divides the leftover space in half:

,,

 

 

J

Similarly, the following expression adds the height of the string to the height of the JFrame and divides the leftover space in half:

,,

 

J

Taken together, these calculations give the coordinates for the lower left pixel of the first character in “Hello, World!!” The only remaining task is to draw the string (Fig. 7.23). Because the paint() method is called automatically whenever the JFrame is resized, this application, whose output is shown in Figure 7.24, will re-center its message whenever it is resized by the user.

 

 

 

 

 

 

CHAPTER SUMMARYTechnical Terms

ascent baseline concatenation

copy constructor data structure delimited string delimiter

empty string


garbage collection glyph lexicographic order logical font

off-by-one error orphan object physical font read only


string string index

string literal token

unit indexed zero indexed

 

CHAPTER 7 Chapter Summary329

,,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

J

Figure 7.23: The CenterText application.

 

 

Summary of Important Points

 

A String literal is a sequence of 0 or more characters enclosed within double quotation marks. A String object is a sequence of 0 or more characters, plus a variety of class and instance methods and variables. A String object is created automatically by Java the first time it en- counters a literal string, such as “Socrates,” in a program. Subsequent occurrences of the literal do not cause additional objects to be instan- tiated. Instead, every occurrence of the literal “Socrates” refers to the initial object.

 

CenterText ap- its message cen- how its window is

 

A String object is created whenever the new operator is used in conjunction with a String() constructor—for example, new String("hello").

The String concatenation operator is the overloaded + symbol; it is

used to combine two Strings into a single String: “hello” + “world”

==> “helloworld”.

Strings are indexed starting at 0. The indexOf() and lastIndex- Of() methods are used for finding the first or last occurrence of a char- acter or substring within a String. The valueOf() methods con- vert a nonstring into a String. The length() method determines the number of characters in a String. The charAt() method re- turns the single character at a particular index position. The vari- ous substring() methods return the substring at particular index positions in a String.

The overloaded equals() method returns true if two Strings con- tain the same exact sequence of characters. The == operator, when used on Strings, returns true if two references designate the same String object.

String objects are immutable. They cannot be modified.

A StringBuffer is a string object that can be modified using meth- ods such as insert() and append().

A StringTokenizer is an object that can be used to break a String into a collection of tokens separated by delimiters. The whitespace characters—tabs, blanks, and newlines—are the default delimiters.

The FontMetrics class is used to obtain the specific dimensions of the the various Fonts. It is useful when you wish to center text. Fonts are inherently platform dependent. For maximum portability, it is best to use default fonts.

 

 

 

 

SOLUTIONS TO

SELF-STUDY EXERCISES


SOLUTION 7.1a. sillyb. sillyc. silly stuff SOLUTION 7.2

String str1 = "";

String str2 = new String("stop");

String str3 = str1 + str2;

SOLUTION 7.3a. 15b. "551"c. "5175"

SOLUTION 7.4 See Figure 7.25.

SOLUTION 7.5a. "45"b. "121"c. "X"

SOLUTION 7.6

String.valueOf(100)

String.valueOf(’V’);

String s = new String(String.valueOf(X * Y));

SOLUTION 7.7a. 0b. 1c. 1

 

 

swer to Exercise is null because it


CHAPTER 7 Solutions to Self-Study Exercises331

s2

 

tantiated and has d a literal value.


"Hello"


s3 s7


"hello" s4


s5s6s1

null

 

 

 

String s1, s2="Hello", s3="Hello"; String s4="hello";

String s5=new String ("Hello"); String s6=s5;

String s7=s3;

 

 

 

SOLUTION 7.8

 

 

16


b. "16"

1

15

1


13

7

3

7


7

3

 

 

SOLUTION 7.9 Evaluate the following expression:

,,

 

 

 

 

 

SOLUTION 7.10a. "uvwxyz"

b. "bcde"

SOLUTION 7.11a. "uvwxyz"

"bcde"


"xyz"

"xy"

"xyz"

"xyz"


J

"xyz"

 

"xyz"

 

 

SOLUTION 7.12 A class to test the string methods.

,,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

J

 

SOLUTION 7.13 Method to remove all blanks from a string:

,,

 

 

 

 

 

 

 

J

SOLUTION 7.14 A Alpha Z Zero Zeroes a alpha bath bin z zero

SOLUTION 7.15 To modify precedes so that it also returns true when its two string arguments are equal, just change the operator in the final return statement to <=:

,,

 

 

 

SOLUTION 7.16a. true

true

false


false

false

true


J

false

false

false

 

SOLUTION 7.17 The variables in TestStringEquals are declared static because they are used in static methods. Whenever you call a method di- rectly from main(), it must be static because main() is static. Remember that static elements are associated with the class, not with its instances. So main() can only use static elements because they don’t depend on the existence of instances.

SOLUTION 7.18

String s3 = s1.substring(s1.indexOf(’n’))

+ s1.substring(0,s1.indexOf(’n’));

String s4 = s2.substring(6) + " " + s2.substring(0,5);

String s5 = s2.substring(0,6) + s1.substring(0,3);

 

 

 

 

EXERCISES

Note: For programming exercises, first draw a UML class diagram describing all classes and their inheritance relationships and/or associations.


EXERCISE 7.1 Explain the difference between the following pairs of terms:

Unit indexing and zero indexing.

Data structure and data type.

StringBuffer and String.

String and StringTokenizer.

Declaring a variable and instantiating a String.

A Font and a FontMetrics object. EXERCISE 7.2 Fill in the blanks.

When the first character in a string has index 0, this is known as.

A sequence of characters enclosed within quotes is known as a.

 

EXERCISE 7.3 Given the String str with the value “to be or not to be that is the question,” write Java expressions to extract each of the substrings shown below. For each substring, provide two sets of answers. One that uses the actual index numbers of the substrings—for example, the first “to” goes from 0 to 2—and a sec- ond more general solution that will also retrieve the substring from the following string “it is easy to become what you want to become.” (Hint: In the second case, use length() and indexOf() along with substring() in your expressions. If necessary, you may use local variables to store intermediate results. The answer to (a) is provided as an example.)

the first “to” in the string

,,

 

 

 

 

the last “to” in the string

the first “be” in the string

the last “be” in the string


J

the first four characters in the string

the last four characters in the string

 

EXERCISE 7.4 Identify the syntax errors in each of the following, assuming that

s is the literal string “exercise”:

 

s.charAt("hello")

s.indexOf(10)

s.substring("er")


s.lastIndexOf(er)

s.length

 

EXERCISE 7.5 Evaluate each of the following expressions, assuming that s is the literal string “exercise”:

 

s.charAt(5)

s.indexOf("er")

s.substring(5)


s.lastIndexOf(’e’)

s.length()

 

EXERCISE 7.6 Write your own equalsIgnoreCase() method using only other String methods.

EXERCISE 7.7 Write your own String equality method without using

String. equals(). (Hint: Modify the precedes() method.)

EXERCISE 7.8 Even though Java’s String class has a built-in toLowerCase() method, write your own implementation of this method. It should take a String parameter and return a String with all its letters written in lowercase.

EXERCISE 7.9 Write a method that converts its String parameter so that let- ters are written in blocks five characters long. For example, consider the following two versions of the same sentence:

,,

 

J

EXERCISE 7.10 Design and implement a Java Swing program that lets the user type a document into a TextArea and then provides the following analysis of the document: the number of words in the document, the number of characters in the document, and the percentage of words that have more than six letters.

EXERCISE 7.11 Design and write a Java Swing program that searches for single- digit numbers in a text and changes them to their corresponding words. For ex- ample, the string “4 score and 7 years ago” would be converted into “four score and seven years ago”.

 

EXERCISE 7.12 A palindrome is a string that is spelled the same way backward and forward. For example, mom, dad, radar, 727 and able was i ere i saw elba are all examples of palindromes. Write a Java Swing program that lets the user type in a word or phrase and then determines whether the string is a palindrome.

 

 

EXERCISE 7.13 Write a maze program that uses a string to store a representa- tion of the maze. Write a method that accepts a String parameter and prints a two-dimensional representation of a maze. For example, the maze shown here, where O marks the entrance and exit can be generated from the following string:

,,

 

 

 

 

J

 

 

 

 

 

 

Sam Penn

14 Bridge St. Hoboken, NJ 01881


EXERCISE 7.14 Write a method that takes a delimited string to store a name and address, from which you can print a mailing label. For example, if the string contains “Sam Penn:14 Bridge St.:Hoboken, NJ 01881,” the method should print the label shown in the margin.

 

 

EXERCISE 7.15 Design and implement a Java Swing program that plays Time Bomb with the user. Here’s how the game works. The computer picks a secret word and then prints one asterisk for each letter in the word: * * * * *. The user guesses at the letters in the word. For every correct guess, an asterisk is replaced by aletter:

* e * * *. For every incorrect guess, the time bomb’s fuse grows shorter. When the fuse disappears, after say, six incorrect guesses, the bomb explodes. Store the secret words in a delimited string and invent your own representation for the time bomb.

 

 

EXERCISE 7.16 Challenge: The global replace function is a string-processing algorithm found in every word processor. Write a method that takes three String arguments: a document, a target string, and a replacement string. The method should replace every occurrence of the target string in the document with the re- placement string. For example, if the document is “To be or not to be, that is the question,” and the target string is “be,”, and the replacement string is “see,” the result should be, “To see or not to see, that is the question.”

 

 

EXERCISE 7.17 Challenge: Design and implement a Java Swing Program that plays the following game with the user. Let the user pick a letter between A and

Z. Then let the computer guess, the secret letter. For every guess the player has to tell the computer whether it’s too high or too low. The computer should be able to guess the letter within five guesses. Do you see why?

 

EXERCISE 7.18 Challenge: A list is a sequential data structure. Design a List class that uses a comma-delimited String—such as, “a,b,c,d,12,dog”—to imple- ment a list. Implement the following methods for this class:

,,

 

 

 

 

 

 

J

EXERCISE 7.19 Challenge: Use a delimited string to create a PhoneList class with an instance method to insert names and phone numbers, and a method to look up a phone number when a user provides a person’s name. Since your class will take care of looking things up, you don’t have to worry about keeping the list in alphabetical order. For example, the following string could be used as such a directory:

,,

 

J

EXERCISE 7.20 Design and implement an application that displays a multi-line message in various fonts and sizes input by the user. Let the user choose from among a fixed selection of fonts, sizes, and styles.

 

 

 

 

 

 

 

 

 

 

 

Chapter 8