Skip to main content.

Web Based Programming Tutorials

Homepage | Forum - Join the forum to discuss anything related to programming! | Programming Resources

JAVA Developer's Guide

Chapter 18 -- Opening Windows

Chapter 18

Opening Windows


CONTENTS


This chapter is the first of eight chapters that cover window programming. It introduces you to Java windows by way of several examples that illustrate different aspects of the classes and methods used to implement simple window applications. Its purpose is to quickly get you up to speed developing window-based programs. Subsequent chapters will fill in the details of the classes and methods that are introduced here. You should approach this chapter by trying to get a good general understanding of what is going on in the sample programs without dwelling on the details. You will learn the details when you study them in later chapters.

Hello Windows!

The first program you wrote in Chapter 4, "First Programs: Hello World! to BlackJack," is the HelloWorldApp program. It displays the traditional Hello World! text to the console window. The main purpose of the program was to show you how to develop a simple Java program that actually produced some noticeable effect. The same rationale applies to the HelloWindowsApp program that you'll develop shortly. The program shows you how to open an application window and write the text Hello Windows! to the window. The code for the HelloWindowsApp program is shown in Listing 18.1.


Listing 18.1. The source code of the HelloWindowsApp program.

import java.awt.Frame;
import java.awt.Event;
import java.awt.Graphics;

public class HelloWindowsApp extends Frame {
 public static void main(String args[]){
  HelloWindowsApp app = new HelloWindowsApp();
 }
 public HelloWindowsApp() {
  super("Hello Windows!");
  pack();
  resize(200,200);
  show();
 }
 public void paint(Graphics g) {
  g.drawString("Hello Windows!",50,90);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else return false;
 }
}




When you compile and run the program it opens a small window in the upper-left corner of your desktop and displays the text Hello Windows! in the middle of the window. This program is no giant feat for mankind, but it's a large step for you. It marks your transition from console to window-based programs. Up to this point in the book, console programs served admirably in helping cover the different aspects of the Java language and many of the classes of the API. However, window-based programs and applets (which you learn about in Part VI, "Programming the Web with Applets and Scripts") are the primary areas of interest for most Java programmers. Figure 18.1 shows the window displayed by the HelloWindowsApp program.

Figure 18.1 :The HelloWindowsApp program display.

Let's take a look at HelloWindowsApp and find out what makes it work. You probably noticed right off the bat that we are now importing classes from the java.awt package. The Frame, Event, and Graphics classes shown in the import statements are classes that are fundamental to developing window programs. The Frame class is used to create Frame objects that implement application main windows. The Event class is used to process user-generated interface events, such as mouse clicks and keyboard input, and the Graphics class is used to update the screen display.

The HelloWindowsApp class extends the Frame class. This is a typical approach to developing window programs. By subclassing Frame, your application class implements a main application window. You still use the same old main() method for implementing the entry point to your program. In HelloWindowsApp, the main() method simply creates a default object of class HelloWindowsApp.

The HelloWindowsApp constructor uses the super() constructor call statement to invoke the Frame constructor with the string "Hello Windows!". The Frame constructor creates a new application window frame with the specified text as its title. The pack() method is used to pack the components of the window and set the window's size based upon the size of these components. It is inherited from the Window class, which is the superclass of Frame. The resize() method then resizes the window to a 200¥200 pixel dimension. The resize() method is inherited from the Component class by way of the Container, Window, and Frame classes. Finally, the show() method is used to cause the window to be displayed. It is inherited from the Window class.

You might be wondering how the "Hello Windows!" text is actually displayed because there is no call from main() or HelloWindowsApp() to the paint() method. When a window or any other object that is in a subclass of Component is initially displayed or redisplayed as the result of the window being uncovered or brought to the foreground, the paint() method is invoked. It then paints the window according to the current application state.

The paint() method used by HelloWindowsApp overrides the paint() method inherited from the Component class. It takes a Graphics object as a parameter. The Graphics class provides numerous easy-to-use methods for drawing on Graphics objects. The paint() method uses the drawString() method to display the text "Hello Windows!" at the screen coordinate 50,90 within the application window.

