6.170 Laboratory in Software Engineering
Spring 2000
Problem Set 5b: PathFinder Applet
Due: March 16, 2000
Handout 13


Guidelines

To do this assignment as efficiently as possible, and to derive the most benefit, we recommend that you: To hand your solution in, follow the standard instructions, which state in part:
Each assignment should be handed in as hardcopy to your TA or to the course secretary (NE43-529) by 4:30 PM on its due date. It is usually most convenient to give the assignment to your TA at the end of class on that day. Additionally, the source and compiled code for each problem set should be put online so your TA can test your program.
See the general information sheet (handout 1) for more details.
The directory for online submission of this problem set is ~/6.170/ps5b.

Purpose

In this part of problem set 5 you will build a graphical interface to the PathFinder program that you wrote in part a. The document that you hand in will encompass both parts a and b.

Background

Your graphical interface to the PathFinder will use heavily JFC-Swing API. There are a number of Swing tutorials online, which can be found at http://developer.java.sun.com/developer/onlineTraining. You might want to take a look at the "Swing Tutorial" or "Fundamentals of JFC/Swing", Part I and II.

The basic elements that you will use in this problem are part of the java.awt and javax.swing packages (you will primarily use javax.swing, which is based on java.awt, but provides more functionality and flexibility). Note that many Swing component classes are prefixed with a letter "J" (such as JApplet) to distinguish them from the old version of the Java GUI package, java.awt. In general, the Swing "J" classes are derived from the corresponding AWT classes, and are more powerful than their AWT superclasses.

In this problem set you will be asked to write an applet. Most applets are quite simple. To make writing applets easier, the Java library provides a very powerful abstraction called JApplet, contained in the javax.swing.JApplet class. The JApplet class provides all of the functionality necessary for building applets of your own.

Because the JApplet class is so powerful, custom applets can provide only the code they need. The following code segments completely describes a working applet that prints the message "Hello" in its window.

You will notice that there is no code for creating or displaying windows. All of this is managed by the JApplet class. The only functionality this code provides is that specifically needed for this applet, i.e. displaying its greeting message. Though the code for this applet is very simple, this applet doesn't do that much either. We will see below that we can add buttons, and other user interface elements to the applet's window to provide greater functionality.

1. Components and Interface Elements

To create more interesting applets than the example above, we must add some elements to the interface for interacting with the user. Java provides a number of different interface elements for us to use. Before we take a look at them, it is necessary for us to understand a little of the structure of Java's component hierarchy.

1.1 Component Hierarchy

A Component is an object having a graphical representation that can be displayed on the screen and that the user can interact with. The Component hierarchy includes a number of interface elements. In particular, there is a Container class that holds other Components. You should use the Swing version of the Component class - JComponent, which extends the Container class (see figure below for the general relationship between different groups of classes). JComponent has a number of subclasses, which you will use in this problem set. They include, but not limited to, an AbstractButton class that provides button controls that can be clicked on to tell the program to perform some action (this class is abstract, thus you will probably want to use JButton, which is derived from the AbstractButton); a JLabel class that provides a textual label next to other components to inform the user of their function; and a JTextComponent class that allows text to be entered. JTextComponents can be used both for input and for output and come in single line versions (JTextField) and multiple versions (JTextArea). For more information on these and other components, see the description of the javax.swing package at http://www.javasoft.com/products/jdk/1.2/docs/api/index.html.

A user interface is always made up of a number of interface elements that are laid out within a container. The layout is performed by the container itself. JWindow and JApplet are both containers. A container can hold other components, and therefore, can hold other containers. For more complex layouts it may be necessary to nest containers. You can create JPanels to hold your interface elements and then arrange the JPanels within your JApplet. Containers can be nested to any level.

The figure below illustrates the basic structure of the Component hierarchy. In reality, JComponent has a lot more subclasses than the ones illustrated here, and you are not limited to the number and type of components discussed in this problem set. For a complete description of the Swing component hierarchy, see Part I of the Short Course in Swing.

Component
|
Container
|
JComponent
|

| | | | |
JTextComponent JList JLabel AbstractButton JScrollPane
| |


    | |        | |   
JTextArea JTextField JButton JMenuItem


1.2 Component Layout

