Chapter 22

Text and Fonts


CONTENTS


This chapter covers the details of Java's text- and font-related classes. It shows how to use the TextComponent subclasses and how to display text with the canvas. It explains Java's use of fonts and shows how the Font and FontMetrics classes are used to provide custom control of text display. When you finish this chapter, you will be able to effectively use text and fonts in your Java window programs.

The Text Classes

You are now fairly familiar with the text-related classes supported by Java because you've used TextArea and TextField objects in the examples presented so far. Let's review these classes and then you can learn how to use font-related classes to alter the way text is presented to the user.

The TextComponent class is the superclass of the TextField and TextArea classes. It extends the Component class to support text-related processing. TextComponent provides several methods that are used to process text that is selected by the user. The setEditable() method determines whether a TextComponent object is read-only or can be edited. The getText() and setText() methods are its most popular methods and are used with all text-related classes.

The TextField class implements a simple, one-line text field. The visible length of the field (in characters) can be specified. Character echoing can be disabled to implement password-like text fields.

The TextArea class implements a multiple-line text field and supports a number of methods for updating the field by inserting, appending, and replacing text. The number of rows and columns associated with a text field can be specified.

Font Basics

The Font class provides a platform-independent method of specifying and using fonts. The Font class constructor constructs Font objects using the font's name, style (PLAIN, BOLD, ITALIC, or BOLD + ITALIC), and point size. Java's fonts are named in a platform-independent manner and then mapped to local fonts that are supported by the operating system on which it executes. The getName() method returns the logical Java font name of a particular font and the getFamily() method returns the operating system-specific name of the font. The standard Java font names are Dialog, DialogInput, Courier, Helvetica, TimesRoman, and ZapfDingbats. You'll see examples of these fonts shortly.

The FontMetrics class is used to return the specific parameters for a particular Font object. An object of this class is created using the getFontMetrics() methods supported by the Component class and other classes, such as the Graphics and Toolkit classes. The FontMetrics access methods provide access to the details of the implementation of a Font object.

The bytesWidth(), charWidth(), charsWidth(), getWidths(), and stringWidth() methods are used to determine the width of a text object in pixels. These methods are essential for determining the horizontal position of text on the screen.

When text characters are displayed, they are displayed relative to a baseline. The baseline is the line drawn through the bottom of non-descending characters. For example, if you drew a line at the bottom of most text displayed on this line, you would get the text's baseline. Some characters, such as g and y, descend below the baseline. The number of pixels that the characters of a font descend below the baseline are known as the font's descent. The number of pixels that the characters of a font extend above the baseline are known as the font's ascent. In addition to a font's ascent and descent, a third parameter, referred to as the font's leading, is used to describe the amount of vertical spacing, in pixels, used between the descent of a line of text and the ascent of the line of text below it. The overall height of a font is the sum of its leading, ascent, and spacing and is equal to the distance between baselines (in pixels) of vertically adjacent lines of text. The getLeading(), getAscent(), getDescent(), and getHeight() methods of the FontMetrics class are used to access these important font-related parameters.

The getMaxAdvance(), getMaxAscent(), and getMaxDescent() methods are provided for backward compatibility with earlier Java versions.

Using the Toolkit Class

The Toolkit class provides a link between the platform-independent Java implementation and its platform-specific characteristics. Among the many uninteresting methods implemented by this class are the getFontList(), getFontMetrics(), getScreenSize(), and getScreenResolution() methods. The getFontList() method returns a list of fonts that are accessible from Java. The getFontMetrics() method identifies the font metrics for a particular font. The getScreenSize() method identifies the screen dimension in terms of horizontal and vertical dots. The getScreenResolution() method identifies the screen resolution in dots per inch.

getFontList() is the method of interest for this chapter. You'll use it to get a list of the fonts available to Java in the next section.

The FontApp Program

The FontApp program illustrates the use of the Font, FontMetrics, and Toolkit classes and shows how to draw text on a Graphics object. Its source code is shown in Listing 22.1.


Listing 22.1. The source code of the FontApp program.

import java.awt.*;
import jdg.ch20.*;