Window coordinates are organized with the upper-left corner of the window being 0,0. The coordinates of the upper-right corner of the window are width,0, where width is the horizontal width of the window in pixels. The coordinates of the lower-left corner of the window are 0,height, where height is the vertical height of the window in pixels. Finally, the coordinates of the lower-right corner of the window are width,height. Figure 18.2 illustrates the window coordinate system.

Figure 18.2 :Window coordinates.

You probably have been wondering what the handleEvent() method is doing in the HelloWindowsApp class. The handleEvent() method provides a standard approach to event handling in Java applications. Events represent actions that occur during the course of program execution. Most events are generated as the result of user actions such as mouse clicks and keyboard actions. The handleEvent() method overrides the method inherited from the Component class. It takes an object of the Event class as a parameter and uses the methods and constants of the Event class to determine what event was passed to it and how it should be handled. The handleEvent() method returns a boolean value indicating whether or not the event has been handled. If a false value is returned, the event is propagated to the handleEvent() method of the parent of the class that is currently handling the event. If a true value is returned, no further event propagation takes place.

The handleEvent() method of HelloWindowsApp checks the id variable of the event to see if it equals the constant Event.WINDOWS_DESTROY. The id variable and the WINDOWS_DESTROY constant both are defined in the API of the Event class. The id variable is used to identify what type of event occurred, and the Event class constants specify the event types. In this example, the event handler only handles the WINDOW_DESTROY event. This event occurs when the user closes the main application window by clicking the Close Window icon, as shown in Figure 18.3.

Figure 18.3 :Terminating the HelloWindowsApp program.

The WINDOW_DESTROY event is handled by invoking the exit() method of the System class to terminate the program. The true value is returned to indicate that the event was handled.

You might be wondering what would happen if the event handler did not handle the WINDOW_DESTROY event. Try deleting the handleEvent() method and recompiling and rerunning HelloWindowsApp to see what happens when you try to terminate the application.

Going Round in Ovals: A Graphics Program

The HelloWindowsApp program provided a simple introduction to window programming. It illustrated many of the basics of writing a window program, but it didn't actually do all that much. The OvalApp program is also an introductory window program. It introduces more window programming classes and methods such as panels, buttons, layouts, additional event handling, and, of course, oval drawing. The source code of OvalApp is shown in Listing 18.2.


Listing 18.2. The source code of the OvalApp program.

import java.awt.*;
import java.util.Random;

public class OvalApp extends Frame {
 int screenWidth = 400;
 int screenHeight = 400;
 Oval oval;
 public static void main(String args[]){
  OvalApp app = new OvalApp();
 }
 public OvalApp() {
  super("Let's Draw Ovals!");
  Panel buttons = new Panel();
  buttons.add(new Button("Next"));
  buttons.add(new Button("Quit"));
  add("South",buttons);
  oval = new Oval(screenWidth,screenHeight);
  pack();
  resize(screenWidth,screenHeight);
  show();
 }
 public void paint(Graphics g) {
  oval.paint(g);
 }
 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 Button){
    if("Next".equals(event.arg)){
     oval.update();
     repaint();
     return true;
    }else if("Quit".equals(event.arg)){
     System.exit(0);
     return true;
    }
   }
  }
  return false;
 }
}

class Oval {
 int x, y, width, height, maxWidth, maxHeight;
 Color color;
 static Random r = new Random();
 public Oval(int w,int h) {
  super();
  maxWidth = w;
  maxHeight = h;
  update();
 }
 public void update() {
  x = Math.abs(r.nextInt() % (maxWidth-100));
  y = Math.abs(r.nextInt() % (maxHeight-100));
  width = (maxWidth - x)/3;
  height = (maxHeight - y)/3;
  int rgb[] = new int[3];
  for(int i=0;i<3;++i) rgb[i]=Math.abs(r.nextInt()%256);
  color = new Color(rgb[0],rgb[1],rgb[2]);
 }
 public void paint(Graphics g) {
  g.setColor(color);
  g.fillOval(x,y,width,height);
 }
}


