When I saw my first applet back in July 1995, I thought, "Cool! A tiny, self-contained window running a program written in a real language!" A few weeks later, I was whining about how applets were confined to a single window.
Java can do anything, but it's good to let your Web browser take care of the display of text and images. Thus, you want most of your page to be created with HTML, and only those bits that need Java to be written in Java. But these Java-powered bits might be anywhere on your page. And since an applet only gets a single window, this means you have to use multiple applets.
Putting Java in different places on a page can sometimes be the right thing, purely from a design standpoint. We might want to have a site directory at the top and another window at the bottom showing some of the same information. Or we might have a Java-powered ticker that shows status information such as "loading..." when our main Java navigation window is loading a new page into a frame.
Of course, you could always have your applet pop up a bunch of frames, and that's done quite often. But we're talking here about having multiple windows embedded in the browser window itself.
Using multiple applets will certainly work, but it's a pain in the neck, because we'd like to think of our program as a single program with multiple windows, just like we do with normal GUI-based programming. If special measures are not taken, using multiple applets can cause duplication of code and increased loading time. These are not good things.
Applets that reside on a page can access each other, and this can help you share code and data between applets. However, Java already has a nice method of sharing code and data between bits of code (we call them function calls and variables) and talking between applets makes everything that much less convenient. And inconvenience is a force against doing The Right Thing(tm).
So the bad news is, an applet only gets one window. The good news is, there's a trick you can employ to make it seem like you have as many as you want. This trick is really just an abstraction layer, and it's called an Applet Terminal.
Try It OutJust to whet your appetite, I invite you to take a look at applet terminals in action here .
What you're looking at on this page is a single applet that is drawing into multiple windows. This applet lives in the upper-left-hand window. In truth, there are really four applets, but all of the logic for drawing the lines and the text is in a single program. This is what we want.
How to Use ItBefore we get into the details of how this trick works, let's see how a programmer (such as yourself) might use it.
Let's pretend, for a moment, that we're writing a Java application instead of an applet. In this situation, it's easy to create windows and put stuff in them. We do something like this:
Frame frame = new Frame();
TextField tf = new TextField( "hi there" ):
frame.setLayout( new BorderLayout() );
frame.add( "center", tf );
frame.resize( 300, 50 );
This code fragment creates a window with a text field in it; the text field says "hi there". We can create as many of these as we want; we can create windows containing any components we might want to throw into them.
When using applet terminals, you do something very similar:
Panel otherWindow = AppletTerminal.getPanel( "other" );
TextField tf = new TextField( "hi there" ):
otherWindow.setLayout( new BorderLayout() );
otherWindow.add( "center", tf );
Instead of creating a frame and putting things in it, we get ourselves a panel and put things in it.
Definition: an applet terminal is a panel that comes from another applet. In creating our Web page, we have our main applet (that contains all the code and data, and does everything), and we have one or more other applets that exist only to have things displayed in them. The AppletTerminal class manages these special applets and allows our main program to use them for display.
To make the above example work, we have to have two applets in our page our main program and AppletTerminal:
<applet code="AppletTerminal.class" width=200 height=200>
<param name="terminalname" value="other">
Note that it's pretty easy to set up an applet terminal window in your Web page you only have to specify the Java class ('AppletTerminal.class'), the size (200 by 200), and, finally, the name of the window ("other"). The name allows your main program to find the window after all, you might have 10 different applet terminal windows, and you want to be able to draw the right thing in the right window.
To actually put stuff in an applet terminal window, you ask for it by name:
Panel otherWindow = AppletTerminal.getPanel( "other" );
This returns a Panel object into which you can place components, just as you would with a regular panel or frame.
Once you have grabbed panels and put stuff in them, you've got yourself a multi-windowed applet!
How It WorksWhen the AppletTerminal class is asked for a panel, it is given a terminal name. AppletTerminal then scans the applets on the page, looking for one with that name. It only checks applets that are AppletTerminals, because that's all we care about and also because only AppletTerminals know what their terminal names are. Other applets don't have terminal names.
If it finds an AppletTerminal with the given name, it gets the panel from that AppletTerminal and returns it to the caller, who can then put stuff in it.
is a static method, meaning that it's not tied to any particular instance of AppletTerminal. This is easier for the user of this class, because you don't have to hunt down the correct instance of AppletTerminal. You just ask the class for a panel.
itself needs an instance of AppletTerminal to be able to look for other applets. This is because one calls
to look through the set of applets living on a page. This is a tolerable requirement; after all, if we didn't have any AppletTerminals on the page, the whole thing would be moot.
Every time an AppletTerminal is created by the browser (responding to the <applet> tags in our page), the AppletTerminal constructor stores a reference to that AppletTerminal in a static variable, so that
can use it to find other terminals. Of course, we only need the first instance, but it's not a problem if each successive AppletTerminal overwrites the last reference with a new reference to itself. As long as there is a reference to some active terminal, we're all set.
Check out the source for detailed comments.
What We've Really Done (philosophical rambling alert!)If you like this Applet Terminal idea, you probably like it because it seems to provide a way to get direct access to a remote applet window from your main applet and is almost the same as when you create multiple windows in a Java application.
But we really haven't done anything new here. After all, Java applets already have a basic method for inter-applet interactions: you can call
, and you've got references to all the other applets right there.
All we've done is create an abstraction layer over this mechanism. And the abstraction layer doesn't do much, aside from allowing us to find particular terminals by name. In fact, in a sense, this abstraction layer gives us less than we would have if we used
, because instead of getting Applet objects, we get mere Panel objects, which keeps us from accessing any of the special features that applets have.
Why, then, is this good? Because it's conceptually simpler. If you were having your main applet talk to other applets, you might be tempted to call their methods and recognize the particular applet subclass (TetrisApplet, NavigationApplet, etc.) that they instantiate, as well as call their specialized methods. Then what you have is a multi-applet program-aggregate, which can be a difficult way to structure a complex program.
Instead, we've created terminals. We call them this because they are rather like the dumb terminals we used to use, back in the day, to access the featureless box we called a mainframe. Putting as little complexity as possible in the terminal means that writing software is easier; we have a single program that does input and output from several different places, rather than having several programs doing different things that have to be coordinated.
In short, less is more (which is true in programming, if not in architecture).
This is an important concept, because, for many applications, dumb terminals are The Right Thing(tm). The paradigm of the World Wide Web, in particular, is a huge example of this in action. The new world of the Web is rather like the old world of the mainframe, except that the terminal is a better terminal.
But the dumb terminal idea isn't right for all things. Many systems started off with elegant dumb-terminal designs (e.g., the Web, the multiplayer first-person action game Quake), but the complexity of the application required that more sophistication be put into the client. When this happens, it complicates the elegant design. Sometimes this works out okay (e.g., Quake) and sometimes it starts getting out of hand (e.g., the Web). In the case of the Web, we now have huge browser-monstrosities that are buggy, inconsistent, and hard to port.
Despite these dangers, it's a good idea at least to seriously consider the dumb-terminal approach, because if it does turn out to be right for your application, it can greatly simplify things.
Further ConsiderationsThere are a few things that could be done to make this system better.
Right now, the number of terminals, and their names, are hard-coded you create tags for a certain set of terminals, and then your main applet draws into them. For some applications, it might make sense to have a system where your main program can first check and see what terminals are on the page (and where they are) and then use them appropriately. This would require a way to get, e.g., an Enumeration of the terminals on a page, which the main program could then browse through.
If you did this, then you'd be able to use the same main program on different pages, each of which had a different set of terminals with different sizes. The main program would have logic to figure out what terminals are available, and what should be displayed in each one.
We haven't put any checks in to make sure that two different applets don't ask for the same terminal (or that one applet doesn't try to put two completely different sets of things in the same terminal). Under the current system, when this happens, the things put in last would most likely replace the things that were put in first, with no warnings of any kind. A more robust system would watch for this.
ConclusionWe've created an elegant abstraction layer called AppletTerminal that allows us to draw to several different locations in a single browser window. This can help us avoid code and data redundancy when creating Web pages that we want to enhance with judiciously-placed bits of Java.
About the Author
Greg Travis is a freelance programmer living in New York City. His interest in computers can probably be traced back to the episode of "The Bionic Woman" where Jamie runs around trying to escape a building, whose lights and doors are controlled by an evil artificial intelligence. He's a devout believer in the idea that when a computer program works, it's a complete coincidence. He can be reached at firstname.lastname@example.org.