An applet runs inside a browser or the applet viewer. An applet can ask the browser to do things for it, for example, fetch an audio clip, show a short message in the status line, or display a different web page. The ambient browser can carry out these requests, or it can ignore them. For example, if an applet running inside the applet viewer asks the applet viewer program to display a web page, nothing happens. To communicate with the browser, an applet calls the getAppletContext method. That method returns an object that implements an interface of type AppletContext. You can think of the concrete implementation of the AppletContext interface as a communication path between the applet and the ambient browser. In addition to getAudioClip and getImage, the AppletContext interface contains several useful methods, which we discuss in the next few sections. Inter-Applet CommunicationA web page can contain more than one applet. If a web page contains multiple applets from the same codebase, they can communicate with each other. Naturally, this is an advanced technique that you probably will not need very often. If you give name attributes to each applet in the HTML file, you can use the getApplet method of the AppletContext interface to get a reference to the applet. For example, if your HTML file contains the tag <applet code="Chart.class" width="100" height="100" name="Chart1"> then the call Applet chart1 = getAppletContext().getApplet("Chart1"); gives you a reference to the applet. What can you do with the reference? Provided you give the Chart class a method to accept new data and redraw the chart, you can call this method by making the appropriate cast. ((Chart) chart1).setData(3, "Earth", 9000); You can also list all applets on a web page, whether or not they have a name attribute. The getApplets method returns an enumeration object. (You learn more about enumeration objects in Volume 2.) Here is a loop that prints the class names of all applets on the current page. Enumeration e = getAppletContext().getApplets(); while (e.hasMoreElements()) { Object a = e.nextElement(); System.out.println(a.getClass().getName()); } An applet cannot communicate with an applet on a different web page. Display of Items in the BrowserYou have access to two areas of the ambient browsers: the status line and the web page display area. Both use methods of the AppletContext class. You can display a string in the status line at the bottom of the browser with the showStatus message, for example, showStatus("Loading data . . . please wait"); TIP
You can tell the browser to show a different web page with the showDocument method. There are several ways to do this. The simplest is with a call to showDocument with one argument, the URL you want to show. URL u = new URL("http://java.sun.com/index.html"); getAppletContext().showDocument(u); The problem with this call is that it opens the new web page in the same window as your current page, thereby displacing your applet. To return to your applet, the user must click the Back button of the browser. You can tell the browser to show the document in another window by giving a second parameter in the call to showDocument (see Table 10-2). If you supply the special string "_blank", the browser opens a new window with the document, instead of displacing the current document. More important, if you take advantage of the frame feature in HTML, you can split a browser window into multiple frames, each of which has a name. You can put your applet into one frame and have it show documents in other frames. We show you an example of how to do this in the next section.
NOTE
java.applet.Applet 1.2
java.applet.AppletContext 1.2
A Bookmark AppletThis applet takes advantage of the frame feature in HTML. We divide the screen vertically into two frames. The left frame contains a Java applet that shows a list of bookmarks. When you select any of the bookmarks, the applet tells the browser to display the corresponding web page (see Figure 10-8). Figure 10-8. A bookmark appletExample 10-6 shows the HTML file that defines the frames. Example 10-6. Bookmark.html1. <html> 2. <head> 3. <title>Bookmark Applet</title> 4. </head> 5. <frameset cols="320,*"> 6. <frame name="left" src="/books/1/281/1/html/2/Left.html" 7. marginheight="2" marginwidth="2" 8. scrolling="no" noresize="noresize"/> 9. <frame name="right" src="/books/1/281/1/html/2/Right.html" 10. marginheight="2" marginwidth="2" 11. scrolling="yes" noresize="noresize"/> 12. </frameset> 13. </html> We do not go over the exact syntax elements. What is important is that each frame has two essential features: a name (given by the name attribute) and a URL (given by the src attribute). We could not think of any good names for the frames, so we simply named them "left" and "right". The left frame uses the Left.html file (Example 10-7) , which loads the applet into the left frame. It simply specifies the applet and the bookmarks. You can customize this file for your own web page by changing the bookmarks. Example 10-7. Left.html1. <html> 2. <head><title>A Bookmark Applet</title></head> 3. <body> 4. <p> 5. Click on one of the radio buttons. 6. The corresponding web page 7. will be displayed in the frame on the right. 8. </p> 9. <applet code="Bookmark.class" width="290" height="300"> 10. <param name="link.1" value="http://java.sun.com"/> 11. <param name="link.2" value="http://java.net"/> 12. <param name="link.3" value="http://linuxtoday.com"/> 13. <param name="link.4" value="http://www.horstmann.com"/> 14. <param name="link.5" value="http://www.phptr.com"/> 15. <param name="link.6" value="http://usps.com"/> 16. <param name="link.7" value="http://www.cafeaulait.org"/> 17. </applet> 18. </body> 19. </html> The right frame loads a dummy file that we called Right.html (Example 10-8). (Some browsers do not approve when you leave a frame blank, so we supply a dummy file for starters.) Example 10-8. Right.html1. <html> 2. <head><title>Web pages will be displayed here.</title></head> 3. <body> 4. <p>Click on one of the radio buttons to the left. 5. The corresponding web page will be displayed here.</p> 6. </body> 7. </html> The code for the bookmark applet that is given in Example 10-9 is simple. It reads the values of the parameters link.1, link.2, and so on, and turns each of them into a radio button. When you select one of the radio buttons, the showDocument method displays the corresponding page in the right frame. Example 10-9. Bookmark.java1. import java.awt.*; 2. import java.awt.event.*; 3. import java.applet.*; 4. import java.util.*; 5. import java.net.*; 6. import javax.swing.*; 7. 8. public class Bookmark extends JApplet 9. { 10. public void init() 11. { 12. Box box = Box.createVerticalBox(); 13. ButtonGroup group = new ButtonGroup(); 14. 15. int i = 1; 16. String urlString; 17. 18. // read all link.n parameters 19. while ((urlString = getParameter("link." + i)) != null) 20. { 21. 22. try 23. { 24. final URL url = new URL(urlString); 25. 26. // make a radio button for each link 27. JRadioButton button = new JRadioButton(urlString); 28. box.add(button); 29. group.add(button); 30. 31. // selecting the radio button shows the URL in the "right" frame 32. button.addActionListener(new 33. ActionListener() 34. { 35. public void actionPerformed(ActionEvent event) 36. { 37. AppletContext context = getAppletContext(); 38. context.showDocument(url, "right"); 39. } 40. }); 41. } 42. catch (MalformedURLException e) 43. { 44. e.printStackTrace(); 45. } 46. 47. i++; 48. } 49. 50. add(box); 51. } 52. } It's an Applet. It's an Application. It's Both!Quite a few years ago, a Saturday Night Live skit poking fun at a television commercial showed a couple arguing about a white, gelatinous substance. The husband said, "It's a dessert topping." The wife said, "It's a floor wax." And the announcer concluded triumphantly, "It's both!" Well, in this section, we show you how to write a Java program that is both an applet and an application. That is, you can load the program with the applet viewer or a browser, or you can start it from the command line with the java program launcher. We are not sure how often this comes up we found it interesting that this could be done at all and thought you would, too. The screen shots in Figures 10-9 and 10-10 show the same program, launched from the command line as an application and viewed inside the applet viewer as an applet. Figure 10-9. The calculator as an applicationFigure 10-10. The calculator as an appletLet us see how this can be done. Every class file has exactly one public class. For the applet viewer to launch it, that class must derive from Applet. For Java to start the application, it must have a static main method. So far, we have class MyAppletApplication extends JApplet { public void init() { . . . } . . . public static void main(String[] args) { . . . } } What can we put into main? Normally, we make an object of the class and invoke setVisible(true) on it. But this case is not so simple. You cannot call setVisible on a naked applet. The applet must be placed inside a frame. To provide a frame, we create the class AppletFrame, like this: public class AppletFrame extends JFrame { public AppletFrame(Applet anApplet) { applet = anApplet; add(applet); . . . } . . . } The constructor of the frame puts the applet (which is a Component) inside the content pane of the frame. In the main method of the applet/application, we construct and show an AppletFrame. class MyAppletApplication extends JApplet { public void init() { . . . } . . . public static void main(String args[]) { AppletFrame frame = new AppletFrame(new MyAppletApplication()); frame.setTitle("MyAppletApplication"); frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } When the applet starts, its init and start methods must be called. We achieve this by overriding the setVisible method of the AppletFrame class: public void setVisible(boolean b) { if (b) { applet.init(); super.setVisible(true); applet.start(); } else { applet.stop(); super.setVisible(false); applet.destroy(); } } There is one catch. If the program is started with the Java launcher and not the applet viewer, and it calls getAppletContext, it gets a null pointer because it has not been launched inside a browser. This causes a runtime crash whenever we have code like getAppletContext().showStatus(message); While we do not want to write a full-fledged browser, we do need to supply the bare minimum to make calls like this work. The call displays no message, but at least it will not crash the program. It turns out that all we need to do is implement two interfaces: AppletStub and AppletContext. You have already seen applet contexts in action. They are responsible for fetching images and audio files and for displaying web pages. They can, however, politely refuse, and this is what our applet context will do. The major purpose of the AppletStub interface is to locate the applet context. Every applet has an applet stub (set with the setStub method of the Applet class). In our case, AppletFrame implements both AppletStub and AppletContext. We supply the bare minimum functionality that is necessary to implement these two interfaces. public class AppletFrame extends JFrame implements AppletStub, AppletContext { . . . // AppletStub methods public boolean isActive() { return true; } public URL getDocumentBase() { return null; } public URL getCodeBase() { return null; } public String getParameter(String name) { return ""; } public AppletContext getAppletContext() { return this; } public void appletResize(int width, int height) {} // AppletContext methods public AudioClip getAudioClip(URL url) { return null; } public Image getImage(URL url) { return null; } public Applet getApplet(String name) { return null; } public Enumeration getApplets() { return null; } public void showDocument(URL url) {} public void showDocument(URL url, String target) {} public void showStatus(String status) {} public void setStream(String key, InputStream stream) {} public InputStream getStream(String key) { return null; } public Iterator getStreamKeys() { return null; } } NOTE
Next, the constructor of the frame class calls setStub on the applet to make itself its stub. public AppletFrame(Applet anApplet) { applet = anApplet Container contentPane = getContentPane(); contentPane.add(applet); applet.setStub(this); } One final twist is possible. Suppose we want to use the calculator as an applet and application simultaneously. Rather than moving the methods of the CalculatorApplet class into the CalculatorAppletApplication class, we will just use inheritance. Here is the code for the class that does this. public class CalculatorAppletApplication extends CalculatorApplet { public static void main(String args[]) { AppletFrame frame = new AppletFrame(new CalculatorApplet()); . . . } } You can do this with any applet, not just with the calculator applet. All you do is derive a class MyAppletApplication from your applet class and pass a new MyApplet() object to the AppletFrame in the main method. The result is a class that is both an applet and an application. Just for fun, we use the previously mentioned trick of adding the applet tag as a comment to the source file. Then you can invoke the applet viewer with the source file without requiring an additional HTML file. Examples 10-10 and 10-11 list the code. You need to copy the CalculatorApplet.java file into the same directory to compile the program. Try running both the applet and the application: appletviewer CalculatorAppletApplication.java java CalculatorAppletApplication Example 10-10. AppletFrame.java1. import java.awt.*; 2. import java.awt.event.*; 3. import java.applet.*; 4. import java.io.*; 5. import java.net.*; 6. import java.util.*; 7. import javax.swing.*; 8. 9. public class AppletFrame extends JFrame 10. implements AppletStub, AppletContext 11. { 12. public AppletFrame(Applet anApplet) 13. { 14. applet = anApplet; 15. add(applet); 16. applet.setStub(this); 17. } 18. 19. public void setVisible(boolean b) 20. { 21. if (b) 22. { 23. applet.init(); 24. super.setVisible(true); 25. applet.start(); 26. } 27. else 28. { 29. applet.stop(); 30. super.setVisible(false); 31. applet.destroy(); 32. } 33. } 34. 35. // AppletStub methods 36. public boolean isActive() { return true; } 37. public URL getDocumentBase() { return null; } 38. public URL getCodeBase() { return null; } 39. public String getParameter(String name) { return ""; } 40. public AppletContext getAppletContext() { return this; } 41. public void appletResize(int width, int height) {} 42. 43. // AppletContext methods 44. public AudioClip getAudioClip(URL url) { return null; } 45. public Image getImage(URL url) { return null; } 46. public Applet getApplet(String name) { return null; } 47. public Enumeration getApplets() { return null; } 48. public void showDocument(URL url) {} 49. public void showDocument(URL url, String target) {} 50. public void showStatus(String status) {} 51. public void setStream(String key, InputStream stream) {} 52. public InputStream getStream(String key) { return null; } 53. public Iterator getStreamKeys() { return null; } 54. 55. private Applet applet; 56. } Example 10-11. CalculatorAppletApplication.java1. /* 2. The applet viewer reads the tags below if you call it with 3. appletviewer CalculatorAppletApplication.java (!) 4. No separate HTML file is required. 5. <applet code="CalculatorAppletApplication.class" width="200" height="200"> 6. </applet> 7. */ 8. 9. import javax.swing.*; 10. 11. public class CalculatorAppletApplication 12. extends CalculatorApplet 13. // It's an applet. It's an application. It's BOTH! 14. { 15. public static void main(String[] args) 16. { 17. AppletFrame frame = new AppletFrame(new CalculatorApplet()); 18. frame.setTitle("CalculatorAppletApplication"); 19. frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 20. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 21. frame.setVisible(true); 22. } 23. 24. public static final int DEFAULT_WIDTH = 200; 25. public static final int DEFAULT_HEIGHT = 200; 26. } |