MPAD: A new design and development methodology for multi-panel applets

Find out how to use this generic, flexible design for deploying robust, multi-screen Java applets over the Internet, intranets, and extranets

Java can be used to develop applets, standalone applications (GUI and console), and packages (library of reusable classes). Unlike applications, however, applets are typically confined to Web browsers and therefore are somewhat limited in their user interface design. To get around this limitation, I will provide you with a generic, flexible and well-thought-out design for Java applets, giving you a head start into deploying robust, multi-screen applets over the Internet, intranets, and extranets.

An applet primer

Generally speaking, applets are embedded in HTML pages using the <APPLET> tag. When a user requests an HTML page, the browser parses the HTML text and upon detecting the <APPLET> tag, requests that the Web server send the class file pointed to by the CODE attribute; any other class files referenced by the initial class file also are downloaded as needed. Once the required class files download successfully, the browser runs the applet within the HTML page, using the WIDTH and HEIGHT specified in the <APPLET> tag as the applet's display area.

Interface obstacles

The standard applet user interface works fine for mini applets that can function within one given applet screen. However, this one-screen-per-HTML-page method does not scale well for organizations that need to deliver robust programs to their target audience over the Internet, intranet, or extranets.

There are some alternatives to this standard interface. You can launch windows in their own frames, which provides a way for applets to contain more than one window at one time. Another alternative is to use dialog boxes for additional screens. Although these alternatives do provide solutions to the standard interface, many users find them annoying. I continually hear gripes about Web sites that clutter desktops with additional browser windows.

So, what do you do if your applet requires multiple screens, but having separate windows is not a viable option? The answer: Use a design that works in the confinement of a single HTML page, but allows multiple screens in a single applet embedded in that HTML page.

Desperately seeking solutions: the Multi-Panel approach

The Multi-Panel Applet Design (MPAD), which allows multiple panels, or screens, to be incorporated into a single applet, is perfect for applets but can just as easily be applied to standalone GUI applications. MPAD is not a new Java API or technology; rather, it is a design that provides some significant benefits:

  • Developers can create individual panels independently and integrate them into the applet at a later point
  • Individual panels can be efficiently unit-tested by their developers
  • Data can be exchanged between panels in an easy, extensible, and extremely flexible fashion
  • The applet's functionality can be enhanced using JavaScript

MPAD uses a Panel Manager to control individual panels. Each panel consists of GUI controls/widgets and performs a specific task. For example, a login panel might contain TextField objects to obtain an ID and password from a user and perform login authentication for a given system. The panels are chained together in a sequence, with the last panel in sequence visible in the applet's display area. This mechanism is similar to a stack where you can "push" (and "pop") objects onto the stack, but can only "peek" at the object on top of the stack. Note:Although MPAD allows you to see only one screen at a time, you can easily overcome this limitation by extending the design.

Although the Panel Manager itself is the main applet class, it works behind the scenes to display individual panels, which are the visible components in this design. What makes MPAD extremely open and flexible is that the Panel Manager has no knowledge of these panels at startup because their names are not hard-coded in the Panel Manager code; rather, they are provided to the Panel Manager at run time.

MPAD design specs: An overview

Each panel in the Multi-Panel Applet Design has a one-to-one relationship with a Java class file. In other words, the Java source code for each panel is in its own Java source file. The Panel Manager uses the class name to create an instance of the panel and display it. The initial panel's class name is extracted from the applet's parameters, and all subsequent panel class names are provided to the Panel Manager via events from the individual panels. Therefore, the only hard-coding required is in the individual panels, which is the class name of the next panel to be displayed. For example, a login panel would contain the name of the panel that should display following a successful login.

Now that you have a basic understanding of the design, let's take a closer look at the individual pieces. But before we begin, you may wish to browse through the live demo of the applet below so the remainder of the article will be easier to follow (a similar demo also is available at the end of the article). The demo contains three panels: a Login panel, a Record List panel, and an Add New Record panel. On the Login panel, enter any user ID and click on the Login button. On the Record List panel, click on any of the image buttons (except the last two) to go to the Add New Record panel. On the Add New Record panel, click on OK to add a record, or Cancel to abort.

Note: If you are using Netscape Navigator via a proxy server, you might encounter problems running the demo. If this is the case, download the archive file found in the Resources section of this article and view the demo locally.

You need a Java-enabled browser to view this applet.

A closer look at the Panel

Manager

Note: Because most browsers do not yet support JDK 1.1, I have decided to present the MPAD design using the JDK 1.0.2 event model. However, the downloadable archive file found in the Resources section of this article provides source code using both the 1.0.2 and 1.1 versions of the event model.

As I mentioned earlier, the Panel Manager doesn't have any hard-coded values, which results in completely generic source code. The Panel Manager performs the following functions, which are illustrated in the figure Interaction between the Panel Manager and individual panels:

  • Builds a java.util.Properties object from a configuration file (we'll discuss this object's significance later in the article).
  • Instantiates the first class and displays it. This step includes the following tasks:

    • Obtaining the first class's name from the applet parameters (discussed later in this article)
    • Creating an instance of the panel class using java.lang.Class
    • Displaying the panel using java.awt.CardLayout
    • Adding the panel to an internal list (java.util.Vector) of panel references
  • Responds to the following events, sent by the panel classes:
    • ADD, which creates and displays a new panel. When this event is received, all the steps described for the first class are executed, except the class name is extracted from the java.awt.Event object instead of an applet parameter
    • REMOVE, which removes the specified panel from the display area and also from the internal list of panel object references