When you run the OvalApp program it displays a window with the title Let's Draw Ovals!. A colored oval is displayed somewhere in the application window, as shown in Figure 18.4.

Figure 18.4 : The OvalApp startup display

The window has two buttons, labeled Next and Quit. When you click on the Next button, as shown in Figure 18.5, a different oval is displayed.

Figure 18.5 : The Next button.

You can continue to click on the Next button to cause different colored ovals to be displayed in different parts of the window, as shown in Figure 18.6.

Figure 18.6 : A new oval is displayed.

When you have thoroughly amused yourself by drawing ovals, you can click on the Quit button, as shown in Figure 18.7, and terminate the program's execution.

Figure 18.7 : The Quit button.

The OvalApp program is cute and entertaining, but doesn't perform any useful processing. However, it does provide a good example of some new window programming constructs.

The program begins by doing an import of the relevant classes of the java.awt package. The program uses a large number of java.awt classes and, rather than listing each one individually, uses the more general package import statement to eliminate the trouble of typing each one in individually. The only other class that is included is the Random class of the java.util package. This class provides the capability to generate random numbers to be used in the oval drawing.

The OvalApp class extends Frame in the same manner as the HelloWindowsApp. Three variables are defined for the OvalApp class. The screenWidth and screenHeight variables define the dimensions of the main window. The oval variable is used to refer to the current Oval object being displayed. The main() method simply creates a new object of class OvalApp.

The OvalApp constructor sets the window title using the superclass constructor call statement, super(). It then creates a Panel object called buttons. Panels are window objects that are used as containers for other objects. They help to organize the way GUI controls are placed in windows. The buttons panel will be used to organize the Next and Quit buttons. The add() method is used with buttons to add two new objects of class Button to the panel. The Button constructor takes a string argument that is the label for the buttons. The add() method is then invoked for the OvalApp object being constructed to add the panel to the OvalApp application window. The OvalApp add() method is inherited from the Container class. The "South" string identifies where the panel should be added in the application window.

The organization of objects within a window container is governed by the layout of the container. (Layouts are described in detail in Chapter 19, "Organizing Window Programs.") The default layout for Frame objects and their subclasses is BorderLayout. This type of layout organizes objects within a container by their North, South, East, and West borders. Objects can also be placed in the Center of a container. The add("South",buttons); method invocation adds the buttons panel to the southern (bottom) border of the OvalApp window.

The buttons panel is also associated with a layout. Panels use a FlowLayout object, by default. The FlowLayout class organizes objects in a container in a left-to-right fashion, fitting as many objects as possible in a row before moving on to fill the next row.

The oval variable is assigned a new object of class Oval that is parameterized by the screenWidth and screenHeight dimensions. These arguments are passed to the Oval constructor to make sure that an Oval object is created that is appropriate for the screen size of the OvalApp window. The Oval class is discussed after the OvalApp class's description is completed.

After adding the buttons panel to the window and creating an Oval object, the pack() method is invoked to organize the components of the window and to determine the minimum preferred size of the window. The resize() method then adjusts the screen to the specified width and height dimensions. Finally, the show() method causes the window to be displayed.

The paint() method for the OvalApp class simply passes the task of drawing the window to the Oval class. Notice that it passes on the Graphics object that it receives to the Oval paint() method. Without the Graphics object, Oval's paint() method would have nothing to draw on.

The handleEvent() method for OvalApp doesn't fare as well as the paint() method. Instead of handing off its processing to other classes, it provides a central point for all program event handling. It processes the WINDOWS_DESTROY event in the same manner as the HelloWindowsApp program. It also checks for events of type ACTION_EVENT. Events of this type are typically generated by performing actions on GUI controls-for example, clicking on a button, selecting a menu item, or checking a checkbox. In this case, the method is checking whether the Next or Quit button was clicked. It does this by checking the target variable of the event to see if it is an instance of class Button. The target variable identifies the object that is the target of the event being processed.

