# Chapter 18

# Using Java Applications in the Real World

### CONTENTS

- Bigger, Better, Faster Applications
- Conceptualizing a Real-World Application
  - Useful Online Resources
  - Determining Requirements
- Designing a Real-World Application
  - Overall Design and Layout
  - Design for the Main Window
  - Design for the Menu Bar
  - Design for the SlidePanel Object
  - Design for the SlideCanvas Object
  - Design for the SlideText Object
  - Design for the Controls
  - Design for the Dialog Boxes
  - File I/O
  - Relationships Among Objects
- Implementing a Real-World Application
  - Building the Main Window
  - Adding the SlidePanel Class
  - Adding the SlideCanvas Object
  - Adding the SlideText Object
  - Adding the Controls
  - Adding the Dialog Boxes
- The Complete Project
- Testing and Debugging
- Summary

Real-world applications differ from the simple stand-alone applications, such as `SumGraph`, in their size, complexity, and usefulness. This chapter introduces you to many of the techniques used to develop large applications.

This chapter works through a single example of an intermediate Java application and introduces additional tools and objects that are useful in building larger applications in Java. The chapter ends with a test plan for the application.

## Bigger, Better, Faster Applications

Real-world applications are expected to have rapid response times; user-friendly help screens; attractive, well-thought-out layouts; and an easy-to-understand organization. Many features that are not necessary in applets are expected in applications.

Adding the features expected for applications increases the amount of programming required. Some features, such as menu layout and frame appearance, are expected to appear similarly amongprograms running on the same operating system. Most applications include an About box giving version, copyright, and authoring information. Applications also may include registration screens, graphical toolbars, pop-up information windows, and many other tools.

Java can be used to develop programs with all these features, although some are easier to include than others. The basic technique for developing applications remains the same as the programs grow. However, greater care must be taken with the design to allow for the additional features and to provide sufficient robustness to meet the needs of sophisticated users. A well-designed program can be easily broken into pieces so that a different person or team can work on each section. The sections then can be seamlessly joined to produce a working program in a short time period.

As more tools and utilities become available for Java, development time will be reduced. Because Java is object-oriented, incorporating existing utilities into Java programs is straightforward; recall how easy incorporating the `ScrollText` applet into the application was in Chapter 17, "Creating a Stand-alone Application."

With the `java.awt` package, you can create a program whose appearance reflects the operating system on which it runs. Therefore, programmers can incorporate features into their applications without worrying about how it will look on each platform.

Looking Ahead
In this chapter you will be working through the development of a more complex application. The application includes several features common in real-world applications. Many of these features are introduced in the sample application in Chapter 17, but the examples given here are significantly more robust. The discussions here will help prepare you for the advanced programs presented in Part VII, "Advanced Issues."

## Conceptualizing a Real-World Application

Chapter 17 shows how the design of a simple application can be modified as it is created. This chapter develops a more complex example with more of the features found in real-world applications.

The design of a large application is generally an iterative breakdown process: The application is divided into smaller pieces and a design is constructed for each piece. One of the key engineering decisions is where to divide the pieces, which is not always obvious from the specification. It is not necessary that the pieces be of equivalent size or complexity, but it is necessary that they be well defined and have distinct boundaries.

### Useful Online Resources

In developing larger applications, you can realize significant time savings if you use utilities that have already been developed. One of the greatest advantages of Java is the ease with which utilities can be shared among developers.

Some of these utilities are available through sites on the Internet. You can find counters, parsers, string tokenizers, and URL verifiers, just to name a few.

Some likely online sources for Java utilities include

> `http://www.yahoo.com/Computers_and_Internet/Languages/Java/Utilities/
> http://www.gamelan.com/
> http://www.blackdown.org/~kbs/`

Try these sites and others to find useful utilities to incorporate into your applications.

### Determining Requirements

The specification for the `SlideShow` application to be developed in this chapter is simply this:

> The application will display a slide show of multiple GIF images with related text.

Although this specification does not mention menus or controls, it is safe to assume these are expected. It is also reasonable to expect to provide a means of loading a show from a file and a graceful mechanism to exit the application.

Expanding on this definition, `SlideShow` must perform the following tasks:

- Load a show from a file
- Display images
- Display text
- Advance forward to the next slide
- Return to the previous slide
- Go to the last slide
- Go to the first slide
- Enable/disable the display of slides
- Enable/disable the display of text
- Provide help
- Provide authoring information
- Exit the program

## Designing a Real-World Application

In this section the entire application is divided into objects, resulting in actual objects to be implemented in Java. In some cases, the objects are composed of other objects that you must define and implement. The process stops when all the components necessary to complete the tasks listed in the requirements are defined. These components will be either implemented as new classes in Java or created using existing Java class definitions.

### Overall Design and Layout

First, you need to define the main features of the application. Applications are usually designed around one main viewing area with additional tools provided in separate windows. The main viewing area is where the user focuses when running the application; therefore, it should be well designed and pleasant to the viewer.

The application's viewing area can be made up of many components grouped into one container to simplify handling. The container is responsible for providing the methods that can be used to modify the display to the user. It does so using methods provided by each of the objects it contains. It groups the methods provided by its contents so that related events are always handled in the same manner, even when they are called by different controls.

The main screen will be more than a simple display window. The user must be able to move through the slides in the display. It also would be nice to provide controls on the display for moving through the pictures. These controls would function similar to VCR controls, enabling the user to move forward and backward through the slides.

Note
Screen appearance is an important part of any commercial application. Customers will decide to purchase a product on the basis of the way they react to its appearance. They will spend a great deal of time interacting with your application; it should be a pleasant experience.

In considering screen layout for an application, you also need to consider fonts, icons, and text size. Some applications require a more modern font; others may require a larger or smaller text size. Java allows you to pick a particular icon and assign it to each window, so your application can be iconified to a graphic that is familiar to your users. The icon is set using the `setIconImage()` in the `Frame` class.

In creating the structure of the program, I made some decisions that reflect an idea of how the screen will be laid out. The program will have one area for display and another for controls. It will include a menu. The display area will be divided into two sections, one for text and the other for graphics. This is not all the information you would need to determine a screen layout, but it is a good starting point.

### Design for the Main Window

The main window provides a frame for the application. Other objects in the display appear in the main window. In general, an application's main window will set its colors, fonts, layout, and other display aspects. It then adds the objects it is responsible for displaying, such as an event handler and the `main()` method used to start the application.

In the `SlideShow` application, two display aspects must be set: The background color will be defined to be light gray, and the layout will be set to a border layout.

Three objects should display in the main window: the menu bar that will display across the top of the frame, the display panel that consists of graphics and text objects, and a set of controls used to direct the slide shows.

### Design for the Menu Bar

The menu bar is a separate object that is attached to the frame for the application. If there are multiple frames in an application, each one should have its own menu bar; but if the main window can control events in the other windows, those windows don't need a menu bar. If there are multiple menu bars, you must decide which features to include on each one. In the `SlideShow` application there is only one main window, and it will have a menu bar. The Help windows will not be given a menu bar.

Note
Adding a menu bar to an application is not a trivial task. There are decisions about what to include on the menu bar, how to group choices on menus, when to make certain menu items visible, and how to connect each menu to the various activities it invokes.

In most applications you want all the activities of the application to be available on the menu because users will look at the menu when it is not obvious how to perform a certain activity on the screen. Your menu also must include an option to exit the application. If you are providing help screens with your application, they should be available from the menu as well.

For the `SlideShow` application, all the actions available on the control panel are duplicated on the menu. In addition, the menu will provide the capability to load a new show. Two check boxes will be added to the menu to enable the user to turn off the video or the text display. The menu also will allow the user to display help, display an About box, or exit the application.