The organization of interface elements within a container is controlled by a set of helper classes called Layout Managers. Java provides a number of different layout managers that provide various forms of automatic organization of the interface elements within them. The most popular layout managers are BorderLayout, GridLayout, and BoxLayout but you may also find GridBagLayout, FlowLayout, or CardLayout useful. Each container comes with a default layout manager. You can change the default manager by calling the setLayout method. For example, a call to:

sets the current layout manager for the container MyContainer to a new BorderLayout. Once the layout manager has been set, components can be added to the container with the add command. There are several forms of the add command, but the following two are the most useful:

The first adds the component c to MyContainer. The second adds a component along with a constraint. The constraint is used by some layout managers, such as BorderLayout, to determine where to place the component. Because many of the layout managers have rather simplistic formatting algorithms, you will frequently have to take advantage of container nesting to get a complex arrangement of interface elements. Remember that a Container is itself a subclass of Component. Therefore, a whole container with its associated elements can be moved around just like any other Component. The only exceptions to this rule are JFrame and JApplet classes. Although these classes are derived from the Container class, you can't add components directly to them. In order to place components inside an applet, you need to get a content pane that is managed by the JApplet object (a content pane is a container, which represents an area of an applet). Here is a sample code that will add a label and a button to an applet that has a border layout:



1.3 Useful Components

You will find the following components useful for this assignment:

JTextArea (http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/JTextArea.html) is used to input or output text information. Useful methods are setEditable to control whether the text is editable, setText and append which allow you to change the text displayed in the JTextArea, and getText which returns the text in the component.

JTextField (http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/JTextField.html) is a single line version of JTextArea with similar methods.

JButton (http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/JButton.html) is used for implementing buttons. Useful methods are setEnabled for specifying whether the button is usable, and setActionCommand and addActionListener for event handling.

JList (http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/JList.html) is used if you need to choose from a list of pre-defined items. Methods of interest are add to add items to the list, setSelectedValue to initially select an item, and getSelectedValue to find the currently selected item.

JLabel (http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/JLabel.html) is used if you need simple labels. Useful methods are setAlignmentX and setAlignmentY that control the alignment of the label.

JScrollPane (http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/JScrollPane.html) is used if you want automatic handling of horizontal and vertical scrolling of content (you might want to do this for JTextArea and JList). When you want an object to be scrolled, you add it to the JScrollPane in the following manner:


2. Events

In Java, interactions with the user, such as clicking on a JButton or typing in a JTextArea, are communicated to a program through events. An event is simply an object that contains information about the event and its source, and it is passed to a set of classes called event handlers. The call to the event handler is actually performed by the Java runtime environment automatically; however, a program is responsible for telling the runtime system which handlers to call. Because there are many things that can happen in a program, there are many different classes of events. There are two major categories of events in Java: low-level events (e.g., MouseEvents and WindowEvents) and semantic events (e.g., ActionEvents and AdjustmentEvents). In this problem set, you will deal mostly with ActionEvents (but you might want to consider other events as well to add more functionality to your applet). ActionEvents represent the actions that happen in a program. In particular, when a button is clicked, that button passes an ActionEvent object to the appropriate handler. ActionEvents have a number of methods, but usually, only the getActionCommand and getSource methods are of any interest. getActionCommand method returns the name of the action. For JButtons, this is simply the name of the JButton. getSource method returns the object on which the event initially occurred.

In order for the runtime system to correctly tell a program that an event has occurred, it is necessary for that program to register its event handlers. There are separate event handler methods for each type of event. For ActionEvents, the handlers are defined by a special interface class called ActionListener.

The ActionListener class has a single method, actionPerformed. The object that implements this method is said to be a handler object. If that object is registered as a handler for a component, the above method will be called by the runtime system when action events are generated by that component. Handler objects must be registered separately for each component, but many components can share the same handler object by passing the same object during registration. Registration of handler objects is performed through one of the handler registration methods. For more information on different kinds of events and listener interfaces, see Part II of the Short Course in Swing.

Typically a component will only have handler registration methods for the events it generates. For the case of ActionEvents, the registration method is called addActionListener. The handler object passed to this method is any object that implements the ActionListener interface. Typically you will design a small class in conjunction with your Applet that will implement a Listener interface for every type of action. Then a single instance of this helper class can be passed to the handler registration methods (such as addActionListener) for each component that appears in the Applet.