The event.arg variable is event specific. It typically provides a value that is used to identify the specific object from its class for which the event was generated. In the case of Button objects, it represents the label of the button. The arg variable is used to determine whether the button being clicked on is the Next button or the Quit button.

When the Next button is clicked, the button-clicked event is handled by invoking the update() method of the oval variable and repainting the screen. The update() method causes the oval's color, position, and size parameters to be changed. The repaint() method results in the paint() method being reinvoked to redraw an object-in this case, the OvalApp window. You should never invoke paint() directly-it is under the control of the native windows implementation. Always access it by invoking repaint().

When the Quit button is clicked, the OvalApp program terminates in the same manner as when the WINDOW_DESTROY event occurs.

The Oval class is used to randomly generate ovals of different colors, sizes, and positions and display them in the OvalApp window. It defines a number of variables that specify these parameters. The maxWidth and maxHeight variables store the dimensions of the application window. The width and height parameters store the actual width and height of an Oval object. The x and y parameters identify its position within the application window. The color parameter identifies the color in which the oval is to be drawn. The static r variable is an object of class Random that is used to generate random numbers that determine the oval's characteristics.

The Oval constructor explicitly calls the default constructor call statement, sets the maxWidth and maxHeight variables, and invokes its update() method to randomly generate the values of the rest of the variables defined by the Oval class.

The update() method sets the upper-left corner of the oval to a random value between (0,0) and (maxWidth=100,maxHeight=100). This keeps the oval from scrunching up against the window's borders. The width and height of the rectangle are set to one-third of the distance between the upper-left corner of the rectangle and the lower-right corner of the application window.

The red, blue, and green color intensities of the rectangle are randomly generated as values between 0 and 255. In order for the full range of color values to be displayed, your screen must support 24-bit color in its current screen resolution; otherwise, the randomly generated color will be approximated by the next closest color supported by your video card. I rarely set my screen to 24-bit color and usually use 8-bit color to cut down on my video-display memory requirements.

The paint() method of the Oval class uses the Graphics object passed to it by the OvalApp paint() method to display the oval. It sets the current color of the Graphics object based on the randomly generated color stored in the color variable. It then invokes the fillOval() method of the Graphics class to draw an oval that is filled with the current color. The fillOval() method takes the upper-left corner of the Oval and its width and height dimensions as parameters.

A Text Editor

Now let's extend your exploration of window applications by developing a primitive text editor. The TextEditApp program illustrates more window programming constructs. It introduces menus, dialog boxes, fonts, text processing, and window-based file I/O. It also builds on the event-handling skills that you've developed so far. The source code of the TextEditApp program is shown in Listing 18.3.


Listing 18.3. The source code of the TextEditApp program.

import java.awt.*;
import java.io.*;