After selecting the activities to include in the menu, you need to organize these options into groups on the menu. The first item on most application menus is the File menu, which includes options that involve loading and saving files. Generally, options to print a file, control the printer, close a particular window, and exit the application are also located here.

For the `SlideShow` application, the File menu will have two items: Load, which provides the option to load a new show; and Exit, which allows the user to exit the program.

The Help menu is usually the last item on the application menu. Items found here commonly involve providing assistance to the person using the application. This help may come in many different forms. The Help menu will provide one item for each type of help available.

The `SlideShow` application will provide a simple screen to describe the use of each of the controls. It will also have an About box that displays copyright, version, and authoring information. Each of these screens is accessible from the Help menu.

The remaining functions on the `SlideShow` menu bar will be grouped into the Display menu, which provides the items to move through the show and to turn off parts of the display.

The menu bar for the `SlideShow` application is summarized in Table 18.1.

Table 18.1. Menu bar features of the `SlideShow` application.

Category | Item | Description
File | Load | Loads slides into the application
| Exit | Exits `SlideShow`
Display | Forward | Moves forward to the next slide
| Back | Moves backward to the previous slide
| Beginning | Moves to the first slide in the show
| End | Moves to the last slide in the show
| No Text | When checked, the text is hidden
| No Slides | When checked, the pictures are hidden
Help | Help Topics | Provides a description of the controls
| About | Provides authoring information

For some applications, menu items may be pertinent at some times but irrelevant at others. It makes sense to make these items invisible when they are not available. In Java, menu items can be made invisible only by removing them from the menu. However, it is perfectly legal to change the items on a menu at runtime.

Tip
There are times when it might make sense to dim certain menu items, such as those that are available under certain circumstances but are not currently available. This feature is not used in this application. The most common example of this technique is the Cut, Copy, and Paste commands on an Edit menu. The Java method to dim a menu item is `disable()`. These menu items can be made available again using the `enable()` method.

For the `SlideShow` application, there is no need to make any of the items invisible. However, the check boxes will be checked only if a particular option has been selected by the user.

### Design for the `SlidePanel` Object

You need to define a new class, `SlidePanel`, to provide the display object. The new class is an extension of the `Panel` class and will contain two new classes: `SlideCanvas,` which will control the display of slides, and `SlideText,` which will control the display of the text.

Note
`SlideCanvas` and `SlideText` are the real performers of the application. These classes provide the features that are available to other objects in the application.

The `SlidePanel` class must include methods to provide the following functions:

- Advance to the next slide
- Revert to the previous slide
- Go to the first slide
- Go to the last slide
- Disable the display of slides
- Enable the display of slides
- Disable the display of text
- Enable the display of text
- Load a new show

The `SlidePanel` methods encapsulate the calls to the methods provided by the objects contained in the panel and are used by both the menu and the controls. `SlidePanel` is also responsible for confirming that the text being displayed corresponds to the slide being shown.

### Design for the `SlideCanvas` Object

The `SlideCanvas` class will contain an array of images to display. This class is responsible for reading the `.gif` files that contain the images and for building the array, as well as for displaying the picture to the user and providing methods to control that display. It maintains the total number of slides stored in the array, the current slide, and a flag to indicate whether slides are currently being displayed to the user.

### Design for the `SlideText` Object

The `SlideText` class is quite similar to the `SlideCanvas` class. The difference is that `SlideText` contains text strings rather than pictures. The text strings are read from `.txt` files containing descriptions of the slides in the `SlideCanvas` object.

The `SlideText` class will have the same list of internal reference variables and must provide methods similar to those provided by `SlideCanvas`. Instead of methods to enable and disable the display of slides, `SlideText` will provide methods to enable and disable the display of text.

### Design for the Controls

Most applications will have some type of graphical controls on the screen in addition to a menu. Selecting appropriate controls and determining their layout are important design considerations. Controls can be grouped and included as a toolbar or a palette. An application may have large buttons for a user to indicate they are done with a certain task, or it may have a picture with different areas taking a user to different tasks. The application may provide scroll boxes, drop-down list boxes, or radio buttons. Java provides mechanisms for supplying many types of controls.

You can create controls as instances of existing objects in the `java.awt` package, or by extending and combining those objects to provide custom controls. Controls are separate objects that can be grouped together on an application. They are usually separated from the display area of the application, but they do not have to be. Each control or group of controls should have an event handler so that it can react appropriately when the user selects the control.

The controls for the `SlideShow` application will be constructed as a `Panel` object containing instances of the `Button` class. The controls will provide buttons to enable the user to move forward or backward through the show and to move to the first or last slide.

### Design for the Dialog Boxes

Three dialog boxes will be provided in the `SlideShow` application. The first will appear off the Load item on the File menu and will enable the user to select a filename to load. The other two dialog boxes will appear off the Help menu.

Create the Load dialog box using the existing `FileDialog` class. The `FileDialog` class is an example of a utility, a class that is useful across many applications. To be useful, a utility must be self-contained and easy to understand. The Java Developer's Kit provides several good utilities, and other resources exist for gathering more Java utilities, such as the official Java reference resource at Gamelan. Utilities that are developed for one application can be easily transferred to another.

The other two dialog boxes will be created as extensions to the `Panel` class. The title of each dialog box and its contents will be coded into the extension. To make the window easy to close, the extensions will provide an OK button that closes the window.

### File I/O

One of the biggest differences between developing applets and developing applications is the availability of local files for reading and writing. Chapter 17 presents a brief example of writing to a file. This section relates some additional details on reading from files and accessing them on the local disk.

The `SlideShow` application reads several different files. It initially reads a file to determine which slides are part of the show, and then reads the files containing those slides. Finally, it reads the text files containing a description or comment about each picture.

In the first file access, the application will read the names of the files without the extension so that the same filenames can be used for both slides and comments. The slides are stored in `.gif` files and the comments in `.txt` files.

Although there are several types of streams that can be used to read a file, the easiest method of performing file I/O is with a `RandomFileAccess` object. This object encapsulates many of the file-access mechanisms, reducing the complexity of the code used to read the file.

The `RandomFileAccess` methods may encounter errors when reading or writing a file such as missing files, corrupt files, files that are read-only, and similar problems related to file storage and access. Although the class may be able to handle some of these problems, many of them must be reported back to the user. Therefore, the methods in this class may throw an `IOException` error.

Note
The `Exception` objects are a graceful way of handling error conditions. Any code that calls a method capable of throwing an exception must either catch the exception or throw back the exception to its caller. It is possible for a single method to throw multiple exceptions. (See Chapter 8, "Tying It All Together: Threads, Exceptions, and More," for a discussion of throwing and catching exceptions.)

If the method elects to catch the exception, it must provide code to do so. The code to catch exceptions uses the following syntax, with the method or methods being called within the braces after the keyword `try`:

> `try {...} catch (ExceptionType exceptionname) {...}`

The exception handling is placed in the braces following the keyword `catch`. The `Exception` object that is caught is assigned a name so that it can be referenced. The way the exception is handled depends on the problem and the context in which it occurred.

Some exceptions can be ignored. In this case, the space between the braces is left blank. Other exceptions can be displayed with or without an error message to the user. Some can be displayed in their own pop-up window. Others can be written to a log file. Some may even cause the program to shut down. In the `SlideShow` application, file I/O exceptions result in an error message being displayed on the standard output-that is, the window where the application was started, not the window where the application is running.

### Relationships Among Objects

After you have decided on the major pieces of your application, the relationships among them must be established. Some pieces may not have any interaction with other pieces. Other pieces will affect the display of the screen they appear on, while still others will affect the display of multiple screens. The menu must interact with many of the objects in the application.

