Java Online Tutorial - Animation Techniques
MORE ABOUT APPLETS
Generally applets are much more powerful than applications
because they can be run within a web browser. They can
be harder to write as they work in context of the web
page they are in. As we mentioned earlier, to create
an applet one has to create a subclass of the java.applet.Applet
class. Applets also take strong advantage of Java's
Abstract Windowing Toolkit (awt), which provides behavior
for creating graphical user interface (GUI)-based applets
and applications: drawing to the screen; creating windows,
menu bars, buttons, check boxes, and other UI elements;
and managing user input such as mouse clicks and keypresses.
The awt classes are part of the java.awt package. We
shall take a look at some of these applet capabilities
in this section.
The applet tag
As you probably know by now that applets are invoked by a java-enabled
browser or an appletviewer by the use of a special tag
known as the <APPLET attributes></APPLET>
tag. This tag is embedded into a html page. Look at
the example below as we shall attempt to explain each
of its components in detail.
<HTML>
<HEAD>
<TITLE>The applet tag !</TITLE>
</HEAD><BODY>
<P>A sample html file which includes an applet:
<APPLET CODE="SampleApplet.class"
WIDTH=150 HEIGHT=25 >
<PARAM NAME = FONT VALUE = "TimesRoman" >
< PARAM NAME = STYLE VALUE = "Italic" >
< PARAM NAME = SIZE VALUE = "30" >
</APPLET>
</BODY>
</HTML>
The <APPLET> tag supports 11 attributes: ALIGN, ALT, ARCHIVE,
CODE, CODEBASE, HEIGHT, HSPACE, VSPACE, NAME, OBJECT
and WIDTH. Of these 11 applet
attibutes only the CODE, WIDTH and HEIGHT are required.
- The ALIGN attribute specifies the alignment of an applet's display
area with respect to the html page it resides in.
Values for this attibute are TOP, TEXTTOP, BOTTOM,
ABSBOTTOM, BASELINE, MIDDLE, ABSMIDDLE, LEFT and RIGHT.
- The ALT attribute identifies text that should be displayed
by a browser if it understands the <applet >
tags, but does not support java applets or has applet
processing disabled.
- The ARCHIVE tag identifies the class archives that enable the
browser to pre-load an applet. Using the archive tag
significantly improves applet start-up time. Typically
this points to a jar or zip file in the applet's codebase.
- The CODE attribute is a relative URL that identifies the name
of the bytecode file of the applet's main class.
- The CODEBASE attribute specifies the directory that will be searched
to locate the applet's bytecode class file. By default
it is the URL of the html page the applet resides
in.
- The HEIGHT and WIDTH attributes specifies in pixels the
height and width of the bounding box of the applets
display area.
- The HSPACE and VSPACE attributes specifies the number
of pixels to be used as the left and right and top
and bottom margins surrounding an applet.
- The NAME attribute is used to assign a name to an applet. This
name is used to support inter-applet communication.
- The OBJECT attribute identifies a file that contains a serialized
representation of an applet.
Back
to TOP
Applet life cycle
Applets do not need to be explicitly constructed. They are automatically
constructed by
the runtime environment associated with their applet
context - the web browser or appletviewer.
An applet's life cycle begins when a browser visits the web page
the applet resides in.
The first part of this process is called class loading.
Once this is done, the browser creates an instance of
the applet class. In the next step of the life cycle,
the browser sends several
start up method calls to the applet.
- init()
The first call the browser makes to the applet is
init(). This method provides the capability to load
applet parameters and perform any necessary initialization
processing such as:
- Creating the applet's GUI.
- Reading values from <PARAM> tags.
- Loading off-screen images from external files.
- Loading audio clips from external files.
- start() and stop()
The start() method serves as the execution entry point
for an applet when it is initially executed and restarted
as the result of a user returning to the web page
that contains the applet.
The stop() method provides the capability to stop
and applet's execution when the web page theat contains
the applet is no longer active.
There are three activities an applet should suspend
in the stop() method and resume in the start() method:
- Animation - There is no benefit in wasting cycles on an
animation that no one is looking at.
- Sound - It would confuse the user to play sound for
a different page than
the one being viewed. Iconified programs of any
kind should not play sounds.
- General background thread processing - The thread would
be doing work
for a page other than the one being viewed. This
would steal
resources that should be available to the current
page.
- paint(Graphics g)
This method is called both at start-up time and subsequently
at the browser's discretion. After the initial call,
the browser calls paint() whenever it needs the applet
to render itself.
- destroy()
The browser calls destroy() when it no longer needs
the applet. The destroy() method
is the applet's opportunity to release any non-memory
resources it might have, such as
threads and network connections.
In fact, the call only happens when the applet's page
is reloaded or when the browser
itself terminates. Because the browser caches the
applet even when the applet's page
is no longer displayed, destroy() is rarely called.
Back
to TOP
What applets can do and cannot do
Here are some of the things browsers let applets do:
- Applets can usually make network connections to the host they came from.
- Applets running within a web browser can easily cause HTML
documents to be displayed.
- Applets can invoke public methods of other applets on the same page.
- Applets that are loaded from the local file system (from a
directory in the user's CLASSPATH) have none of the
restrictions that applets loaded over the network do.
- Although most applets stop running once you leave the page
they're on, they don't have to.
Browsers impose the following restrictions on any applet loaded over
the network:
- An applet cannot load libraries or define native
methods.
- It cannot ordinarily read or write files on the
host that's executing it.
- It cannot make network connectiopns except to the
host it came from.
- It cannot start any program on the host that's executing
it.
- It cannot read certain system properties.
- Windows that an applet brings up to look different
than windows that an
application brings up.
Back
to TOP
An Animation Applet
Displaying animation is probably the most popular use of java applets
on the web. We can use HTML to display static images,
but we need java to make them come alive.
There are three general steps that should usually be followed when creating
animation applets.
- Load the images.
- Start a thread.
- Run the animation.
While the first part is accomplished in the applet's
init() method, the other two are accomplished in
start() and paint().
Take a good look at the source code below and also see the example
running on this page. Then we will discuss an advanced
technique for improving animation called double buffering.
import java.awt.*;
import java.applet.*;
/** Sample html file provided to run this example.
<applet code=Animation codebase="." height=68 width=55>
</applet>
*/
public class Animation extends Applet implements Runnable {
Image img[] = new Image[10];
Image current;
int picture[] = {0,1,2,3,4,5,6,7,8,9};
Thread thread;
public void init() {
for (int i=0;i<img.length;i++){
img[i]=getImage(getCodeBase(), "./images/" + "T"+ (i+1) +".gif");
}
}
public void start(){
if(thread==null)
thread=new Thread(this);
thread.start();
}
public void stop() {
if(thread!=null)
thread=null;
thread.stop();
}
public void run(){
while(true) {
for(int i=0;i<picture.length;i++) {
current=img[i];
repaint();
try {
thread.sleep(200);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
}
public void paint(Graphics g) {
if(current!=null)
g.drawImage(current, 0, 0, this);
showStatus("Inside paint");
}
}
To see a sample of the
above applet in action go
here.
Back
to TOP
Reducing animation flicker: Double Buffering
In the above example you might have noticed that parts of the animation
seem to dissapear as the frames are drawn onto the screen
which gives rise to something called flicker.
This flicker is due
to the fact that the entire screen is repainted with
each new frame. For advanced animation, the
best solution for fighting flicker is a technique called
double buffering.b
With double-buffering, you create a second surface (offscreen, so to
speak), do all your painting to that offscreen surface,
and then draw the whole surface at once onto the actual
applet (and onto
the screen) at the end-rather than drawing to the applet's
actual graphics surface. Because all the work actually
goes on behind the scenes, there's no opportunity for
interim parts of the drawing process to appear accidentally
and disrupt the smoothness of the animation.
Double-bufferingis the process of doing all your drawing to an offscreen
buffer and then displaying that entire screen at once.
It's called double-buffering because there are two drawing
buffers and you switch between them.
Creating Applets with Double-Buffering
To create an applet that uses double-buffering, you need two things:
an offscreen image to draw on and a graphics context
for that image. Those two together mimic the effect
of the applet's drawing surface: the graphics context
(an instance of Graphics) to provide the drawing methods,
such as drawImage (and drawString), and the Image to
hold the dots that get drawn.
There are four major steps to adding double-buffering to your applet.
First, your offscreen image
and graphics context need to be stored in instance variables
so that you can pass them to the paint() method. Declare
the following instance variables in your class definition:
Image offscreenImage;
Graphics offscreenGraphics;
Second, during the initialization of the applet, you'll create an Image
and a Graphics object and assign them to these variables
(you have to wait until initialization so you know how
big they're going to be). The createImage() method gives
you an instance of Image, which you can then send the
getGraphics() method in order to get a new graphics
context for that image:
offscreenImage = createImage(size().width, size().height);
offscreenGraphics = offscreenImage.getGraphics();
Now, whenever you have to draw to the screen (usually in your paint()
method), rather than drawing to paint's graphics, draw
to the offscreen graphics. For example, to draw an image
called img at position 10,10, use this line:
offscreenGraphics.drawImage(img, 10, 10, this);
Finally, at the end of your paint method, after all the drawing
to the offscreen image is done, add the following line
to place the offscreen buffer on to the real screen:
g.drawImage(offscreenImage, 0, 0, this);
Of course, you most likely will want to override update() so that
it doesn't clear the screen between paintings:
public
void paint(Graphics g) {
update(g);
}
Let's review those four steps:
- Add instance variables to hold the image and graphics contexts
for the offscreen buffer.
- Create an image and a graphics context when your applet is initialized.
- Do all your applet painting to the offscreen buffer, not the applet's
drawing surface.
- At the end of your paint() method, draw the offscreen buffer
to the real screen.
Back
to TOP
The Animation Applet: Revisited
Here is the animation applet which now supports double buffering
and eliminates flicker. The html file is included within
comments in the source code. Save it separately within
a html file.
import java.awt.*;
import java.applet.*;
/**
<applet code="DoubleBufferedAnim.class" codebase="." width=55 height=68>
<param name=delay value="200">
</applet>
*/
public class DoubleBufferedAnim extends Applet implements Runnable {
Image img [] = new Image[10];
Image current, doubleg;
int picture[] = {0,1,2,3,4,5,6,7,8,9};
Thread thread;
Graphics gg;
int delay=200;
public void init() {
for(int i=0; i<img.length;i++){
img[i]=getImage(getCodeBase(),"./images/"+"T"+(i+1)+".gif");
}
delay=Integer.parseInt(getParameter("delay"));
}
public void start() {
if (thread==null)
thread= new Thread(this);
thread.start();
}
public void stop() {
if(thread != null)
thread.stop();
thread=null;
}
public void run() {
while (true) {
for (int i=0;i<picture.length;i++) {
current=img[i];
repaint();
try {
thread.sleep(delay);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void paint(Graphics g) {
update(g);
}
public void update(Graphics g) {
if (current != null) {
doubleg = createImage(100, 100);
gg = doubleg.getGraphics();
gg.drawImage(current, 0,0, null);
g.drawImage(doubleg, 0, 0, this);
showStatus("Inside paint");
}
}
}
To see a sample of the
improved applet in action go
here.
A Note on Disposing Graphics Contexts
pIf you make pextensive use of graphics contexts in your applets or
applications, be aware that those contexts will often
continue to stay around after you're done with them,
even if you no longer have any references to them. Graphics
contexts are special objects in the awt that map to
the native operating system; Java's garbage collector
cannot release those contexts by itself. If you use
multiple graphics contexts or use them repeatedly, you'll
want to explicitly get rid of those contexts once you're
done with them.
Use the dispose() method to explicitly clean up a graphics context.
A good place to put this might be in the applet's destroy()
method.
public void
destroy() {
offscreenGraphics.dispose();
}
Download a zipped copy of
all the source code, class files and html
for this chapter here.
Back
to TOP
Now on to the next chapter The
Java Awt or Graphic User Interfaces
All questions and comments can be addressed to the
author.
All material appearing within this website is copyright
protected and may not be reproduced elsewhere without
the express written permission of the author (Sanjeev
Dasgupta)
|