public class TextEditApp extends Frame {
 TextArea text;
 MenuBar menuBar;
 FileDialog openFile;
 FileDialog saveFile;
 public static void main(String args[]){
  TextEditApp app = new TextEditApp();
 }
 public TextEditApp() {
  super("Text Editor");
  setup();
  resize(text.minimumSize());
  pack();
  show();
 }
 void setup() {
  setFont(new Font("System",Font.PLAIN,12));
  setBackground(Color.white);
  text = new TextArea(25,80);
  add("Center",text);
  setupMenuBar();
  openFile = new FileDialog(this,"Open File",FileDialog.LOAD);
  saveFile = new FileDialog(this,"Save File As",FileDialog.SAVE);
 }
 void setupMenuBar(){
  menuBar = new MenuBar();
  Menu fileMenu = new Menu("File");
  fileMenu.add(new MenuItem("New"));
  fileMenu.add(new MenuItem("Open"));
  fileMenu.addSeparator();
  fileMenu.add(new MenuItem("Save As"));
  fileMenu.addSeparator();
  fileMenu.add(new MenuItem("Exit"));
  menuBar.add(fileMenu);
  setMenuBar(menuBar);
 }
 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("New".equals(event.arg)){
     text.setText("");
     return true;
    }else if("Open".equals(event.arg)){
     openFile.show();
     String inFile = openFile.getFile();
     readFile(inFile);
     return true;
    }else if("Save As".equals(event.arg)){
     saveFile.show();
     String outFile = saveFile.getFile();
     writeFile(outFile);
     return true;
    }else if("Exit".equals(event.arg)){
     System.exit(0);
     return true;
    }
   }
  }
  return false;
 }
 public void readFile(String file) {
  DataInputStream inStream;
  try{
   inStream = new DataInputStream(new FileInputStream(file));
  }catch (IOException ex){
   notifyDialog("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){
   notifyDialog("Error reading file");
  }
 }
 public void writeFile(String file) {
  DataOutputStream outStream;
  try{
   outStream = new DataOutputStream(new FileOutputStream(file));
  }catch (IOException ex){
   notifyDialog("Error opening file");
   return;
  }
  try{
   outStream.writeBytes(text.getText());
   outStream.close();
  }catch (IOException ex){
   notifyDialog("Error writing file");
  }
 }
 public void notifyDialog(String msg) {
  Notification notification = new Notification(this,msg);
  notification.show();
 }
}
class Notification extends Dialog {
 String msg;
 public Notification(Frame f,String s) {
  super(f,"Notification",true);
  msg = s;
 }
 public void show() {
  add("North",new Label(msg,Label.CENTER));
  Panel p = new Panel();
  p.add(new Button("OK"));
  add("South",p);
  setBackground(Color.gray);
  resize(160,100);
  super.show();
 }
 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("OK".equals(event.arg)){
     dispose();
     return true;
    }
   }
  }
  return false;
 }
}


The TextEditApp program provides quite a bit more functionality than the other window programs that you've written so far. After you've compiled it, run the program. It will begin by launching a blank text-editing window with the Text Editor title, as shown in Figure 18.8.

Figure 18.8 : The TextEditApp opening window.

Click in the editor window and begin experimenting with editing text. Type in whatever text comes to your mind. Experiment with tabs to see how they work. Try typing past the right margin to see how the horizontal scrollbars work. Select text with your cursor and use the keyboard copy, cut, and paste commands. Double-click on a word to select it, and then type another word over it. Try typing a few lines to cause the vertical scrollbars to come into play. Your screen should look somewhat similar to Figure 18.9.

Figure 18.9 : Editing text

When you have finished editing the text, check out the File pull-down menu shown in Figure 18.10. You'll notice that the File menu supports four commands and contains two separator lines that help organize these commands.

Figure 18.10 : The File pull-down menu

Save your text in the file test.txt. A File Save As dialog box appears to help you save your file. The Windows 95 implementation of Java displays a dialog box, as shown in Figure 18.11. If you are using Java on another operating system, the dialog box will look different.

Figure 18.11 : Saving text to a file.

After you have saved your file, select New from the File menu. A new text-editing buffer is displayed. Having cleared the buffer, select Open from the File menu and open the test.txt file that you just saved. (See Figure 18.12.) This file will be read in and loaded into the text-editing buffer.

Figure 18.12 : Opening a file.

If this seems like a lot of functionality for two pages of code, you're right. Java does most of the work for you. You just need to invoke the correct methods for the java.awt API classes.

Let's explore the TextEditApp program to see how it works. You'll first notice that it imports the classes of the java.awt and java.io classes. The java.awt package provides the required window classes, and the java.io package provides needed file I/O classes.

TextEditApp follows the lead of the other window programs developed earlier in this chapter and subclasses the Frame class. It declares four field variables: text, menuBar, openFile, and saveFile. The text variable is of class TextArea. It holds the object that implements the functionality of the text-editing buffer. The menuBar variable sets up the File menu. The openFile and saveFile variables support the file dialog boxes shown in Figures 18.11 and 18.12.