For the application being created, the dialog boxes will be displayed via the menu. The menu will also be used to load a new show into the main window. The controls that have been defined must call methods in the display panel to change the display on the screen. The functions available on the controls should be duplicated on the menu; therefore, these methods also must be available to the menu.

The relationships among objects and the users of the program indicate the events that must be handled by the objects. The actions that occur on the menu must be handled in the event handler of the `SlideShow` class. The actions that occur in dialog boxes are handled by the event handler for the dialog box. The controls have an event handler to respond to user actions in the controls.

Peter's Principle
In the real world, designing an application is hampered by the changing nature of the user's needs. The design process will start in one direction, only to have new needs or new constraints appear. The flexibility of Java helps to ease this problem; however, skilled project management is still important to successfully bring applications to completion.

## Implementing a Real-World Application

In the implementation of the application, you will create the classes that were designed in the previous section as well as instances of these and other classes as needed to perform the tasks required for the application. Seven new classes must be defined to create the `SlideShow` application.

### Building the Main Window

The first class to define is an extension of the `Frame` class named `SlideShow`. The main window is built in this class, as is the `main()` method used to start the application. After declaring the new class, two key containers are defined to create instances of the `MenuBar` and `SlidePanel` objects. These declarations appear as follows:

> `public class SlideShow extends Frame {
> protected MenuBar mbar; // Menu for the slideshow
> protected SlidePanel displayPanel; // Panel to display the show`

To help you visualize these objects as they are discussed, Figure 18.1 shows the main window for the application.

Figure 18.1 : The main window of the SlideShow application.

#### The `SlideShow()` Method

Following a top-down methodology, you should construct the high-level objects before the low-level objects. For this reason, you now need to define the layout and style of the application and instantiate the key objects used to build the window. This is handled in a method called `SlideShow()`, which is shown in Listing 18.1.

The `SlideShow()` method builds the main window in a few easy steps. It calls a method used to build the menu and then sets the menu bar on the frame. Afterward, it sets the color of the background and defines the layout style for the display panel and controls. Its final step is to create new instances of the display panel and the controls and add them to the frame. The display panel is instantiated and added to the center of the frame using a single line of code. Likewise, the controls are instantiated and added to the South portion of the frame using a single line of code.

> Listing 18.1. The `SlideShow()` method.

> `public SlideShow(String args) {
> InitializeMenu();
> setMenuBar(mbar);
> setBackground(Color.lightGray);
> setLayout(new BorderLayout());
> add("Center",displayPanel = new SlidePanel(args));
> add("South",new ShowControls(displayPanel));
> }`

#### Creating the Menu Bar

The `SlideShow` class is also used to build the menu bar, which is an instance of the class `MenuBar` from the `java.awt` package. Compared with all the thought that goes into setting up a menu, the code to create it is short. For clarity, the code is placed in its own method called `InitializeMenu`. This method, shown in Listing 18.2, is called by the `SlideShow()` method.

To ensure that the menu bar is easy to use, menu items are logically grouped into menu categories. The `SlideShow` application's menu bar has three menu categories: File, Display, and Help, which are defined using the `Menu` class. Items on the menus are defined as `MenuItem` or `CheckBoxMenuItem` objects from the same package.

Just as you group menus into categories, you should also logically group menu items. If a particular menu can be grouped into subcategories, you can use the `addSeparator()` method to add a graphical rule to the menu to visually separate the categories of menu items.

After you define all the menu items for a particular menu, you need to add the menu to the menu bar using the `add()` method.

> Listing 18.2. The `InitializeMenu()` method.

> `// Creates the menu and attaches it to the MenuBar
> private void InitializeMenu()
> {
> mbar = new MenuBar();
> Menu m = new Menu("File");
> m.add(new MenuItem("Load..."));
> m.addSeparator();
> m.add(new MenuItem("Exit"));
> mbar.add(m);
> m = new Menu("Display");
> m.add(new MenuItem("Forward"));
> m.add(new MenuItem("Back"));
> m.add(new MenuItem("Beginning"));
> m.add(new MenuItem("End"));
> m.addSeparator();
> m.add(new CheckboxMenuItem("No Text"));
> m.add(new CheckboxMenuItem("No Slides"));
> mbar.add(m);
> m = new Menu("Help");
> m.add(new MenuItem("Help Topics"));
> m.addSeparator();
> m.add(new MenuItem("About SlideShow"));
> mbar.add(m);
> }`

Figure 18.2 shows the Display menu in the `SlideShow` application. The menu contains each of the menu items listed in the code with a separator between the menu subcategories.

Figure 18.2 : Using the menu.

#### Handling Events

The event handler of the `SlideShow` class is used to respond to the menu events in this application. The code for the event handler is shown in Listing 18.3. Notice that the item name is used to determine the user's selection. Therefore, the item names in the event handler must exactly match the item names listed on the menu.

The event handler is responsible for displaying the three dialog boxes created in the previous section. In each case, it creates the dialog box and assigns a name to the instance. It then uses the name to display the dialog box. When the Load dialog box closes, it passes the name of the file to the display panel so the appropriate file is loaded.

For events in the Display menu, the event handler calls the appropriate method on the display panel. When the user selects Exit or destroys the window, the event handler causes the application to exit.

> Listing 18.3. The event handler for `SlideShow`.

> `// Event handler responds to events in the window and
> // events on the menu
> public boolean handleEvent(Event evt) {
> if (evt.id == Event.WINDOW_DESTROY &&
> evt.target instanceof SlideShow)
> {
> System.exit(0);
> return true;
> } else if(evt.target instanceof CheckboxMenuItem) {
> if (evt.arg.equals("No Text")) {
> if (((CheckboxMenuItem) evt.target).getState() == true)
> displayPanel.NoText();
> else
> displayPanel.ShowText();
> return true;
> } else if (evt.arg.equals("No Slides")) {
> if (((CheckboxMenuItem) evt.target).getState() == true)
> displayPanel.NoSlides();
> else
> displayPanel.ShowSlides();
> return true;
> }
> } else if(evt.target instanceof MenuItem) {
> if (evt.arg.equals("Load...")) {
> String FileName;
> FileDialog fd =
> new FileDialog((Frame) this,
> "Get New Slide Show",
> FileDialog.LOAD);
> fd.show();
> FileName = fd. getDirectory() + fd.getFile();
> displayPanel.LoadShow(FileName);
> return true;
> } else if (evt.arg.equals("Forward")) {
> displayPanel.ShowNextSlide();
> return true;
> } else if (evt.arg.equals("Back")) {
> displayPanel.ShowPrevSlide();
> return true;
> } else if (evt.arg.equals("Beginning")) {
> displayPanel.ShowFirstSlide();
> return true;
> } else if (evt.arg.equals("End")) {
> displayPanel.ShowLastSlide();
> return true;
> } else if (evt.arg.equals("Exit")) {
> System.exit(0);
> return true;
> } else if (evt.arg.equals("About SlideShow")) {
> AboutBox ab = new AboutBox(this);
> ab.show();
> return true;
> } else if (evt.arg.equals("Help Topics")) {
> HelpBox ab = new HelpBox(this);
> ab.show();
> return true;
> }
> }
> return super.handleEvent(evt); // Let parent handle event
> }`

#### Starting the Application

The final method defined in the `SlideShow` class is the `main()` method. In any application, `main()` is the first method called when the application starts. Listing 18.4 shows this method.

The `SlideShow` application's `main()` method expects a filename to be passed as an argument from the command line. If this does not happen, the application prints a usage message and exits the application. If a filename is passed as an argument, the `main()` method does the following:

- Creates a new instance of the `SlideShow` object
- Sets a title on the main frame
- Resizes the application's frame to the current window size
- Shows the objects built when the `SlideShow()` method was invoked