public class FontApp extends Frame {
 MyMenuBar menuBar;
 Toolkit toolkit;
 Font defaultFont;
 String fontNames[];
 int screenWidth = 400;
 int screenHeight = 400;
 public static void main(String args[]){
  FontApp app = new FontApp();
 }
 public FontApp() {
  super("FontApp");
  setup();
  pack();
  resize(screenWidth,screenHeight);
  show();
 }
 void setup() {
  setBackground(Color.white);
  setupMenuBar();
  setMenuBar(menuBar);
  setupFonts();
 }
 void setupMenuBar() {
  String menuItems[][] = {{"File","Exit"}};
  menuBar = new MyMenuBar(menuItems);
 }
 void setupFonts() {
  toolkit = getToolkit();
  defaultFont = getFont();
  fontNames = toolkit.getFontList();
 }
 public void paint(Graphics g) {
  int styles[] = {Font.PLAIN,Font.BOLD,Font.ITALIC,Font.BOLD+Font.ITALIC};
  String styleNames[] = {"Plain","Bold","Italic","Bold and Italic"};
  int y = 0;
  int size = 14;
  for(int i=0;i<fontNames.length;++i) {
   for(int j=0;j<styles.length;++j) {
    Font newFont = new Font(fontNames[i],styles[j],size);
    FontMetrics fm = g.getFontMetrics(newFont);
    g.setFont(newFont);
    String text = fontNames[i]+"-"+styleNames[j];
    int x = (screenWidth - fm.stringWidth(text))/2;
    g.drawString(text,x,y+fm.getLeading()+fm.getAscent());
    y += fm.getHeight();
   }
  }
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id==Event.ACTION_EVENT){
   if(event.target instanceof MenuItem){
    if("Exit".equals(event.arg)){
     System.exit(0);
     return true;
    }
   }
  }
  return false;
 }
}


The FontApp program does not provide much functionality. Just run it and it will display a list of the fonts that are currently available to Java, with each name written in its font. Figure 22.1 shows its display. The program's importance is not what it does, but in how it does it. By closely examining this program, you'll be able to quickly come up to speed on working with Java fonts.

Figure 22.1 : The FontApp opening window.

The FontApp class declares a number of field variables. The toolkit variable is used to refer to the Toolkit object associated with the program window. The defaultFont variable identifies the default font used by the program. The fontNames[] array is used to store the names of the fonts that are accessible to Java.

The setupFonts() method obtains the Toolkit object associated with the program's window using the getToolkit() method and assigns this object to the toolkit variable. The current font used by the program is accessed by getFont() and assigned to the defaultFont variable. The Toolkit object is then used to obtain the current list of font names via the getFontList() method of the Toolkit class. That's all for the program's setup. The program's event handling is the standard Exit menu item and WINDOW_DESTROY event processing.

The paint() method is where the primary processing of interest takes place. The styles[] and styleNames[] arrays are used to identify the various text styles and their associated string descriptions. The y variable identifies the vertical screen position where text is displayed. The size variable identifies the point size used to display a font.

The paint() method uses two for statements. The outer statement iterates through the list of font names, and the inner statement iterates through the font styles. At each passes through the inner loop, a new font is created with the specified name, style, and size. The getFontMetrics() method of the Graphics class is used to obtain the FontMetrics object associated with the newly created font and this object is assigned to the fm variable. The setFont() method of the Graphics class is used to set the current font to the new font.

The next line of text to be displayed is created by concatenating the font name and its style name. The horizontal position at which the text is to be displayed in order for it to be centered is calculated based on the width of the text (in pixels) returned by the stringWidth() method of the FontMetrics class and the initial width of the program window. The vertical position where the text is to be displayed is its baseline and is determined by adding the leading and ascent values of the font with the y variable. These values are obtained using the getLeading() and getAscent() methods of the current FontMetric object. The y variable identifies the point of maximum descent of the previously displayed line of text. It is then updated for the current line of text by adding the height of the current font returned by the getHeight() method of the FontMetric class.

WYSIWYG Editors

