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.
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." |
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.
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.
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:
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
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. |
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.
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.
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));
}
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.
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
}
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:
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
}
}
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);
}
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;
}
}
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;
}
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();
}
}
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 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 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 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.
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
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;
}
}
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:
Next there are some basic questions about the appearance of the application:
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:
In addition to testing that the menu displays the Help and About windows, there are a few specific questions pertaining to the windows themselves:
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:
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.
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.