The main() method simply creates an object of TextEditApp. The TextEditApp constructor sets the window title using the constructor of the Frame class and then invokes its setup() method to set up all the objects in the TextEditApp window. The resize() method is called to size the application window based on the minimum size required to implement the TextArea object assigned to text. The pack() and show() methods complete the TextEditApp window setup and display.

The setup() method sets the font to be used in the TextArea object, changes the window's background color, and then sets up the TextArea object, the menu bar, and the file dialog boxes. The setFont() method sets the current font to a newly constructed font. It is inherited from the Component class. The Font class constructor used to create the new font uses the font name (System), text type (PLAIN), and point size (12) of the font as parameters. The Font class defines a number of font parameters that can be used in constructing new font variations.

The setBackground() method sets the background color to white. It is inherited from the Component class. The Color class provides a number of predefined color constants. The text variable is assigned an object of class TextArea that is at least 25 rows by 80 columns. This object implements most of the text-editing capabilities of TextEditApp. It is then added to the center of the TextEditApp window. The setupMenuBar() method is called to set up the File menu.

The openFile and saveFile FileDialog variables are assigned newly created FileDialog objects. The FileDialog constructor takes three arguments. The first is the window that "owns" the dialog box. This is the window to which the file dialog box is attached. The window is attached to the TextEditApp object created by the main() method, so the this argument is supplied to identify the current TextEditApp object. The second parameter is the text string to be displayed at the top of the dialog box. Refer to Figures 18.11 and 18.12 to see how the text string is displayed. The third parameter is either the FileDialog.LOAD or the FileDialog.SAVE constant, indicating whether a file is to be loaded from disk or saved to disk.

The setupMenuBar() method shows how menu bars are created and added to a window. The menuBar variable is assigned an object of class MenuBar. A Menu object is created with the File label and assigned to the fileMenu variable. Menu items and separators are then added to the menu. A Menu object represents a single pull-down menu. A MenuItem object is a pull-down menu selection. A MenuBar object is a collection of Menu objects that is attached to a window.

The MenuItem objects are assigned a label when they are created. They are added to the fileMenu in a top-down fashion. The addSeparator() method is used to add a separator line to a menu. Refer to Figure 18.10 to see how the resulting File menu is displayed. The fileMenu is added to the menuBar object using the add() method of the MenuBar class. The resulting menu bar is added to the TextEditApp window using the setMenuBar() method inherited from the Frame class.

At this point you might have noticed that the TextEditApp class has no paint() method. The TextArea object takes care of drawing itself and does not require an external paint() method. TextArea is a remarkably self-contained and easy-to-use class. Without TextArea, implementing TextEditApp would be considerably more difficult.

The handleEvent() method handles more events than in previous examples. It handles the WINDOW_DESTROY event in the usual manner. This editor is just a prototype-a complete text editor would prompt the user to save any changes before terminating the application. All other events processed are of type ACTION_EVENT and have as their target objects of class MenuItem. In other words, these events process selections from the File menu. MenuItem objects are distinguished by their labels as supplied to the arg variable of an event.

The handling of the New menu item invokes the setText() method of the TextArea class to delete all text in the text variable. The handling of the Open menu item invokes the show() method for the openFile FileDialog, causing the dialog box to be displayed. The getFile() method is invoked to get the name of the file selected for opening by the user. The returned string is then passed to the readFile() method of TextEditApp. The handling of the Save As menu item is similar to that of the Open menu item. The saveFile FileDialog is displayed. A filename is returned and then passed to the writeFile() method of the TextEditApp class. The Exit menu item is handled in the same way as the WINDOW_DESTROY event. Again, a complete editor would prompt the user to save changes before exiting.