The Font and FontMetrics classes are not confined to text that is drawn on Graphics objects. These classes can also be used with the TextField and TextArea classes. These classes automatically calculate the correct text-display locations using the native text objects supported by the local operating-system platform. In addition to changing text fonts, the TextField and TextArea classes also support the display of text using different foreground and background colors. The following program shows how fonts and colors can be quickly incorporated into a Java program to implement features associated with what-you-see-is-what-you-get (WYSIWYG) editors.

The EditApp Program

The EditApp program shows how the Font and Color classes can be incorporated into the TextEdit program introduced in Chapter 18, "Opening Windows." Its source code is shown in Listing 22.2.

The EditApp program uses the FontDialog and ColorDialog classes that are introduced in subsequent sections. In order to compile and run EditApp.java, you will need to type in the FontDialog.java and ColorDialog.java files. Java will automatically compile the FontDialog.java and ColorDialog.java files when EditApp.java is compiled.


Listing 22.2. The source code of the EditApp program.

import java.awt.*;
import java.io.*;
import jdg.ch20.*;
import jdg.ch22.FontDialog;
import jdg.ch22.ColorDialog;

public class EditApp extends Frame {
 String programName;
 Object menuItems[][] = {
  {"File","New","Open","-","Save As","-","Exit"},
  {"Format","Font","Color"}
 };
 MyMenuBar menuBar = new MyMenuBar(menuItems);
 TextArea text;
 FileDialog openFile = new FileDialog(this,"Open File",FileDialog.LOAD);
 FileDialog saveFile = new FileDialog(this,"Save File As",FileDialog.SAVE);
 FontDialog fd;
 ColorDialog cd;
 Font currentFont = new Font("Courier",Font.PLAIN,12);
 Color currentColor = Color.black;
 public static void main(String args[]){
  EditApp app = new EditApp();
 }
 public EditApp() {
  super("WYSIWYG Text Editor");
  programName = getTitle();
  setup();
  pack();
  resize(text.preferredSize());
  show();
 }
 void setup() {
  setBackground(Color.white);
  text = new TextArea(25,80);
  text.setFont(currentFont);
  add("Center",text);
  setMenuBar(menuBar);
  setCursor(TEXT_CURSOR);
 }
 public void readFile(String file) {
  DataInputStream inStream;
  try{
   inStream = new DataInputStream(new FileInputStream(file));
  }catch (IOException ex){
   notifyUser("Error opening file");
   return;
  }
  try{
   String newText="";
   String line;
  while((line=inStream.readLine())!=null)
   newText=newText+line+"\n";
  text.setText(newText);
   inStream.close();
  }catch (IOException ex){
   notifyUser("Error reading file");
  }
 }
 public void writeFile(String file) {
  DataOutputStream outStream;
  try{
   outStream = new DataOutputStream(new FileOutputStream(file));
  }catch (IOException ex){
   notifyUser("Error opening file");
   return;
  }
  try{
   outStream.writeBytes(text.getText());
   outStream.close();
  }catch (IOException ex){
   notifyUser("Error writing file");
  }
 }
 public void notifyUser(String s) {
  String text[] = {s};
  String buttons[] = {"OK"};
  new Notification(this,"Error",true,text,buttons);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
  return true;
 }else if(event.id==Event.GOT_FOCUS && !(event.target instanceof TextArea)) {
  setCursor(DEFAULT_CURSOR);
  return true;
 }else if(event.id==Event.LOST_FOCUS) {
  setCursor(TEXT_CURSOR);
  return true;
 }else if(event.id==Event.ACTION_EVENT){
  String arg = (String) event.arg;
  if(event.target instanceof MenuItem){
   if(processFileMenu(arg)) return true;
   if(processFormatMenu(arg)) return true;
  }else if(event.target instanceof Button){
  if("Select".equals(arg)){
   if(fd != null) {
   if(fd.isChanged()) {
    currentFont = fd.getFont();
    fd.dispose();
    text.setFont(currentFont);
   }
  }
   if(cd != null) {
    if(cd.isChanged()) {
     currentColor = cd.getColor();
     cd.dispose();
     text.setForeground(currentColor);
     text.setText(text.getText());
    }
   }
  }
 }
}
return false;
}
public boolean processFileMenu(String s) {
 if("New".equals(s)){
  text.setText("");
  return true;
 }else if("Open".equals(s)){
  openFile.show();
  String inFile = openFile.getFile();
  readFile(inFile);
  return true;
 }else if("Save As".equals(s)){
  saveFile.show();
  String outFile = saveFile.getFile();
  writeFile(outFile);
  return true;
 }else if("Exit".equals(s)){
  System.exit(0);
  return true;
 }
 return false;
 }
 public boolean processFormatMenu(String s) {
 if("Font".equals(s)){
  fd = new FontDialog(this,currentFont);
  fd.show();
  return true;
 }else if("Color".equals(s)){
  cd = new ColorDialog(this,currentColor);
  cd.show();
  return true;
 }
 return false;
 }
}
class Notification extends MessageDialog {
 public Notification(Frame parent,String title,boolean modal,String text[],
 String buttons[]) {
 super(parent,title,modal,text,buttons);
 }
 public boolean handleEvent(Event event) {
 if(event.id==Event.WINDOW_DESTROY){
  dispose();
  return true;
 }else if(event.id==Event.ACTION_EVENT && event.target instanceof Button){
  dispose();
  return true;
 }
 return false;
 }
}