Panel Manager
Interaction between the Panel Manager and individual panels

Listing 1 provides the complete source code for the Panel Manager. As you peruse the code, you'll notice a few peculiar things that require a bit of explanation.

The first unusual thing you'll encounter is the following snippet, which builds a java.util.Properties object:

properties=new Properties(); InputStream is = (new URL(getCodeBase(), "JPanels.cfg")).openStream(); properties.load(is); is.close();

properties.put("Applet", this); properties.put("NotificationComponent", this);

This is how the applet gets its parameters, not via the typical java.applet.Applet.getParameter() method. In addition, this is how data between panels is exchanged. We'll discuss this style of parameter passing and its benefits later in the article.

The next peculiar thing is that the handleEvent method only handles two events -- one to ADD a new panel and the other to REMOVE an existing panel. If necessary, you can easily extend MPAD by adding new event types (REFRESH, SHOW_PANEL, for example).

public boolean handleEvent(Event evt)
{  
    switch(evt.id)
    {
        case ADD:
             panelAdd(evt.arg);
   .
   .
        case REMOVE:
             panelRemove(evt.arg);

Another stumbling block is the panelAdd() method. For starters, notice how a new instance of a panel class is created with the java.lang.Class object. The instance is cast to JPanel, a class that all panel classes must extend in order for this design to work. We'll discuss JPanel later on.

Class  c = Class.forName((String)arg);
jp = (JPanel)c.newInstance();

Next, notice some of the initial steps that occur when a new panel is created, such as passing the global Properties object to the new panel so it has access to the applet's parameters. Also, notice the calls to the init(), start(), and stop() methods; these methods are defined in the JPanel class but can be overridden by the panel subclasses to perform such tasks as setting the user interface and allocating/deallocating objects. This style of using special methods simulates how applets work.

jp.setProperties(properties);

jp.init(); jp.start(); . . ((JPanel)vPanels.lastElement()).stop();

Another unusual portion of code is shown next. This snippet adds the new panel reference to the internal java.util.Vector and to the global Properties object, adds the panel to CardLayout layout manager, and shows the new panel.

vPanels.addElement(jp); add(jp.getClass().getName(), (Component)jp); jCardLayout.last(this);

this.properties.put(jp.getClass().getName(), jp);

Finally, the panelRemove() method performs the tasks in the reverse order of the panelAdd(), which we just discussed.

Now that we have those explanations out of the way, click here to see the complete Panel Manager source code.

Developing individual panels

Developing individual panels is very similar to developing individual applets -- with one main difference: The panels must extend the

JPanel

class (see Listings 1 and 2) instead of extending the

java.applet.Applet

class. The figure

JPanel* class hierarchy

provides a graphical view of the class hierarchy.

JPanel Class Hierarchy
JPanel* class hierarchy

Similar to applets, the panels can override special methods, such as init(), start(), stop(), and destroy(), for performing initialization and termination type functions. For example, the init() method is a good place to create new GUI objects and place them on the screen. The benefits of simulating applets are that the learning curve for developing panels is minimal for developers who understand applets; and the panels can easily be converted to individual applets if required.

Listing 1: JPanel.java

public class JPanel extends Panel { protected Component notifyComponent=null; protected Applet applet=null; protected Properties properties=null;

public void init() {} public void start() {} public void stop() {} public void destroy() {}

public void setProperties(Properties p) { properties = p; if (properties != null) { applet = (Applet) properties.get("Applet"); notifyComponent = (Component)properties.get("NotificationComponent"); } } }

Listing 2: JPanelRecordList.java (sample panel)

public class JPanelRecordList extends JPanel { . . public void init() { . . bpButtons.add(gib.build("images/1.gif")); bpButtons.add(gib.build("images/2.gif")); taAcctInfo = new TextArea(5, 40); . . gbl.setConstraints(taAcctInfo, gbc); add(taAcctInfo); }

public void start() { lStatusBar.setText(""); }

public boolean action(Event evt, Object arg) { if (evt.target instanceof ImageButton) { if (evt.target == ibExit) return notifyComponent.postEvent(new Event(this, JPanelManager.REMOVE, this)); else if (evt.target == ibHelp) { try { applet.getAppletContext().showDocument(new URL(applet.getCodeBase(), "help/RecordList.html"), "helpWin"); } catch (Exception e) { e.printStackTrace(); } } else { lStatusBar.setText("Please wait..."); return notifyComponent.postEvent(new Event(this, JPanelManager.ADD, "JPanelCreateRecord")); }

return true; }

return false; } . .

Integrating panels

Integrating panels requires interaction between the panels and the Panel Manager. As I mentioned earlier, the first class name is obtained from an applet parameter, and the panel class is subsequently created and displayed. From then on, new panels are created by existing panels sending an event to the Panel Manager, as shown here:

return notifyComponent.postEvent(new Event(this, JPanelManager.ADD, "JPanelRecordList"));

To remove a panel, the panel in question must ask the Panel Manager to remove it from the sequence of panels by sending an event like this:

return notifyComponent.postEvent(new Event(this, JPanelManager.REMOVE, this));

The variable notifyComponent points to the Panel Manager object. The variable is loaded into the global Properties object by the Panel Manager during startup and is then set locally by JPanel each time the Panel Manager creates a new panel.

1 2 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more