The readFile() method reads the file whose name was retrieved via the openFile FileDialog. It first opens the file by creating a new FileInputStream object using the filename and then filtering this stream as a DataInputStream object. The resulting input stream is then assigned to the inStream variable. The try statement has a catch clause that checks for the occurrence of an IOException. If an exception occurs, the notifyDialog is used to warn the user. It displays a dialog box as shown in Figure 18.13. You can cause this dialog box to be generated by trying to open a non-existent file. Try it!

Figure 18.13 : The Notification dialog box.

After the file has been opened, its text is read in a line at a time and appended to the newText variable. This results in the input being placed in one long string. The setText() method of the TextArea class is used to move the text into the TextArea object assigned to the text variable. Any I/O errors occurring while the file is being read result in the display of a notification dialog box with the Error reading file message.

The writeFile() method operates in a similar but reverse manner than the readFile() method. It uses the filename retrieved via the saveFile FileDialog to create a FileOutputStream object. It then filters this stream as a DataOutputStream and assigns it to the outStream variable. If any errors occur in the creation of these streams, a dialog box is displayed with the message Error opening file.

After opening the file, the writeBytes() method of the DataOutputStream class is invoked to write the data stored in the TextArea object assigned to the text variable to the output stream. The close() method is then invoked to close the output stream. Any write errors result in the display of an error-notification dialog box.

The notifyDialog() method supports the generation and display of dialog boxes by creating new instances of the Notification class and passing them the error message. It then invokes their show() method to display them.

The Notification class actually implements the dialog boxes that are displayed when an error occurs by extending the Dialog class. The Dialog class, like the Frame class, extends the Window class. It provides a different set of methods to display dialog boxes as opposed to main application windows. It has one variable, msg, that stores the message to be displayed in the dialog box. Its constructor takes two arguments: the application window object to which it is attached and the message to be displayed. It invokes the Dialog class constructor using the superclass constructor call statement and passes it the Frame object, the string "Notification" to be used as the title of the dialog box, and the true boolean value, which determines whether the dialog box will be modal. A modal dialog box is one that must be closed before the user can return to the main application window. (Java currently does not implement this blocking feature of modal dialog boxes.) The constructor then saves the error message argument in the msg variable.

The show() method of the Notification class causes the dialog box to be displayed. It first creates an object of class Label with the contents of the msg variable being the text assigned to the Label object. The Label.CENTER constant is used to center the text in the Label object. The new label is then added to the North end of the dialog box. Dialog objects, like Frame objects, use a BorderLayout object by default. A Panel object is then created, and the OK button is created and added to the panel. The panel is added to the South end of the dialog box. The single button was placed in the panel to cause the button into be displayed in its default dimensions. Instead of the button being stretched to fit the dialog box, the panel in which the button resides is stretched. To see this, try directly inserting the button to the dialog box without using a panel. The background color of the dialog box is set to gray using the setBackground() method inherited from the Component class and the Color class constants. The window is resized to 160¥100 pixels and then displayed using the show() method of the Dialog class. The super keyword is used to indicate that the show() method of the superclass (Dialog) should be used instead of the show() method of the current class (Notification).

The Notification class handles its own events by overriding the handleEvent() method. The WINDOW_DESTROY event is generated for a dialog box when the user tries to directly close the dialog box without using any of the dialog box buttons. This event is different from the event generated for the main application window. The Notification event handler handles the WINDOW_DESTROY event by invoking the dispose() method inherited from the Window class. The dispose() method causes the dialog window to be closed and its resources to be returned to the system. The handleEvent() method handles the OK button click by looking for an event with an id set to ACTION_EVENT, checking its target to make sure that it is an instance of the Button class and checking its arg variable to make sure that it is the OK button. It then invokes the dispose() method to close the dialog box.

Summary

This chapter introduces you to window programming by way of several sample programs that illustrate the classes and methods used to implement simple window applications. You should now be comfortable with analyzing window-based programs. Subsequent chapters fill in the details of the classes and methods introduced here. They will help you to become proficient in developing your own window programs. Chapter 19 lays the framework for developing window programs by expanding on the basics introduced here.