The EditApp program displays the opening window shown in Figure 22.2.

Figure 22.2 : The EditApp opening window.

Select Open from the File menu as shown in Figure 22.3 and use the Open File dialog box, shown in Figure 22.4, to open the EditApp.java source code file.

Figure 22.3 : The File menu.

Figure 22.4 : The Open File dialog box.

The text of the EditApp.java source file is read into the program and displayed in the window using a 12-point Courier font, as shown in Figure 22.5.

Figure 22.5 : Editing EditApp.java

Select the Font menu item from the Format menu to change the current font used to display the text, as shown in Figure 22.6.

Figure 22.6 : The Format menu.

The Select a font: dialog box is displayed, as shown in Figure 22.7. Use this dialog box to select a 14-point Bold Italic Helvetica font, as shown in Figure 22.8.

Figure 22.7 : The Font dialog box.

Figure 22.8 : Selecting a new font.

The text's display is updated, as shown in Figure 22.9.

Figure 22.9 : Updated text.

Select the Color menu item from the Format menu. The Select a color: dialog box is displayed, as shown in Figure 22.10. Use this dialog box to change the color associated with the text's display. Try using primary colors such as blue or yellow. Other colors might not display correctly, depending on the number of colors supported by your video card and the current color map associated with the display.

Figure 22.10 : The color dialog box.

The EditApp program makes use of the FontDialog and ColorDialog classes, which are covered in the following sections. The basic functionality of the EditApp program remains the same as the TextEdit program. It has been streamlined to use the MyMenuBar and MyMenu classes and adds the fd and cd variables to refer to the FontDialog and ColorDialog objects created by the program.

The setup() method specifies that TEXT_CURSOR should be used, by default, and extra event-handling code has been added to switch between TEXT_CURSOR and DEFAULT_CURSOR, depending on whether the text is in the locus of the text area or the menu bar.

The Notification class has also been updated to take advantage of the MessageDialog class.

The main changes to the EditApp program are to its event handling. The GOT_FOCUS event is handled by checking the target of the event to determine whether it is the TextArea object. If it is not, the cursor is changed to DEFAULT_CURSOR. The cursor is changed back to TEXT_CURSOR when it handles the LOST_FOCUS event. This event is handled when the object getting the focus is the TextArea object.

When an ACTION_EVENT occurs whose target is an instance of the MenuItem class, the processFileMenu() and processFormatMenu() methods are invoked to process the associated menu items. When ACTION_EVENT is an instance of the Button class, signifying a FontDialog or ColorDialog selection, the current objects associated with the fd and cd variables are checked to see which one is associated with an object. The isChanged() methods of the dialog boxes are used to determine whether a font or color change occurred. The getFont() and getColor() methods are used to set the currentFont and currentColor variables, the dialog boxes are disposed of using the dispose() method of the Window class, and the font, color, and text are set appropriately.