Resizing your application's main frame to the current window size is a key design concept. In this way, you ensure that the main frame always fits in the user's screen.

> Listing 18.4. The `main()` method.

> `// main method used to start application
> public static void main(String args[]){
> // Verify that there is a filename to attempt to load show
> if (args.length <= 0) {
> System.out.println("Usage: java SlideShow filename.");
> System.exit(0);
> }
> // Create instance of this object
> SlideShow ss = new SlideShow(args[0]);
> ss.setTitle("Slide Show"); // Set the title of the frame
> ss.pack(); // Pack components
> //resize frame to current window size
> Dimension d;
> d = Toolkit.getDefaultToolkit().getScreenSize();
> ss.resize(d.width, d.height);
> ss.show(); // Display the frame
> }
> }`

### Adding the `SlidePanel` Class

The `SlidePanel` class added in the `SlideShow()` method is implemented next. This class defines the main viewing area for the application. The viewing area is divided into two parts: the picture and the text. This parallels the two objects that are placed in the `SlidePanel` class.

The two parts must change in coordination with one another. Therefore, these objects are protected in `SlidePanel`, and all events that modify the contents of these objects must occur through `SlidePanel`. This becomes important when you look at the code for the controls. The declaration and constructor for `SlidePanel` appear in Listing 18.5.

> Listing 18.5. The `SlidePanel` constructor.

> `/**
> * SlidePanel class holds objects participating in the slideshow
> * Objects are arrays displaying one at a time to the user
> */
> class SlidePanel extends Panel {
> protected SlideCanvas displayCanvas; // Canvas to display .gifs
> protected SlideText displayText; // Text area to display text
> // Constructor adds objects to the panel
> // Gives each object the filename to get load its array from
> public SlidePanel(String ShowName) {
> super();
> setLayout(new BorderLayout());
> add("Center",displayCanvas = new SlideCanvas(ShowName));
> add("South",displayText = new SlideText(ShowName));
> }`

All the features that act on the display in the main viewing area must use methods defined in the object providing the main display. For custom controls, the name of the object providing this display is passed to each control. For menu options, the main event handler is used to activate the cor-rect method.

In the `SlidePanel` object, you define methods for each of the functions listed in the design. The body of these methods consists of calling similar methods for each of the two objects on the display. (See Listing 18.6.) These methods will be implemented when you define the `SlideCanvas` and `SlideText` objects.

> Listing 18.6. Methods for the `SlidePanel()` class.

> `public void ShowNextSlide() {
> displayCanvas.ShowNextSlide();
> displayText.ShowNextText();
> }
> public void ShowPrevSlide() {
> displayCanvas.ShowPrevSlide();
> displayText.ShowPrevText();
> }
> public void ShowFirstSlide() {
> displayCanvas.ShowFirstSlide();
> displayText.ShowFirstText();
> }
> public void ShowLastSlide() {
> displayCanvas.ShowLastSlide();
> displayText.ShowLastText();
> }
> public void NoSlides(){
> displayCanvas.NoSlides();
> }
> public void ShowSlides(){
> displayCanvas.ShowSlides();
> }
> public void NoText(){
> displayText.NoText();
> }
> public void ShowText(){
> displayText.ShowText();
> }
> public void LoadShow(String ShowName) {
> displayCanvas.LoadShow(ShowName);
> displayText.LoadShow(ShowName);
> }`

### Adding the `SlideCanvas` Object

Create the `SlideCanvas` class used to display images first. The information contained in this object is held in variables that are implemented as protected. The complete declaration appears as

> `/**
> * SlideCanvas is an extension of Canvas
> * It provides a means to display slides to the user
> */
> class SlideCanvas extends Canvas {
> protected Image im[] = new Image[20];//Array of Images to display
> protected int NumSlides; // Number of images in the array
> protected int CurrentSlide; // Number of image currently displayed
> protected boolean showslide; // False to turn off display`

The constructor for this class takes one parameter: the name of the file containing the list of images the show will display. The constructor for the class is just three lines: the first calls the constructor for the `Canvas` class; the second calls the method (described in the "File I/O" section in this chapter) to load the array from the given filename; and the final line sets the `showslide` variable to `true`, indicating that slides are shown, not hidden, by default. The code for the constructor is

> `public SlideCanvas(String ShowName) {
> super();
> LoadShow(ShowName); // Load internal array
> showslide = true; // Enable the display of slides
> }`

The class draws the image on the screen by overriding the `paint()` method. The new method will draw a blank rectangle if the display is currently disabled. Otherwise, it will determine the current size of the display and draw an appropriately sized image:

> `public void paint(Graphics g) {
> Rectangle r = bounds();
> if (showslide)
> g.drawImage(im[CurrentSlide],50,50,
> r.width-100,r.height-100,this);
> else {
> g.setColor(Color.lightGray);
> g.fillRect(0,0,r.width,r.height);
> }
> }`

The access methods needed for these variables are defined in the "Designing a Real-World Application" section in this chapter. These methods ensure that an instance of the class is repainted any time the current slide is altered. Again, you can see the advantages of protected variables. If the variable containing the current slide number could be accessed directly, there would be no guarantee that the slide would be repainted when the current slide is altered.

The first access methods are those that enable the user to move through the slide show. The methods that move forward or backward one slide must check for the array bounds. If the method encounters an array boundary, it simply remains on the same slide. The methods operate by setting a new current slide and then calling `repaint()` to display the slide, as in the following code fragment:

> `public void ShowNextSlide() {
> if (CurrentSlide < (NumSlides - 1)) {
> CurrentSlide = CurrentSlide + 1;
> repaint();
> }
> }
> public void ShowPrevSlide() {
> if (CurrentSlide > 0) {
> CurrentSlide = CurrentSlide - 1;
> repaint();
> }
> }
> public void ShowFirstSlide() {
> CurrentSlide = 0;
> repaint();
> }
> public void ShowLastSlide() {
> CurrentSlide = NumSlides - 1;
> repaint();
> }`

To enable and disable the display of slides, access methods must be provided for the boolean variable `showslide`. These methods will change the value of the variable and then force a repaint of the screen so that the new value becomes effective immediately:

> `public void NoSlides(){
> showslide = false;
> repaint();
> }
> public void ShowSlides(){
> showslide = true;
> repaint();
> }`

The last method to be defined for `SlideCanvas` is the one that loads the array. This code must open the file specified by the user, read each line from the file, store the line in the array, close the file, and handle any exceptions. These functions are shown in the following code:

> `public void LoadShow(String LoadFile) {
> RandomAccessFile ListFile;
> String[] imgFile = new String[20]; // name of image to display
> int i; // Loop counter
> // Create an array of images and load the images
> i=0;
> try {
> // Open the file
> ListFile = new RandomAccessFile(LoadFile,"r");
> // Read until the end of the file is reached
> while (ListFile.getFilePointer() != ListFile.length() ) {
> // Store each line from the file in an array element
> imgFile[i] = ListFile.readLine() + ".gif";
> i++;
> }
> //Close the file
> ListFile.close();
> // Trap any errors which occur while reading the file
> } catch (java.io.IOException e) {
> System.out.println("Could not read from file.");
> System.out.println(e);
> }`

`RandomAccessFile` is a class that implements two different interfaces, `DataOutput` and `DataInput`. Therefore, objects that are instances of this class can be used for both reading and writing. The `SlideShow` application currently does not need to write to a file. However, writing to a file in an application works in a manner analogous to reading.

This type of file access will handle reading from and writing to text files. Something different is needed to read an image file. In applets, the `getImage()` method is used to get an image from a file or a URL. This method cannot be used in an application because it loads relative to the applet's URL. The application does not have a URL, so it needs another mechanism to load the image.