In the following code sample, a simple applet is defined that contains two buttons: }


In this code, a handler object is defined for ActionEvents and is registered as the handler for the JButtons. Note that the handler object handles the event directly based on which button is pressed.

If you consult the samples on the web or in books, you will see other styles for achieving the goals outlined here. For instance, on occasion the applet class itself is also the handler and extends the Listener interface. In addition, sometimes the handler object is implemented with an outer class, in which case a pointer to the applet has to be passed to the listener object. For more information on the alternative approaches of handling events in Swing, see examples in Part II of the Short Course in Swing.

3. File Access and URL Class

Because of the distributed nature of applets when used on the World Wide Web, applets can be somewhat dangerous. An applet that is loaded off the web represents code written by someone else that is running on your machine. If that code were harmful it could cause damage to your system before you were aware that it was running. To protect web users from this hazard, Java applets cannot perform some operations that Java applications can. Loading files or otherwise accessing the disk is one such operation. Therefore, when you design an applet you must have another way to access file data that your applet will need. A common way of providing this access is through the "java.net.URL" class. This class is a very powerful class that provides functionality for downloading files and other resources directly from a web server across the network.

Because you will need to load a database for your database engine to perform queries on, it will be necessary for you to read a file from a URL object. Typically this is done using the following two lines of code:

The first line opens a web connection for the file and the second line connects a stream to that connection for reading the file. Once the BufferedReader is obtained it can be used in just the same way that you would use a BufferedReader obtained from a FileReader. There is one catch to all of this. An applet can only request files from the server from which the applet was retrieved. Fortunately, this restriction is relaxed when you run the applet in appletviewer. However, keep this in mind if you use Netscape or Internet Explorer to test your applet.

If you want to serve your own test files from your Athena locker while working on your problem set, you should place your test files in a directory with the correct permissions. Files accessible through web.mit.edu can be placed anywhere in your locker but the directory must provide read permissions to the system group system:anyuser, meaning that it is world-readable. You can make a directory world-readable with the following command: where <dirpath> is the path to the directory whose permissions you wish to change. Be careful about which directories you give system:anyuser read access to, as the whole world will be able to read these files through the web.

4. Viewing applets

To display an applet, you need an HTML file that references it. The applet tag is used for this purpose, as in the following HTML fragment: For this problem set, you should create a "PathFinder.html" file for your applet. You should use "appletviewer" to view your applet:

Assignment

Create an applet that displays an interface that allows the user to query a database. The interface should provide some field(s) for setting up the database file. Once the database is loaded, additional input devices should support querying the database and displaying the results. The user must be allowed to load another database at any time. In the Appendix we provided you with a sample of what your interface might look like, but you don't have to follow the same format.

Your interface should contain features such as disabling the "run query" function (e.g., graying out the button or whatever controls that function with the "setEnabled" method) and displaying some sort of message prompting the user to enter a database filename when no database is loaded, and displaying some kind of "please wait..." message indicating that the program is busy while loading large databases.

You should not modify any files in your ~/6.170/ps5a/  directory after you have turned in part a. You should copy your entire ps5a directory to a ps5b directory for use with part b (you can do so with the command "cp -R ~/6.170/ps5a ~/6.170/ps5b"  ).   We should be able to run your applet from your ~/6.170/ps5b   directory with the command:

Extensions

If you wish you can provide a program that does more than what is discussed above. However, before doing this, you should be certain that your program handles all the required commands and formats. Also you should discuss proposed extensions with your TA before doing them.

Extensions might involve allowing editing of the database file or, for the truly ambitious, graphically displaying the database and highlighting the resulting routes.

What to turn in

As mentioned above, we should be able to view your applet using appletviewer. In addition, you must turn in documentation covering both parts a and b of problem set 5. Your applet and this document are due on March 16. On this date you must deliver hardcopies of both your documentation and your executable code (for both parts a and b; for part b only include new and modified code) as an appendix to your document to your TA or to the course secretary by 4:30PM. Remember to indicate the name of your TA on the first page. Your document should follow all of the guidelines explained in Handout 12. Be sure that your documentation contains the following: Be clear in your discussions when you are talking about part a and when you are talking about part b.

Be concise -- do not confuse length with content! Good luck!

Appendix

Click here to look at the sample of the applet interface.