The processFileMenu() method checks to see if the currently selected menu item is a File menu item and processes it using the same approach as in the TextEdit program. The processFormatMenu() method checks for a Font or Color menu item and processes the menu item by creating a new FontDialog or ColorDialog object and then displaying the dialog box using the show() method of the Window class.

The FontDialog Class

The FontDialog class provides a handy encapsulation of the dialog boxes commonly used to select a font from the list of available fonts provided by the system. The source code of the FontDialog class is shown in Listing 22.3.


Listing 22.3. The source code of the FontDialog class.

package jdg.ch22;

import java.awt.*;
import jdg.ch21.MyList;

public class FontDialog extends Dialog {
 String fontName;
 int fontStyle;
 int fontSize;
 String fontNames[];
 String styleNames[] = {"Plain","Bold","Italic","Bold Italic"};
 String sizeNames[] = {"10","12","14","18","24","36","72"};
 int styles[] = {Font.PLAIN,Font.BOLD,Font.ITALIC,Font.BOLD+Font.ITALIC};
 int sizes[] = {10,12,14,18,24,36,72};
 MyList fontList;
 MyList styleList = new MyList(5,false,styleNames);
 MyList sizeList = new MyList(5,false,sizeNames);
 Toolkit toolkit;
 Font newFont;
 boolean fontChanged;
 public FontDialog(Frame parent,Font currentFont) {
 super(parent,"Select a font:",true);
 toolkit = parent.getToolkit();
 newFont = currentFont;
 setupFonts();
 setupPanels();
 setBackground(Color.lightGray);
 setForeground(Color.black);
 pack();
 resize(preferredSize());
 }
 void setupFonts() {
 fontName=newFont.getName();
 fontStyle=newFont.getStyle();
 fontSize=newFont.getSize();
 fontNames = toolkit.getFontList();
 fontList = new MyList(5,false,fontNames);
 }
 void setupPanels() {
 Panel mainPanel = new Panel();
 mainPanel.setLayout(new GridLayout(1,3));
 Panel fontPanel = new Panel();
 fontPanel.setLayout(new BorderLayout());
 Label fontLabel = new Label("Font:");
 fontPanel.add("North",fontLabel);
 fontPanel.add("Center",fontList);
 Panel stylePanel = new Panel();
 stylePanel.setLayout(new BorderLayout());
 Label styleLabel = new Label("Style:");
 stylePanel.add("North",styleLabel);
 stylePanel.add("Center",styleList);
 Panel sizePanel = new Panel();
 sizePanel.setLayout(new BorderLayout());
 Label sizeLabel = new Label("Size:");
 sizePanel.add("North",sizeLabel);
 sizePanel.add("Center",sizeList);
 mainPanel.add(fontPanel);
 mainPanel.add(stylePanel);
 mainPanel.add(sizePanel);
 Font plainFont = new Font("Helvetica",Font.PLAIN,12);
 Font boldFont = new Font("Helvetica",Font.BOLD,12);
 mainPanel.setFont(plainFont);
 fontLabel.setFont(boldFont);
 styleLabel.setFont(boldFont);
 sizeLabel.setFont(boldFont);
 Panel buttonPanel = new Panel();
 buttonPanel.setLayout(new FlowLayout());
 buttonPanel.add(new Button("Select"));
 buttonPanel.add(new Button("Cancel"));
 buttonPanel.setFont(boldFont);
 add("Center",mainPanel);
 add("South",buttonPanel);
 }
 public boolean isChanged() {
 return fontChanged;
 }
 public Font getFont() {
 return newFont;
 }
 public boolean handleEvent(Event event) {
 if(event.id==Event.WINDOW_DESTROY){
  dispose();
  return true;
 }else if(event.id==Event.ACTION_EVENT) {
  if(event.target instanceof Button) {
  if("Select".equals(event.arg)) {
   updateNewFont();
   show(false);
   return false;
  }else if("Cancel".equals(event.arg)) {
   dispose();
   return true;
  }
  }
 }
return false;
}
void updateNewFont() {
 if(fontList.getSelectedIndex() != -1) fontName = fontList.getSelectedItem();
 if(styleList.getSelectedIndex() != -1)
  fontStyle = styles[styleList.getSelectedIndex()];
 if(sizeList.getSelectedIndex() != -1)
  fontSize = sizes[sizeList.getSelectedIndex()];
 newFont = new Font(fontName,fontStyle,fontSize);
 fontChanged = true;
 }
}