For applications, the image can be loaded using the `getImage()` method from a `Toolkit` object. To do this, the application first must get the current `Toolkit` object and then get the image. The `getImage()` method in the `Toolkit` object encapsulates all the details of reading the file and storing the image. The code to load the images for the slide show is

> `NumSlides = i;
> for (i=0; i<NumSlides;i++) {
> im[i] = getToolkit().getImage(imgFile[i]);
> }
> CurrentSlide = 0;
> }
> }`

### Adding the `SlideText` Object

The `SlideText` class is similar to the `SlideCanvas` class except that it contains an array of text strings. The modified declaration appears as

> `/**
> * SlideText is an extension of TextArea
> * It provides a means to display text descriptions to the user
> */
> class SlideText extends TextArea {
> protected String str[] = new String[20];//Array of Strings to display
> protected int NumTexts; // Number of strings in the array
> protected int CurrentText; // Number of strings currently displayed
> protected boolean showtext; // True if text is not being displayed`

The constructor for the `SlideText` class is just a little longer than the constructor for the `SlideCanvas` class. In addition to the tasks performed in the constructor for `SlideCanvas`, `SlideText` must set its `Editable` attribute to `false` to prevent viewers from modifying the slide descriptions:

> `public SlideText(String ShowName) {
> super();
> LoadShow(ShowName); // Load internal array
> setEditable(false); // Prevent editing of text
> showtext = true; // Enable the display of text
> }`

There is no `paint()` method for text classes. The normal `setText()` method takes a string as a parameter and sets the text of the object to that string. To prevent another object from accidentally setting the display text, you override this method and call a new implementation of `setText()` that does not require a parameter, as in the following code fragment:

> `// Override normal setText so text can not be reset accidentally
> public void setText(String str){
> setText();
> }`

The new implementation of `setText()` will set the text based on the current text element in the array. Therefore, you do not need a parameter. If text is not being displayed, set the text to an empty string, which must be done using the version of `setText()` in the superclass because `setText(String)` was overridden for this class. The new implementation of `setText` is

> `public void setText(){
> if (showtext)
> super.setText(str[CurrentText]);
> else
> super.setText("");
> }`

The `SlideText` class is responsible for providing the same access methods as the `SlideCanvas` class. These methods are similar to those implemented for `SlideCanvas`. Note that the array boundaries must be checked in these methods as well:

> `public void ShowNextText() {
> if (CurrentText < (NumTexts - 1)) {
> CurrentText = CurrentText + 1;
> setText();
> }
> }
> public void ShowPrevText() {
> if (CurrentText > 0) {
> CurrentText = CurrentText - 1;
> setText();
> }
> }
> public void ShowFirstText() {
> CurrentText = 0;
> setText();
> }
> public void ShowLastText() {
> CurrentText = NumTexts - 1;
> setText();
> }`

Hiding and displaying text is done by providing accessor methods for the boolean variable. Instead of forcing a repaint of the screen to cause the new value to become effective, these methods call `setText()` directly:

> `public void NoText(){
> showtext = false;
> setText();
> }
> public void ShowText(){
> showtext = true;
> setText();
> }`

The `load` method follows the same algorithm as that for `SlideCanvas`; however, a new method is implemented to provide for reading an entire file into an element in the array of text strings. This method, called `getText`, will make use of the `RandomAccessFile` class in a manner similar to how filenames are read. However, instead of reading a line looking for a null terminator, this method will read the entire file into a string. The new method appears as

> `// Read text for an item from a file
> protected String getText(String LoadFile){
> RandomAccessFile ListFile;
> byte b[] = new byte[1024];
> int numbytes;
> try {
> ListFile = new RandomAccessFile(LoadFile,"r");
> numbytes = (int)ListFile.length();
> ListFile.read(b,0,numbytes);
> ListFile.close();
> } catch (java.io.IOException e) {
> System.out.println("Could not read from file.");
> System.out.println(e);
> }
> return (new String(b,0));
> }
> }`

Using this method, the `load` method for the `SlideText` class can be implemented as follows:

> `// Load the text array based on filename in the LoadFile
> public void LoadShow(String LoadFile) {
> RandomAccessFile ListFile;
> String[] strFile = new String[20]; // name of image to display
> int i; // Loop counter
> // Create an array of strings and load the strings
> i=0;
> try {
> ListFile = new RandomAccessFile(LoadFile,"r");
> while (ListFile.getFilePointer() != ListFile.length() ) {
> strFile[i] = ListFile.readLine() + ".txt";
> i++;
> }
> ListFile.close();
> } catch (java.io.IOException e) {
> System.out.println("Could not read from file.");
> System.out.println(e);
> }
> NumTexts = i;
> for (i=0; i<NumTexts;i++) {
> str[i] = getText(strFile[i]);
> }
> CurrentText = 0;
> }`

### Adding the Controls

Now that you can display images and text, you can turn your attention to creating the controls to navigate through the show. The controls are created using four buttons. These buttons are then grouped into a single object that is an extension of the `Panel` class.

The controls must reference a particular `SlidePanel` where they will cause slides to change. Therefore, the constructor for the controls takes an instance of `SlidePanel` as a parameter. This value is stored as an internal variable and is used by the event handler for this class. The declaration and constructor for the controls appear as

> `/**
> * Control bar for moving through a slide show
> */
> class ShowControls extends Panel {
> static SlidePanel ss; // Panel controls are attached to
> // Constructor requires a SlidePanel to which the
> // controls are attached
> public ShowControls(SlidePanel theShow) {
> ss = theShow;
> setLayout(new FlowLayout(FlowLayout.CENTER));
> add(new Button("|<<"));
> add(new Button("<"));
> add(new Button(">"));
> add(new Button(">>|"));
> }`

When the user interacts with the controls, an event is triggered. The controls must react to this event and perform the desired operation. The `action()` method for the controls is triggered by the runtime environment when an action event, such as pressing a button, takes place on the control panel. This method determines whether a button was pressed by examining the event target. If the event target is not a button, it calls the action method for its superclass, which enables the runtime environment to react to other defined actions:

> `public boolean action(Event evt, Object arg) {
> if (evt.target instanceof Button) {
> handleButton((String)arg);
> return true;
> } else return super.action(evt,arg);
> }`

When the action method determines that a button is the target of the action, it calls the `handleButton` method. This method determines which button is pressed and calls an appropriate method in the `SlidePanel` that this object controls:

> `// Determine which button was pressed and act accordingly
> // Actions will refer to the Slide panel to which the
> // control bar is attached
> public void handleButton(String bname) {
> if (bname.equals(">")) {
> ss.ShowNextSlide();
> } else if (bname.equals("<")) {
> ss.ShowPrevSlide();
> } else if (bname.equals("|<<")) {
> ss.ShowFirstSlide();
> } else if (bname.equals(">>|")) {
> ss.ShowLastSlide();
> }
> }`

### Adding the Dialog Boxes

Dialog boxes in their general form are introduced in Chapter 17. This section shows you how to implement the three dialog boxes that appear in response to the Load, Help Topics, and About SlideShow menu items.

#### The File Dialog Box

The File dialog box is a specific kind of dialog box. Implemented in the `java.awt` package, these boxes enable the user to select a particular file located on his or her system. By default, the dialog box displays the listing of the directory where the application is launched. However, the directory the dialog box displays can be modified by the application.

The dialog box can be supplied with a default filename so that it will display only files that match that filename. If the filename contains wildcards, all files matching the expression are displayed. In this manner, the File dialog box can be used to display only files of a certain type.

The dialog box is implemented so that its appearance depends on the operating system on which the application is running. This means the user has the look and feel of a familiar platform, but the application has all the advantages of platform independence. Thankfully, the difference in appearance of the dialog box is transparent to the programmer.

