As discussed previously, Java is a full-featured programming language that is capable of producing full-featured standalone applications. However, the innovations that Java brings to the World Wide Web have created the most interest in Java. This chapter focuses on the ways in which applets can enhance Web pages.
Applets can add a variety of enhancements to any Web page, from a personal page to a business page. Within the restrictions placed on applets by browsers and security, you can create astounding applets. Applets can bring sound, animation, user interaction, and much more to your Web pages.
The Web has come a long way since 1992. Now graphics are very common (and sometimes a bit annoying). With the release of Netscape, server-push animation became possible, although it was slow and awkward. This server-push animation is not practical for animations of any significant length and has never really been used for much other than novelty purposes. But with Java, the possibility for real-time animations is a reality.
Visual enhancements are some of the simplest applets to program and use. Often these applets are simply variations of image viewers, but you can create surprisingly different applets using the techniques required to make an image viewer. For example, the following applets can be created by displaying and manipulating images:
All these types of applets use image techniques; the clock moves hands to display the time, a demonstration applet shows diagrams, an animator flips a series of images for motion, and a photo viewer cycles through snapshots. All these applets contain a lot of similar code, yet all accomplish different tasks. The following sections examine some of these applets and how they enhance the appearance of Web pages.
The Web is global entity and is certainly not limited to any specific geographic area or time zone. In fact, the global aspect of the Web is one of its most appealing factors. Java applets can help enhance the global nature of the Web.
Many Web pages have begun to incorporate snapshots of the weather outside or other forms of local information. Silly as it may seem, the local time is one of the most basic forms of local information and can be a very useful navigation device. The following Java clocks can be used to show time information on your Web page:
Clock | |
Written by Nils Hedström | |
http://www-und.ida.liu.se/~d94nilhe/java/applets.html | |
WorldClock | |
Written by Vijay Vaidy | |
http://www.webpage.com/~vijay/java/wt/testwt.html |
The first clock uses graphic images to draw the hands of an analog clock (see Figure 4.1). The second clock has no graphical enhancements and displays the time and date information using text (see Figure 4.2).
Figure 4.1. A clock is an example of an informative applet.
Figure 4.2. A simple clock applet showing times at various locations around the world.
Listing 4.1 shows some of the Java code used to produce the clock in Figure 4.1.
public class Clock extends java.applet.Applet implements Runnable { int width,height,num_lines,sleep,timezone,backgroundType; Polygon clockBackground; URL homepage; private Needle hour,minute,second; double pi=3.1415926535f; Color clockBackground_col,clockBackgroundBorder_col,backgroundBorder_col,background_col; Thread animate=null; Image backBuffer; Image backgroundImage; Graphics backGC; public void run() //Run the applet { while (true) { updateNeedles(); repaint(); try {Thread.sleep(sleep);} catch (InterruptedException e){} } } public void makeClockBackground() // Creates a polygon-background with num_lines-corners { double add,count; clockBackground=new Polygon(); add=2.*pi/num_lines; for(count=0;count<=2.*pi;count+=add) { clockBackground.addPoint(size().width/2+(int)(size().width*Math.cos(count)/2.), size().height/2+(int)(size().height*Math.sin(count)/2.)); } } public void drawClockBackground(Graphics g) // Draws the background of the Clock { if(backgroundType!=1) { g.setColor(clockBackground_col); g.fillPolygon(clockBackground); g.setColor(clockBackgroundBorder_col); g.drawPolygon(clockBackground); } if(backgroundType!=0) { int img_width=backgroundImage.getWidth(null); int img_height=backgroundImage.getHeight(null); int x=(size().width-img_width)/2; int y=(size().height-img_height)/2; if (x<0) x=0; if(y<0) y=0; if((img_width!=-1) && (img_height!=-1)) g.drawImage(backgroundImage,x,y,null); } } public void start() // When the applet is started { if (animate == null) { animate = new Thread(this); animate.start(); } } public void stop() // When the applet is stopped { if (animate != null) { animate.stop(); animate=null; } }
A clock applet requires quite a bit of code. Listing 4.1 shows only a third of the code needed to produce the entire clock shown in Figure 4.1. The applet developer must also provide the images used to make up the clock face and hands and the animation that keeps the hands moving and keeping accurate time. The code shown in Listing 4.1 should give you an idea about what's involved in creating Java applets. Java applets are full-fledged programs, and as such, they require some time and planning to create them.
Applets can also be used for educational purposes or to inform users about how to accomplish tasks by means of demonstration. Rather than just listing a number of steps, applets can visually demonstrate how to do something. For some topics, a visual demonstration is far more effective than a verbal explanation. The following applet is an example of how you can use graphics and animation to demonstrate concepts (see Figure 4.3):
Juggling Applet | |
Written by Christopher Sequin | |
http://www.acm.uiuc.edu/webmonkeys/juggling/ |
Listing 4.2 shows the code for the Juggling Applet. Keep in mind that this code does quite a bit. It lets the user configure the number of balls used in the demonstration, it animates the hands, and it animates the balls along the correct paths. Don't worry about compiling this code, the applet is included on the CD-ROM. The listing is just provided to give you an example of some real Java code.
/* * @(#)Juggling.java 1.0f 95/05/01 Chris Seguin * E-mail: seguin@uiuc.edu * * Copyright 1995 University of Illinois (UIUC) */ import java.io.InputStream; import java.awt.*; import java.net.*; /** * JugglingImages class. This is a container for a list * of images that are animated. * * @author Chris Seguin * @version 1.0f, May 1, 1995 */ class JugglingImages { /** * The images. */ Image imgs[]; /** * The number of images actually loaded. */ int nImagesCount = 0; /** * Load the images, from dir. The images are assumed to be * named T1.gif, T2.gif... */ JugglingImages(URL context, String dir, Juggling parent) { nImagesCount = 0; imgs = new Image[10]; int nWidth = 0; for (int i = 1; i < imgs.length; i++) { Image im = parent.getImage(parent.getDocumentBase(), dir + "/T" + i + ".gif"); imgs[nImagesCount++] = im; } } } /** * BallPaths class. This is a container for a path * of juggling balls * * @author Chris Seguin * @version 1.0f, May 1, 1995 */ class BallPaths { /** * Arrays containing the path of the balls */ int pnX[] = {0}; int pnY[] = {0}; int nLength = 1; /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex) { if ((nIndex > nLength) || (nIndex < 0)) return 0; return pnX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex > nLength) || (nIndex < 0)) return 0; return pnY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * CascadeBallPaths class. This is a container for a path * of juggling balls, the balls are moving in a standard * cascade pattern * * @author Chris Seguin * @version 1.0f, May 1, 1995 */ class CascadeBallPaths extends BallPaths { /** * Arrays containing the path of the balls */ int pnX[] = { 20, 24, 27, 31, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 143, 144, 141, 138, 134, 130, 126, 123, 119, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 7, 6, 9, 12, 16 }; int pnY[] = { 76, 78, 76, 70, 60, 60, 50, 42, 34, 28, 22, 18, 14, 12, 10, 10, 10, 12, 14, 18, 22, 28, 34, 42, 50, 66, 68, 70, 72, 74, 76, 78, 76, 70, 60, 60, 50, 42, 34, 28, 22, 18, 14, 12, 10, 10, 10, 12, 14, 18, 22, 28, 34, 42, 50, 66, 68, 70, 72, 74 }; /** * The length of the arrays */ int nLength = 60; /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * ReverseCascadeBallPaths class. This is a container * for a path of juggling balls, the balls are moving * in a reverse cascade pattern * * @author Chris Seguin * @version 1.0f, May 1, 1995 */ class ReverseCascadeBallPaths extends BallPaths { /** * Arrays containing the path of the balls */ int pnX[] = { 12, 9, 6, 3, 0, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 125, 120, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 27, 24, 21, 18, 15 }; int pnY[] = { 60, 60, 60, 60, 60, 60, 51, 42, 35, 28, 23, 18, 15, 12, 11, 10, 11, 12, 15, 18, 23, 28, 35, 42, 51, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 51, 42, 35, 28, 23, 18, 15, 12, 11, 10, 11, 12, 15, 18, 23, 28, 35, 42, 51, 60, 60, 60, 60, 60 }; /** * The length of the arrays */ int nLength = 60; /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * JugglingBall class. This is a juggling ball * * @author Chris Seguin * @version 1.0f, May 1, 1995 */ class JugglingBall { /** * The location on the ball's path */ int nCycleSlot; /** * The color of the ball - specified by an index into the ball array */ int nBallColor; /** * The current location of the ball */ int nX; int nY; /** * The path to follow */ BallPaths ptbpPath; /** * JugglingBall - creates a juggling ball */ public JugglingBall (int nStartPos, int nStartColor, BallPaths ptbpThePath) { nCycleSlot = nStartPos; nBallColor = nStartColor; ptbpPath = ptbpThePath; nX = ptbpPath.LookupX(nStartPos); nY = ptbpPath.LookupY(nStartPos); } /** * Move - moves the ball to the next location */ public void Move () { nCycleSlot++; if ((nCycleSlot >= ptbpPath.Length ()) || (nCycleSlot <= 0)) { nCycleSlot = 0; } nX = ptbpPath.LookupX(nCycleSlot); nY = ptbpPath.LookupY(nCycleSlot); } /** * XLoc - returns the x location */ public int XLoc () { return nX; } /** * YLoc - returns the Y location */ public int YLoc () { return nY; } /** * Color - returns the color */ public int Color () { return nBallColor; } } /** * HandPath class. This is a container for the paths of the hands * * @author Chris Seguin * @version 1.0f, May 3, 1995 */ class HandPath { /** * Arrays containing the path of the hands */ int pnLeftHandX[] = { 7, 6, 9, 12, 16, 20, 24, 27, 31, 35, 35, 31, 27, 24, 20, 16, 12, 9, 6, 7 }; int pnRightHandX[] = { 143, 144, 141, 138, 134, 130, 126, 123, 119, 115, 115, 119, 123, 126, 130, 134, 138, 141, 144, 143 }; int pnHandY[] = { 73, 75, 77, 79, 81, 83, 85, 83, 77, 67, 67, 57, 51, 49, 51, 53, 55, 57, 59, 61 }; /** * The length of the arrays */ int nLength = 60; int nBalls = 0; /** * HandPath - creates a hand path */ public HandPath (int nStartBalls) { nBalls = nStartBalls; } /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex, boolean bLeft) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; // Limit the lookup to the range if (nIndex >= 20 * nBalls) nIndex = 19; while (nIndex >= 20) nIndex -= 20; // Look up the value if (bLeft) return pnLeftHandX[nIndex]; else return pnRightHandX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; // Limit the lookup to the range if (nIndex >= 20 * nBalls) nIndex = 19; while (nIndex >= 20) nIndex -= 20; // Look up the value return pnHandY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * Hand class. This is a hand * * @author Chris Seguin * @version 1.0f, May 3, 1995 */ class Hand { /** * The location on the ball's path */ int nCycleSlot; /** * Whether this is the left hand */ boolean bLeft; /** * The current location of the ball */ int nX; int nY; /** * The path to follow */ HandPath phPath; /** * Hand - creates a hand */ public Hand (int nStartPos, HandPath phThePath, boolean bStartLeft) { nCycleSlot = nStartPos; bLeft = bStartLeft; phPath = phThePath; nX = phPath.LookupX(nStartPos, bLeft); nY = phPath.LookupY(nStartPos); } /** * Move - moves the ball to the next location */ public void Move () { nCycleSlot++; if ((nCycleSlot >= phPath.Length ()) || (nCycleSlot <= 0)) { nCycleSlot = 0; } nX = phPath.LookupX(nCycleSlot, bLeft); nY = phPath.LookupY(nCycleSlot); } /** * XLoc - returns the x location */ public int XLoc () { return nX; } /** * YLoc - returns the Y location */ public int YLoc () { return nY; } } /** * A juggling demonstration program * * @author Chris Seguin * @version 1.0f, May 1, 1995 */ public class Juggling extends java.applet.Applet implements Runnable { /** * The path of the juggling balls */ BallPaths pjbPaths; /** * The juggling balls */ JugglingBall pjbBalls[] = {null, null, null}; /** * The paths that the hands trace out */ HandPath phHandPaths; /** * The hands */ Hand phLeft; Hand phRight; /** * The directory or URL from which the images are loaded */ String dir; /** * The images used. */ JugglingImages jbiImages; /** * The thread animating the images. */ Thread kicker = null; /** * The delay between animation frames */ int nSpeed; /** * Shape of the window */ int nHeight = 0; int nWidth = 0; /** * The number of balls in the demonstration */ int nBalls = 0; /** * Parameter info. */ public String[][] getParameterInfo() { String[][] info = { {"balls", "int", "the number of balls to animate"}, {"speed", "int", "the speed the balls move at"}, {"img", "urls", "the directory where the images are located"}, }; return info; } /** * Initialize the applet. Get attributes. */ public void init() { // Load the parameters from the HTML file String at = getParameter("img"); dir = (at != null) ? at : "images"; at = getParameter("speed"); nSpeed = (at != null) ? Integer.valueOf (at).intValue() : 20; at = getParameter("height"); nHeight = (at != null) ? Integer.valueOf (at).intValue() : 100; at = getParameter("width"); nWidth = (at != null) ? Integer.valueOf (at).intValue() : 170; at = getParameter("balls"); nBalls = (at != null) ? Integer.valueOf (at).intValue() : 3; // Initialize the Ball variables pjbPaths = new CascadeBallPaths (); pjbBalls[0] = new JugglingBall ( 0, 0, pjbPaths); pjbBalls[1] = new JugglingBall (40, 2, pjbPaths); pjbBalls[2] = new JugglingBall (20, 4, pjbPaths); // Initialize the hand variables phHandPaths = new HandPath (nBalls); phLeft = new Hand (5, phHandPaths, true); phRight = new Hand (35, phHandPaths, false); resize(nWidth, nHeight); } /** * Run the image loop. This method is called by class Thread. * @see java.lang.Thread */ public void run() { // Create the thread Thread.currentThread().setPriority(Thread.MIN_PRIORITY); // Load the images jbiImages = new JugglingImages(getDocumentBase(), dir, this); // Do the animation int ndx = 0; while (size().width > 0 && size().height > 0 && kicker != null) { for (ndx = 0; ndx < nBalls; ndx++) { (pjbBalls[ndx]).Move(); } phLeft.Move(); phRight.Move(); repaint(); try {Thread.sleep(nSpeed);} catch (InterruptedException e){} } } /** * Paint the current frame. */ public void paint(Graphics g) { update ; } public void update(Graphics g) { if ((jbiImages != null) && (jbiImages.imgs != null)) { // Erase the background g.setColor(java.awt.Color.lightGray); g.fillRect(0, 0, nWidth, nHeight); int ndx = 0; for (ndx = 0; ndx < nBalls; ndx++) { if (jbiImages.imgs[pjbBalls[ndx].Color ()] == null) { System.out.print ("ERROR::No Image "); System.out.println (ndx); } g.drawImage(jbiImages.imgs[pjbBalls[ndx].Color ()], (pjbBalls[ndx]).XLoc(), (pjbBalls[ndx]).YLoc(), this); } // Draw the hands g.drawImage(jbiImages.imgs[7], phLeft.XLoc(), phLeft.YLoc(), this); g.drawImage(jbiImages.imgs[7], phRight.XLoc(), phRight.YLoc(), this); } } /** * Start the applet by forking an animation thread. */ public void start() { if (kicker == null) { kicker = new Thread(this); kicker.start(); } } /** * Stop the applet. The thread will exit because kicker is set to null. */ public void stop() { kicker = null; } }
This chapter has shown you some simple applets based on animating images, but suppose you wanted to spice up a Web page with something a little more dynamic, such as the capability to interact with user input. Remember that Java has a complete set of windowing tools in the Abstract Window Toolkit. These tools allow you to build interfaces into your applets and create applets that interact with user input. For example, if you wanted to have some sort of animation or display some information based on when a user clicked a mouse, Java enables you to do just that.
ClickBoard is an example of an applet that uses both animation and user input. The program can display a series of still images in sequence to create an animation, and the user activates the animation by clicking an image (see Figure 4.4 and Figure 4.5):
ClickBoard: Interactive Animation | |
Written by Steve Fu | |
http://www.intrinsa.com/personal/steve/ClickBoard/ClickBoard.html |
ClickBoard is quite flexible, and the user can configure many of the applet's attributes. For example, ClickBoard makes use of a configuration file that allows users to specify the following items:
A configuration file allows the applet to be adaptable without requiring the user to alter the actual program. When you are designing applets that incorporate a number of complex features, configuration files or applet parameters can be a great way to make your applet useful to many people or easy to change later. Implementing configuration files or applet parameters can save you the trouble of reprogramming an applet to change its functionality and also allows you to pass the applet along to other users with a user-friendly method for implementing changes.
Figure 4.4. In the ClickBoard applet, the user activates the animation by clicking the fish.
Figure 4.5 The ClickBoard animation plays after the user clicks the picture.
Many personal Web pages are enhanced by putting up photographs of family or friends. With a slide show applet, you can put together a collection of images that a user could flip through like a photo album. You could even add sound to the applet to assemble a soundtrack to your slide show. Such an applet could be used for personal photos, product photos, or even presentation slides.
The following is an example of such a slide show applet:
SlideShow | |
Written by David Gulbransen | |
http://www.fa.indiana.edu/~dgulbran/slideshow.html |
This applet allows you to specify a number of images to be loaded, and a sound file to play. It also has controls to allow the user to flip through the slides or play them in a slide show and a button to turn off the soundtrack (see Figure 4.6). The SlideShow applet is a good example of a fairly simple applet that can be very flexible. Chapter 13 covers the development of the SlideShow applet in detail.
Figure 4.6. A slide show applet can add a new twist to a Web photo gallery.
In addition to adding more graphics and sound capabilities to Web pages, Java applets can also do a great deal to enhance the functionality of Web pages. You can use applets to provide complex information in a more intuitive way or to simplify the presentation of such information. The following sections describe some applets that show how you can add functionality to a Web page.
The Curve Applet is an educational applet designed to show different types of mathematical curves and how they are manipulated (see Figure 4.7). The applet shows three types of curves and how those curves are manipulated by points on the curve. Drawing curves is a fundamental part of graphics programming, and this applet helps explain how curves function:
Written by Michael Heinrichs
Curve Applet
http://fas.sfu.ca:80/1/cs/people/GradStudents/heinrica/personal/curve.html
Because Java can communicate back to a server, applets can be configured to provide data to users in real time. Stock prices, for example, are in a constant state of flux, updating from minute to minute throughout the day. An applet that could provide real-time information about stocks could be invaluable as a device for keeping track of stock prices.
The StockTrace Applet enables you to specify stocks to trace, and then fetches the price information from the server and displays current prices (see Figure 4.8). This applet also has a graphing function that enables you to plot the performance of a particular stock. Although putting server-based data onto Web pages has always been possible, updating the data in real time was not practical or easy. Updating standard HTML pages dynamically is slow and taxes both the browser and the server. But because Java applets run within the context of the Java Virtual Machine and open a separate data connection to the host machine, updating Java applets is not taxing for the browser or the Web server.
StockTrace Applet | |
Written by Christian Dreke | |
http://www.cs.virginia.edu/~cd4v/graph/StockGraph.html |
Java applets can update any kind of data in real time with the proper server connection. Another prototype applet designed to showcase this capability is the TeleRadiology applet. This applet was developed at the Los Alamos National Laboratory and is designed to show how medical information could be transmitted and viewed by using such real-time applications.
This prototype was designed to show how medical information can be transmitted to various locations, allowing consultations and diagnostics to be performed anywhere in the world. Such technology could help increase the quality of medicine in rural areas or help doctors verify opinions with colleagues around the globe.
Java TeleMed Prototype | |
Written by Andrew White | |
http://www.acl.lanl.gov/~rdaniel/classesJDK/PickTest2.html |
Communication with a server is not limited to updating real-time information. Java applets can be written to perform typical client/server tasks, such as functioning as database front ends. The Interactive PC Scoreboard is an example of how applets can communicate back to a database, use the database to look up information, and then redisplay the information in a useful format.
This particular applet allows users to enter information about what qualities they are looking for in a personal computer. The applet then searches a database and, based on the criteria the user has selected, displays some recommended machines. Users can then click the recommended models to get configuration and pricing information.
c|net Interactive PC Scoreboard | |
http://www.cnet.com/Content/Reviews/Compare/Pc100/0,30,,0200.html |
The lack of seamless sound has plagued the Web for many years. Downloading sounds has always been possible, but the capability to load sounds directly with a page has eluded the Web. The latest versions of Netscape and third-party applications such as Real Audio have begun to add the dimension of sound to the Web, but they still fall short of full Web integration. Java brings integrated sound to the Web. An applet can play a sound when the applet is launched, or the applet can be configured to play sounds at the click of a button.
An outstanding example of an applet that utilizes sound is the Player Piano applet. This applet actually simulates a player piano, displaying the roll that is used to create the sounds within the applet. Sound can enhance Web pages by adding personality and, as this applet shows, functionality.
Player Piano | |
Written by Mark Leather | |
http://reality.sgi.com/employees/mark/piano/index.html |
Don't be disappointed if the first applet you create doesn't allow users to select a region of the country and display real-time satellite weather photos. The applets in this chapter have been presented to show you the range of what is possible with Java, not to imply that these are beginning applets. Each of the applets shown in this chapter utilize the basic idea of adding exciting new elements to a Web page. Some of them do so by adding animations, and others add animation and sound. They range from the functional (A Clock, the TeleRadiology applet) to educational (The Juggling Applet, the PC Scoreboard) to fun (ClickBoard, the Player Piano). As you become more involved with Java, you might want to start adding some of the advanced features shown in this chapter, but every programmer still needs to start with the basics. Now that you have a handle on what Java is and what it can do, the next chapters move on to cover how you can start adding Java to your own Web pages. Chapter 5 examines the issues raised in adding Java applets to your Web pages and shows you an example of how to add an applet to your page. Chapter 7 helps you to create your first applet, HelloWorld. From there, you'll move onto some more advanced programming topics, which give you the basic foundation you need to start creating your own applets.