The FontDialog class creates the Font dialog box shown in Figure 22.7. This type of dialog box is used in most text-processing applications. You can reuse the FontDialog class, as it is currently defined, in your Java programs. You can also subclass FontDialog and add your own custom enhancements.

The FontDialog class declares a number of variables that are used in the generation and processing of the Font dialog box. The fontName, fontStyle, and fontSize variables are used to keep track of the parameters of the currently selected font. The fontNames[] array identifies the names of the fonts that are currently supported by the system. The styles[], styleNames[], sizes[], and sizeNames[] arrays are used to maintain int and String lists of the font styles and sizes that are displayed in the dialog box. The fontList, styleList, and sizeList variables refer to the MyList objects displayed in the dialog box. The toolkit variable refers to the Toolkit object of the window containing the Font dialog box. The fontChanged variable keeps track of whether the user has selected a new font, and the newFont variable maintains the Font object that is selected by the user.

The FontDialog constructor uses the superclass constructor call statement to create a modal dialog box with the title Select a font:. The toolkit associated with the window containing the dialog box is obtained using the getToolkit() method of the Window class. The newFont variable, representing the user's font selection, is set to the default value of the currently selected font. This font is passed to the FontDialog constructor using the currentFont parameter. The FontDialog constructor invokes the setupFonts() and setupPanels() methods to perform the bulk of the dialog box setup. It then packs the dialog box window and resizes it. Note that the constructor does not invoke the show() method to display the dialog box. The actual display of the dialog box must be performed by the containing window.

The setupFonts() method assigns default values to the fontName, fontStyle, and fontSize variables based on the values of the current font stored in the newFont variable. The getFontList() method of the Toolkit class is used to set the fontNames[] array to the list of fonts currently supported by the system. These names are converted to a list using the MyList() constructor.

The setupPanels() method performs all the grunt work, adding the lists to the dialog box and rearranging them in an appealing fashion. The mainPanel variable is used to refer to the overall panel into which the fontPanel, stylePanel, and sizePanel objects are inserted. The mainPanel is laid out as a three-column set of subpanels. These subpanels are identified by the fontPanel, stylePanel, and sizePanel variables. Each of these subpanels is laid out using a BorderLayout object. The label identifying the contents of the panel is added to the top of the panel. The center of each panel contains the three MyList objects identified by the fontList, styleList, and sizeList variables.

The Helvetica font is used for the contents of the Font dialog box. The labels at the top of each column are set in a boldface style. A second panel, referred to by the buttonPanel variable, is created with two buttons: Select and Cancel. These buttons provide the user controls needed to accept or abort a font selection. The mainPanel is added to the center of the Font dialog box and the buttonPanel is added to the bottom.

Two access methods are provided with the FontDialog class. The isChanged() method is used to query a FontDialog object to determine whether the user made a font selection. The getFont() method returns the font selected by the user.

The events handled by FontDialog consist of the WINDOW_DESTROY event and the ACTION_EVENT events associated with the Select and Cancel buttons. The use of the WINDOW_DESTROY event and Cancel button result in the destruction of the FontDialog object. The object is destroyed using the dispose() method of the Window class. The Select button invokes the updateNewFont() method to create a font based on the user's current list selections and assign that font to the newFont variable. The Font dialog box is then hidden but not destroyed. The show() method of the Component class is used to hide the dialog box.

The updateNewFont() method checks the MyList objects referred to by the fontList, styleList, and sizeList variables to update the fontName, fontStyle, and fontSize variables based on the user's selection. These variables are then used to construct a new Font object, which is assigned to the newFont variable. The fontChanged flag is then set to indicate that a user font selection has occurred.

The ColorDialog Class