The constructor for the File dialog box is passed three parameters: the current frame as the parent of the new window; a title for the dialog box, in this case Get New Slide Show; and an indicator that this is an Open dialog box, not a Save dialog box. For the `SlideShow` application, the call to the file dialog box is

> `new FileDialog((Frame) this,"Get New Slide Show",FileDialog.LOAD);`

The dialog box as it appears on a Windows system is shown in Figure 18.3.

Figure 18.3 : A file dialog box under Windows.

#### The `HelpBox` Class

The Help dialog box is designed as an extension to the `Panel` class and is constructed with a grid layout. Each of the help items is added as a label. The constructor for the dialog box takes care of resizing the box, but does not actually display it. The method that creates the dialog box will determine when to display it.

The OK button specified in the design is added at the bottom of the dialog box. The OK button is placed in its own panel so that it is displayed in a standard button shape instead of occupying the entire width of the grid item where it is displayed. Listing 18.7 shows the code for the `HelpBox` constructor.

> Listing 18.7. Creating the Help dialog box.

> `/**
> * Basic Help window to explain the slide controls
> */
> class HelpBox extends Dialog
> {
> public HelpBox(Frame parent)
> {
> super(parent, "Help Topics", true);
> setLayout(new GridLayout(6,1));
> add(new Label("The controls work as follows:",Label.LEFT));
> add(new Label(" |<< returns to the first slide",
> Label.LEFT));
> add(new Label(" < returns to the previous slide",
> Label.LEFT));
> add(new Label(" > advances to the next slide",
> Label.LEFT));
> add(new Label(" >>| advances to the last slide",
> Label.LEFT));
> Panel pp = new Panel();
> pp.add(new Button("OK"));
> add(pp);
> resize(250,300);
> }
> }`

Figure 18.4 shows the Help box for the `SlideShow` application.

Figure 18.4 : The Help box for SlideShow.

The dialog box must have an event handler to respond to user events in the dialog box. The user can click the OK button to close the dialog box or close the window where the dialog box is displayed. In either case, the application will dispose of the dialog box, indicating that it is done with the resource the object used. The event handler appears in Listing 18.8.

> Listing 18.8. The `HelpBox()` event handler.

> `// Event handler closes the window if the user
> // hits the OK button or the window close button
> public boolean handleEvent(Event evt) {
> if (evt.id == Event.WINDOW_DESTROY &&
> evt.target instanceof HelpBox) {
> dispose();
> return true;
> } else if("OK".equals(evt.arg)) {
> dispose();
> return true;
> }
> return false;
> }
> }`

#### The `AboutBox` Class

The About box is similar to the Help Topics dialog box. However, because it has different contents, it uses a different layout. At the center of the panel, a grid layout is used to display the authoring information. The OK button goes in its own panel in the South portion of the layout. The entire listing for the `AboutBox` class is shown in Listing 18.9.

> Listing 18.9. Creating the About dialog box.

> `/**
> * Creates an about box for the Slideshow
> */
> class AboutBox extends Dialog
> {
> public AboutBox(Frame parent)
> {
> super(parent, "About SlideShow", true);
> setLayout(new GridLayout(3,1));
> add(new Label("SlideShow",Label.CENTER));
> add(new Label("by Peter Norton and William Stanek",Label.CENTER));
> Panel pp = new Panel();
> pp.add(new Button("OK"));
> add("South",pp);
> resize(250,200);
> }
> // Event handler closes the window if the user
> // hits the OK button or the window close button
> public boolean handleEvent(Event evt) {
> if (evt.id == Event.WINDOW_DESTROY &&
> evt.target instanceof AboutBox) {
> dispose();
> return true;
> } else if("OK".equals(evt.arg)) {
> dispose();
> return true;
> }
> return false;
> }
> }`

Figure 18.5 shows the About box for the `SlideShow` application.

Figure 18.5 : The About box for SlideShow.

## The Complete Project

To test the application, you must be able to run the application correctly. The stand-alone application can be run from the command line using the command

> `java SlideShow filename.txt`

where `filename.txt` is the name of the file containing the list of slides to display. This file can be created using a standard text editor, provided that null characters are inserted between the filenames. The same type of text editor can be used to create the descriptions supplied with each slide.

For example, you could create a slide show file named `Hawaii.txt` containing a list of pictures from your vacation to Hawaii. The pictures are named

- `Mountain1.gif`
- `Mountain2.gif`
- `Beach1.gif`
- `Beach2.gif`
- `Luau1.gif`
- `Luau2.gif`

The file `Hawaii.txt` would appear as

> `Mountain1¤Mountain2¤Beach1¤Beach2¤Luau1¤Luau2`

where the symbol ¤ represents the null character. If you have difficulty including the null in a text editor, you can create a simple Java program to read filenames from the command line and insert them in a file. After each filename, append the string `\n` to get the null character. This allows you to use the simple `readline()` method in the program rather than adding code to parse the file.

Tip
The ASCII code for the null character is `010`. In Microsoft Word, you can generate the null character that Java expects as an end-of-line marker by holding the Alt key and typing `010`. Unfortunately, when Word saves a text file, it puts an extra carriage return at the end of the file. Although `SlideShow` will run, it will look for an extra file and generate an error. Chapter 19, "Application Upgrades," demonstrates how to create a long-term fix for this problem by building slide shows within the application.

To continue the Hawaiian vacation slide show, you need six text files with the names `Mountain1.txt`, `Mountain2.txt`, `Beach1.txt`, and so on. These files will explain more about each picture. For example, `Mountain1.txt` might read

> View looking south from Ka Ala on the leeward coast of Oahu. Taken at 3 p.m. after an enjoyable all-day hike.

Text files such as these help you to remember more about each picture. They can be particularly helpful if you are going to keep the pictures for any length of time.

The finished application is shown in Listing 18.10. This example has demonstrated the possibilities of Java applications. Now you should be able to put the techniques discussed in this chapter to use to build original Java programs.

After working through this example, try to modify the application to increase your experience with Java. For example, you could rewrite the `Aboutbox` class so that the constructor takes two arguments, the title and the author. The class would then know exactly how to display the information and could be reused in other applications.

You could use a similar technique to create standard Help boxes. The argument to the constructor could be a string or list of strings containing the information to be displayed in the help window. These types of utilities are in the process of being developed for Java.

> Listing 18.10. The complete `SlideShow` application.

