Section 7.11. Handling Text in a Graphics Context (Optional)


[Page 334 (continued)]

7.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.

Every graphics context has an associated Font and FontMetrics object, and the Graphics class (Fig. 7.18) provides several methods to access 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:


[Page 335]

g.setFont(new Font("TimesRoman", Font.ITALIC, 12)); 


Figure 7.18. Methods to access the Font and FontMetrics objects associated with every Graphics context.
(This item is displayed on page 334 in the print version)


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

7.11.1. The Font and FontMetrics Classes

The Font class (Fig. 7.19) provides a platform-independent representation 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.

Figure 7.19. The Font class.


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 character into a corresponding shape, as defined by the 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 platform (host computer plus operating system) will have a collection of fonts available on it.

A logical font is one of the five font families supported by the Java runtime environment. These include Serif, SansSerif, Monospaced, Dialog, and DialogInput. Java also supports the following font styles: PLAIN, BOLD, ITALIC, and BOLD+ITALIC. Whereas the physical fonts are platform 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 specified font, it will supply a substitute. For example, if you specify a 48-point, italic, Monospaced font,

Font myFont = new Font("Monospaced", Font.ITALIC, 48); 


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


[Page 336]

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,

g.setFont(new Font("Random", Font.ITALIC, 12) ); g.drawString("Hello World! (random, italic, 12)", 30, 45); 


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

Effective Design: Font Portability

The fact that Font() will produce a font for virtually any set of arguments is important in ensuring that a Java program can run on any platform. This is another example of how Java has been designed for portability.


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:

Button b = new Button("Label"); b.setFont(new Font("Times", Font.ITALIC, 14)); 


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

7.11.2. Font Metrics

To illustrate how to use the FontMetrics class, let's write a "Hello World" application that centers its message both horizontally and vertically 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, such as the height and width of its characters, whether the characters have a fixed or variable width, and so on. In order to get access to these properties, we will use the FontMetrics class.

Problem statement


Figure 7.20 illustrates the various properties associated with a font. The baseline of a font refers to the line on which the bottom of most characters occurs. When drawing a string, the x- and y-coordinates determine the baseline of the string's first character. Thus, in

Figure 7.20. Illustration of font measurements.


g.drawString("Hello World", 10, 40); 


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


[Page 337]

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 is 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, descent, 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 the 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 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 characters. Alternatively, the stringWidth() method can be used to determine the number of pixels required to draw the entire string.

Figure 7.21. The FontMetrics class.


7.11.3. 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 particular font 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.

Algorithm design: Generality


The only method we need for this application is the paint() method. We 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:

g.setFont(new Font("Random", Font.BOLD, 24)); FontMetrics metrics = g.getFontMetrics(); 



[Page 338]

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 manipulate an object's width and height as a single entity. Note that the height and width variables are defined as public, which is an exception from the usual convention of defining instance 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:

Dimension d = new Dimension(100, 50); System.out.println("width = " + d.width + " height = " + d.height); 


Figure 7.22. The Dimension class.


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 version of some access methods, the class achieves a higher level of flexibility. The same can be said for its providing of several different constructors, including a copy constructor. Finally, note how the class overrides the equals() and toString() methods. These are all examples of good object-oriented design.

Effective Design: Redundancy

Redundancy is often a desirable characteristic of object design. It makes the object easier to use and more widely applicable.


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:

int x = (d.width - metrics.stringWidth(str)) / 2;  // Calculate coordinates 



[Page 339]

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

int y = (d.height + metrics.getHeight()) / 2; 


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 recenter its message whenever it is resized by the user.

Figure 7.23. The CenterText application.

import java.awt.*; import javax.swing.*; public class CenterText extends JFrame {    public void paint(Graphics g) {    // Print hello world! in center of frame       String str = "Hello World!";       g.setFont(new Font("Random", Font.PLAIN, 24));   // Random font       FontMetrics metrics = g.getFontMetrics();        // And its metrics       Dimension d = getSize();                         // Get the frame's size                                                        // Clear the frame       g.setColor(getBackground());       g.fillRect(0,0,d.width,d.height);       g.setColor(Color.black);                                                        // Calculate coordinates       int x = (d.width - metrics.stringWidth(str)) / 2;       int y = (d.height + metrics.getHeight()) / 2;       g.drawString( str, x, y );                       // Draw the string    } // paint()    public static void main(String args[]) {       CenterText ct = new CenterText();       ct.setSize(400,400);       ct.setVisible(true);    } // main() } // CenterText class 

Figure 7.24. The CenterText application keeps its message centered no matter how its window is resized.


Java Programming Tip: Generality

By using a component's size and font as the determining factors, you can center text on virtually any component. These values are available via the component's getFont() and getSize() methods.





Java, Java, Java(c) Object-Orienting Problem Solving
Java, Java, Java, Object-Oriented Problem Solving (3rd Edition)
ISBN: 0131474340
EAN: 2147483647
Year: 2005
Pages: 275

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net