The ColorDialog class is very similar to, but simpler than, the FontDialog class. It allows the user to select a color from the list of colors defined in the Color class. It provides a dialog box that is similar to that of FontDialog, but is much simpler because only one list-the list of available color-is supported. The source code of the ColorDialog class is shown in Listing 22.4.


Listing 22.4. The source code of the ColorDialog class.

package jdg.ch22;

import java.awt.*;
import jdg.ch21.MyList;

public class ColorDialog extends Dialog {
 Color colors[] = {Color.black,Color.blue,Color.cyan,Color.darkGray,Color.gray,
   Color.green,Color.lightGray,Color.magenta,Color.orange,Color.pink,Color.red,
    Color.white,Color.yellow};
  String colorNames[] = {"black","blue","cyan","darkGray","gray","green",
   "lightGray","magenta","orange","pink","red",
   "white","yellow"};
  MyList colorList = new MyList(5,false,colorNames);
  Color newColor;
  boolean colorChanged;
 public ColorDialog(Frame parent,Color currentColor) {
  super(parent,"Select a color:",true);
  setupPanels();
  setBackground(Color.lightGray);
  setForeground(Color.black);
  pack();
  resize(preferredSize());
 }
 void setupPanels() {
  Panel colorPanel = new Panel();
  colorPanel.setLayout(new BorderLayout());
  Label colorLabel = new Label("Color:");
  colorPanel.add("North",colorLabel);
  colorPanel.add("Center",colorList);
  Font plainFont = new Font("Helvetica",Font.PLAIN,12);
  Font boldFont = new Font("Helvetica",Font.BOLD,12);
  colorLabel.setFont(boldFont);
  colorList.setFont(plainFont);
  Panel buttonPanel = new Panel();
  buttonPanel.setLayout(new FlowLayout());
  buttonPanel.add(new Button("Select"));
  buttonPanel.add(new Button("Cancel"));
  buttonPanel.setFont(boldFont);
  add("Center",colorPanel);
  add("South",buttonPanel);
 }
 public boolean isChanged() {
  return colorChanged;
 }
 public Color getColor() {
  return newColor;
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   dispose();
   return true;
  }else if(event.id==Event.ACTION_EVENT) {
   if(event.target instanceof Button) {
    if("Select".equals(event.arg)) {
     if(colorList.getSelectedIndex() != -1)
      newColor = colors[colorList.getSelectedIndex()];
     colorChanged = true;
     show(false);
     return false;
    }else if("Cancel".equals(event.arg)) {
      dispose();
      return true;
     }
    }
   }
  return false;
 }
}


The ColorDialog class declares the colors[] array as an array of color constants and the colorNames[] array as the names associated with these color constants. The colorList variable refers to the MyList object that presents the colorNames[] array to the user. The newColor variable identifies the color selected by the user, and the colorChanged variable indicates whether a user color selection has been made.

The ColorDialog constructor invokes the Dialog constructor to set the title of the dialog box. It then invokes the setupPanels() method to perform most of the setup of the dialog box's internal components. The foreground and background colors are set and then the dialog box is packed and resized.

The setupPanels() method creates and adds two panels to the dialog box. These panels are identified by the colorPanel and buttonPanel variables. The panel identified by the colorPanel variable contains the Color: label and the MyList object referred to by the colorList variable. The button panel is implemented in the same manner as in the FontDialog class.

The isChanged() and getColor() methods are used to determine whether the user has selected a color and, if so, to return the color selected.

The WINDOW_DESTROY event and the clicking of the Cancel button are handled by invoking the dispose() method of the Window class. This causes the dialog box to be destroyed and its resources to be returned to the system. The clicking of the Select button is handled by invoking the getSelectedIndex() method of the List class to see if a color was selected and setting the newColor variable to the selected color. The colorChanged flag is updated to indicate that a color has been selected and the show() method causes the dialog box to be hidden.

Summary

This chapter covers the details of using the text- and font-related classes. It shows you how to use the text-based classes provided by Java and how to display text with the canvas. It also explains how the Font and FontMetrics classes are used to provide custom control of text display. Chapter 23, "The Canvas," covers the Canvas and Graphics classes.