> `import java.awt.*;
> import java.applet.*;
> import java.io.RandomAccessFile;
> /**
> * Creates Window with panel for the slideshow
> * plus a Menu and controls for the SlideShow
> */
> public class SlideShow extends Frame {
> protected MenuBar mbar; // Menu for the slideshow
> protected SlidePanel displayPanel; // Panel to display the show
> public SlideShow(String args) {
> setBackground(Color.lightGray);
> setLayout(new BorderLayout());
> add("Center",displayPanel = new SlidePanel(args));
> add("South",new ShowControls(displayPanel));
> InitializeMenu();
> setMenuBar(mbar);
> }
> // Creates the menu and attaches it to the MenuBar
> private void InitializeMenu()
> {
> mbar = new MenuBar();
> Menu m = new Menu("File");
> m.add(new MenuItem("Load..."));
> m.addSeparator();
> m.add(new MenuItem("Exit"));
> mbar.add(m);
> m = new Menu("Display");
> m.add(new MenuItem("Forward"));
> m.add(new MenuItem("Back"));
> m.add(new MenuItem("Beginning"));
> m.add(new MenuItem("End"));
> m.addSeparator();
> m.add(new CheckboxMenuItem("No Text"));
> m.add(new CheckboxMenuItem("No Slides"));
> mbar.add(m);
> m = new Menu("Help");
> m.add(new MenuItem("Help Topics"));
> m.addSeparator();
> m.add(new MenuItem("About SlideShow"));
> mbar.add(m);
> }
> // Event handler responds to events in the window and
> // events on the menu
> public boolean handleEvent(Event evt) {
> if (evt.id == Event.WINDOW_DESTROY &&
> evt.target instanceof SlideShow)
> {
> System.exit(0);
> return true;
> } else if(evt.target instanceof CheckboxMenuItem) {
> if (evt.arg.equals("No Text")) {
> if (((CheckboxMenuItem) evt.target).getState() == true)
> displayPanel.NoText();
> else
> displayPanel.ShowText();
> return true;
> } else if (evt.arg.equals("No Slides")) {
> if (((CheckboxMenuItem) evt.target).getState() == true)
> displayPanel.NoSlides();
> else
> displayPanel.ShowSlides();
> return true;
> }
> } else if(evt.target instanceof MenuItem) {
> if (evt.arg.equals("Load...")) {
> String FileName;
> FileDialog fd =
> new FileDialog((Frame) this,
> "Get New Slide Show",
> FileDialog.LOAD);
> fd.show();
> FileName = fd. getDirectory() + fd.getFile();
> displayPanel.LoadShow(FileName);
> return true;
> } else if (evt.arg.equals("Forward")) {
> displayPanel.ShowNextSlide();
> return true;
> } else if (evt.arg.equals("Back")) {
> displayPanel.ShowPrevSlide();
> return true;
> } else if (evt.arg.equals("Beginning")) {
> displayPanel.ShowFirstSlide();
> return true;
> } else if (evt.arg.equals("End")) {
> displayPanel.ShowLastSlide();
> return true;
> } else if (evt.arg.equals("Exit")) {
> System.exit(0);
> return true;
> } else if (evt.arg.equals("About SlideShow")) {
> AboutBox ab = new AboutBox(this);
> ab.show();
> return true;
> } else if (evt.arg.equals("Help Topics")) {
> HelpBox ab = new HelpBox(this);
> ab.show();
> return true;
> }
> }
> return super.handleEvent(evt); // Let parent handle event
> }
> // main method used to start application
> public static void main(String args[]){
> // Verify that there is a filename to attempt to load show
> if (args.length <= 0) {
> System.out.println("Usage: java SlideShow filename.");
> System.exit(0);
> }
> // Create instance of this object
> SlideShow ss = new SlideShow(args[0]);
> ss.setTitle("Slide Show"); // Set the title of the frame
> ss.pack(); // Pack components
> //resize frame to current window size
> Dimension d;
> d = Toolkit.getDefaultToolkit().getScreenSize();
> ss.resize(d.width, d.height);
> ss.show(); // Display the frame
> }
> }
> /**
> * SlidePanel class holds objects participating in the slideshow
> * Objects are arrays displaying one at a time to the user
> */
> class SlidePanel extends Panel {
> protected SlideCanvas displayCanvas; // Canvas to display .gifs
> protected SlideText displayText; // Text area to display text
> // Constructor adds objects to the panel
> // Gives each object the filename to get load its array from
> public SlidePanel(String ShowName) {
> super();
> setLayout(new BorderLayout());
> add("Center",displayCanvas = new SlideCanvas(ShowName));
> add("South",displayText = new SlideText(ShowName));
> }
> public void NoText(){
> displayText.NoText();
> }
> public void ShowText(){
> displayText.ShowText();
> }
> public void NoSlides(){
> displayCanvas.NoSlides();
> }
> public void ShowSlides(){
> displayCanvas.ShowSlides();
> }
> public void LoadShow(String ShowName) {
> displayCanvas.LoadShow(ShowName);
> displayText.LoadShow(ShowName);
> }
> public void ShowNextSlide() {
> displayCanvas.ShowNextSlide();
> displayText.ShowNextText();
> }
> public void ShowPrevSlide() {
> displayCanvas.ShowPrevSlide();
> displayText.ShowPrevText();
> }
> public void ShowFirstSlide() {
> displayCanvas.ShowFirstSlide();
> displayText.ShowFirstText();
> }
> public void ShowLastSlide() {
> displayCanvas.ShowLastSlide();
> displayText.ShowLastText();
> }
> }
> /**
> * SlideCanvas is an extension of Canvas
> * It provides a means to display slides to the user
> */
> class SlideCanvas extends Canvas {
> protected Image im[] = new Image[20]; // Array of Images to display
> protected int NumSlides; // Number of images in the array
> protected int CurrentSlide; // Number of image currently displayed
> protected boolean showslide; // False to turn off display
> public SlideCanvas(String ShowName) {
> super();
> LoadShow(ShowName);
> showslide = true;
> }
> public void NoSlides(){
> showslide = false;
> repaint();
> }
> public void ShowSlides(){
> showslide = true;
> repaint();
> }
> public void paint(Graphics g) {
> Rectangle r = bounds();
> if (showslide)
> g.drawImage(im[CurrentSlide],50,50,
> r.width-100,r.height-100,this);
> else {
> g.setColor(Color.lightGray);
> g.fillRect(0,0,r.width,r.height);
> }
> }
> public void ShowNextSlide() {
> if (CurrentSlide < (NumSlides - 1)) {
> CurrentSlide = CurrentSlide + 1;
> repaint();
> }
> }
> public void ShowPrevSlide() {
> if (CurrentSlide > 0) {
> CurrentSlide = CurrentSlide - 1;
> repaint();
> }
> }
> public void ShowFirstSlide() {
> CurrentSlide = 0;
> repaint();
> }
> public void ShowLastSlide() {
> CurrentSlide = NumSlides - 1;
> repaint();
> }
> public void LoadShow(String LoadFile) {
> RandomAccessFile ListFile;
> // name of image to display
> String[] imgFile = new String[20];
> int i; // Loop counter
> // Create an array of images and load the images
> i=0;
> try {
> ListFile = new RandomAccessFile(LoadFile,"r");
> while (ListFile.getFilePointer() != ListFile.length() ) {
> imgFile[i] = ListFile.readLine() + ".gif";
> i++;
> }
> ListFile.close();
> } catch (java.io.IOException e) {
> System.out.println("Could not read from file.");
> System.out.println(e);
> }
> NumSlides = i;
> for (i=0; i<NumSlides;i++) {
> im[i] = getToolkit().getImage(imgFile[i]);
> }
> CurrentSlide = 0;
> }
> }
> /**
> * SlideText is an extension of TextArea
> * It provides a means to display text descriptions to the user
> */
> class SlideText extends TextArea {
> protected String str[] = new String[20];//Array of Strings to display
> protected int NumTexts; // Number of strings in the array
> protected int CurrentText; // Number of string currently displayed
> protected boolean showtext; // True if text is not being displayed
> public SlideText(String ShowName) {
> super();
> LoadShow(ShowName);
> setEditable(false);
> showtext = true;
> }
> public void NoText(){
> showtext = false;
> setText();
> }
> public void ShowText(){
> showtext = true;
> setText();
> }
> // Override normal setText so text can not be reset accidentally
> public void setText(String str){
> setText();
> }
> public void setText(){
> if (showtext)
> super.setText(str[CurrentText]);
> else
> super.setText("");
> }
> public void ShowNextText() {
> if (CurrentText < (NumTexts - 1)) {
> CurrentText = CurrentText + 1;
> setText();
> }
> }
> public void ShowPrevText() {
> if (CurrentText > 0) {
> CurrentText = CurrentText - 1;
> setText();
> }
> }
> public void ShowFirstText() {
> CurrentText = 0;
> setText();
> }
> public void ShowLastText() {
> CurrentText = NumTexts - 1;
> setText();
> }
> // Load the text array based on filename in the LoadFile
> public void LoadShow(String LoadFile) {
> RandomAccessFile ListFile;
> String[] strFile = new String[20]; // name of image to display
> int i; // Loop counter
> // Create an array of strings and load the strings
> i=0;
> try {
> ListFile = new RandomAccessFile(LoadFile,"r");
> while (ListFile.getFilePointer() != ListFile.length() ) {
> strFile[i] = ListFile.readLine() + ".txt";
> i++;
> }
> ListFile.close();
> } catch (java.io.IOException e) {
> System.out.println("Could not read from file.");
> System.out.println(e);
> }
> NumTexts = i;
> for (i=0; i<NumTexts;i++) {
> str[i] = getText(strFile[i]);
> }
> CurrentText = 0;
> }
> // Read text for an item from a file
> protected String getText(String LoadFile){
> RandomAccessFile ListFile;
> byte b[] = new byte[1024];
> int numbytes;
> try {
> ListFile = new RandomAccessFile(LoadFile,"r");
> numbytes = (int)ListFile.length();
> ListFile.read(b,0,numbytes);
> ListFile.close();
> } catch (java.io.IOException e) {
> System.out.println("Could not read from file.");
> System.out.println(e);
> }
> return (new String(b,0));
> }
> }
> /**
> * Control bar for moving through a slide show
> */
> class ShowControls extends Panel {
> static SlidePanel ss; // Panel controls are attached to
> // Constructor requires a SlidePanel to which the
> // controls are attached
> public ShowControls(SlidePanel theShow) {
> ss = theShow;
> setLayout(new FlowLayout(FlowLayout.CENTER));
> add(new Button("|<<"));
> add(new Button("<"));
> add(new Button(">"));
> add(new Button(">>|"));
> }
> // Determine which button was pressed and act accordingly
> // Actions will refer to the Slide panel to which the
> // control bar is attached
> public void handleButton(String bname) {
> if (bname.equals(">")) {
> ss.ShowNextSlide();
> } else if (bname.equals("<")) {
> ss.ShowPrevSlide();
> } else if (bname.equals("|<<")) {
> ss.ShowFirstSlide();
> } else if (bname.equals(">>|")) {
> ss.ShowLastSlide();
> }
> }
> public boolean action(Event evt, Object arg) {
> if (evt.target instanceof Button) {
> handleButton((String)arg);
> return true;
> } else return super.action(evt,arg);
> }
> }
> /**
> * Creates an about box for the Slideshow
> */
> class AboutBox extends Dialog
> {
> public AboutBox(Frame parent)
> {
> super(parent, "About SlideShow", true);
> setLayout(new GridLayout(3,1));
> add(new Label("SlideShow",Label.CENTER));
> add(new Label("by Peter Norton and William Stanek",Label.CENTER));
> Panel pp = new Panel();
> pp.add(new Button("OK"));
> add("South",pp);
> resize(250,200);
> }
> // Event handler closes the window if the user
> // hits the OK button or the window close button
> public boolean handleEvent(Event evt) {
> if (evt.id == Event.WINDOW_DESTROY &&
> evt.target instanceof AboutBox) {
> dispose();
> return true;
> } else if("OK".equals(evt.arg)) {
> dispose();
> return true;
> }
> return false;
> }
> }
> /**
> * Basic Help window to explain the slide controls
> */
> class HelpBox extends Dialog
> {
> public HelpBox(Frame parent)
> {
> super(parent, "Help Topics", true);
> setLayout(new GridLayout(6,1));
> add(new Label("The controls work as follows:",Label.LEFT));
> add(new Label(" |<< returns to the first slide",
> Label.LEFT));
> add(new Label(" < returns to the previous slide",
> Label.LEFT));
> add(new Label(" > advances to the next slide",
> Label.LEFT));
> add(new Label(" >>| advances to the last slide",
> Label.LEFT));
> Panel pp = new Panel();
> pp.add(new Button("OK"));
> add(pp);
> resize(250,300);
> }
> // Event handler closes the window if the user
> // hits the OK button or the window close button
> public boolean handleEvent(Event evt) {
> if (evt.id == Event.WINDOW_DESTROY &&
> evt.target instanceof HelpBox) {
> dispose();
> return true;
> } else if("OK".equals(evt.arg)) {
> dispose();
> return true;
> }
> return false;
> }
> }`

## Testing and Debugging

Although you did not develop a test plan for the simple application created in Chapter 17, you should do so for this more complex application. The test plan is written using the components stated in the design. The overall question is, "Does the application perform as expected?"

The following questions are related to the main frame of the application:

- Does the frame containing the application work as expected?
- Does the application start as expected?
- Does the application start and display a slide with text?
- Does the application close when the user presses the Close button on the frame?
- Does the application resize when the user presses the resize buttons on the frame?

Next there are some basic questions about the appearance of the application:

- Does each slide appear?
- Does the text for each slide appear?
- Are the controls visible?
- Is the menu present?

The following questions relate to the menu. Although some menu items are similar, it is important to test each one individually. The purpose of testing is to verify how the application will appear to the user. Therefore, be sure to verify each of the following items:

- Does the Exit option on the menu shut down the application?
- Does the Load option on the menu work?
- Does the File dialog box open?
- When a show is selected in the File dialog box, is it displayed to the user?
- If the user cancels in the File dialog box, does the same slide show remain?
- Does the About box appear when the About menu item is selected?
- Does the Help box appear when the Help Topics menu item is selected?
- Does the Forward menu item move to the next slide in the show?
- Does the Backward menu item move to the previous item in the show?
- Does the Beginning menu item move to the first slide in the show?
- Does the End menu item move to the last slide in the show?
- Does the No Text menu cause the text to disappear when it is selected?
- Is the No Text menu item checked after it has been selected?
- Does selecting the No Text menu item a second time cause the text to reappear?
- After the No Text menu item is selected a second time, is the checkmark removed from the menu item?
- Does the No Slides menu cause the slide to disappear when it is selected?
- Is the No Slides menu item checked after it has been selected?
- Does selecting the No Slides menu item a second time cause the slide to reappear?
- After the No Slides menu item is selected a second time, is the checkmark removed from the menu item?

In addition to testing that the menu displays the Help and About windows, there are a few specific questions pertaining to the windows themselves:

- Is all the text visible when the Help window is displayed?
- Does the Help window close when the user presses the OK button?
- Does the Help window close when the user presses the Close button on its frame?
- Is all the text visible when the About window is displayed?
- Does the About window close when the user presses the OK button?
- Does the About window close when the user presses the Close button on its frame?

Specific tests are also needed for the controls. This may seem redundant because you have tested the methods during the menu test; however, it verifies that each control is connected to the correct method and is using the method correctly. Here are some of the tests you would perform for the `SlideShow` application:

- Does the control marked >>| move to the last slide in the show?
- Does the control marked |<< move to the first slide in the show?
- Does the control marked > move forward one slide?
- Does the control marked < move backward one slide?

This completes the test plan. There are tests for each piece of functionality provided by the application. There are certainly more questions that could be asked about the functioning of this application, but these tests are sufficient to verify the decisions made in the application design and to alert programmers to any unexpected occurrences.

## Summary

This chapter demonstrates how to develop a complex, useful application. It pulls together concepts that are introduced in preceding chapters and applies them to the development of the application. The chapter covers several techniques for developing larger applications. The ideas presented here will assist you as you develop your own Java applications.

At this point, you should have an understanding of the Java language that will enable you to follow the discussions of advanced applications in Part VII. You also should fully understand the application presented in this chapter so that you can follow the discussion in Chapter 19.