CIS 121 March 13, 2000
Applets
Recall that an applet is a special type of Java program. It has no
main method, and, therefore, cannot be executed with the Java
interpreter. Applets are run in the context of a web browser or the
appletviewer which is included with the JDK from Sun Microsystems.
There are a few methods that are particular to applets that need to be
mentioned.
| init |
This method can be used the way a constructor is used. (We can
have a default constructor in the applet if we want) This method is
executed once when the browser/appletviewer loads the applet. |
| start |
This method is called each time the applet is made visible. That is,
if we minimize the browser, then maximize it again so that the applet
is visible, the start method is executed again. However, init is not
executed again. |
| stop |
This method is called when the browser/appletviewer changes so
that the applet is no longer visible. |
| destroy |
This method is called when the browser/appletviewer changes so
that the applet will stop running completely. For example, if we exit the
browser/appletviewer. It is similar to the finalize method in a normal
program. |
Within an applet there is a special method that we can take
advantage of.
The method repaint will cause the method paint to be called as
soon as the browser/appletviewer can call it. This is why it is important
not to place code in the start or init methods which take a long time to
execute especially infinite loops.
Applets cannot run by themselves since they have no main method. They must
be run in the context of a browser which acts as the parent of the
applet. In order to run an applet we must write a small HTML (HyperText
Markup Language) document. We do not need a complete HTML document. The
following code will suffice. Suppose we wish to run the applet
MyApplet.class.
<applet code=MyApplet width=w height=l>
</applet>
Threads
Recall that a thread is a single sequential flow of control. In
all of the programs that you wrote in CIS 120 and this the first part
of this semester ran in their own thread. Java allows us to have more
than one thread executing simulataneously. Since the CPU can only
process one thing at a time, multithreading is accomplished by very
quickly switching threads in and out of the processor.
Multithreading is sometimes necessary when developing applets. Recall
that an applet cannot have a main method, and, therefore, must be run
in the context of a browser or appletviewer. The browser/appletviewer
runs in its own thread, and so we must make sure that the methods in
the applet do not take a long time to execute. In particular, we shouldn't
have infinite loops in the methods of an applet if we intend to have
that applet run in the thread of the browser/appletviewer.
The following is a partial sequence of execution when an applet runs in the
thread of a browser/appletviewer.
| The browser/appletviewer loads the applet |
| The init() method in the applet is executed |
| The start() method in the applet is executed |
The class Thread is found in the java.lang. Since each applet we create
extends the class Applet, we can't make the applet a subclass of Thread.
In order to run an applet in its own thread we implement the interface
Runnable. The Runnable interface has one method which must be overridden,
public void run(). This method is run when the thread is started.
There a few methods available in the Thread class that are important. Suppose we have
a Thread object called thread.
| thread.start() |
causes the thread to begin executing. The run() method is then
called. |
| thread.suspend() |
temporarily halts the execution of the thread. |
| thread.resume() |
resume execution of the thread |
| thread.stop() |
permanently stops the execution of the thread |
There is a static method called sleep in the class Thread which takes
as an argument a number of milliseconds. We can use this method to cause
the Thread to sleep for a number of milliseconds. This method must be
called in a try block since it might cause an InterruptedException to
be thrown. This occurs if the user halts the applet while the thread is
sleeping.
Let us look again at examples of using threads.
Recall the digital clock example.
import java.applet.*;
import java.awt.*;
import java.util.*;
public class DigitalClock extends Applet {
Font font = new Font("Monospaced",Font.BOLD,16);
int hours,mins,secs;
public void start() {
while (true) {
Calendar time = Calendar.getInstance();
hours = time.get(Calendar.HOUR);
mins = time.get(Calendar.MINUTE);
secs = time.get(Calendar.SECOND);
repaint();
}
}
public void paint(Graphics g) {
g.setFont(font);
g.drawString(String.valueOf(hours) + ":" +
String.valueOf(mins) + ":" +
String.valueOf(secs),50,50);
}
}
Since we don't override the init method nor have a constructor, the first method executed by the browser/appletviewer is the start method.
Within the start method we have an infinite loop which tries to call the repaint method. Recall that a call to the repaint method will cause the
browser/appletviewer to call the method paint as soon as it can. However since we have an infinite loop in the start method, the browser/appletviewer
never regains control so nothing happens.
In order to correct the problem, we run the applet in its own thread. We will override the init method to start the thread running.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class DigitalClock2 extends Applet implements Runnable {
Font font = new Font("Monospaced",Font.BOLD,16);
int hours,mins,secs;
Thread appletThread;
public void init() {
if (appletThread == null) {
appletThread = new Thread(this);
appletThread.start();
}
}
public void run() {
while (true) {
Calendar time = Calendar.getInstance();
hours = time.get(Calendar.HOUR);
mins = time.get(Calendar.MINUTE);
secs = time.get(Calendar.SECOND);
repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException i) {
System.exit(1);
}
}
}
public void destroy() {
if (appletThread != null) {
appletThread.stop();
appletThread = null;
}
}
public void paint(Graphics g) {
g.setFont(font);
g.drawString(String.valueOf(hours) + ":" +
String.valueOf(mins) + ":" +
String.valueOf(secs),50,50);
}
}
Another important aspect in this applet is how the time is calculated. In the package java.util is the class Calendar. In order to get the current time,
we make a new instance of a calendar object by using the method getInstance. When the method getInstance is called we have available to use the time of
the system at the time the call was made. In order to access the time, we use the get method. Get accepts as a parameter an integer indicating what field
we would like. There are several static constants we can make use of in the Calendar class, in particular HOUR, MINUTE, SECOND, and HOUR_OF_DAY.
HOUR_OF_DAY will return the hour in 24-hour format, i.e. 5 pm will give an HOUR_OF_DAY of 17.
Each time we wish to make a time calculation we must make another call to getInstance.
Let us look at a slightly more complicated example of an applet.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Walker extends Applet implements Runnable,ActionListener,ItemListener {
int scale=1;
Panel drawingArea = new Panel(null);
Thread appletThread;
Button north;
Button west;
Button south;
Button east;
Panel messageArea = new Panel(null);
TextField message = new TextField();
String direction="South";
int x = 250;
int y = 0;
Choice speedChoice = new Choice();
int speed = 5;
TextField directionArea;
public class MyException extends Exception {
public String message;
public MyException(String s) {
super(s);
message = s;
}
}
public Walker() {
setLayout(null);
drawingArea.setSize(500,200);
drawingArea.setLocation(0,0);
Panel controlPanel = new Panel(new FlowLayout());
Font font = new Font("Sanserif",Font.BOLD,12);
Label directionLabel = new Label("Direction ");
directionLabel.setFont(font);
directionArea = new TextField("South",10);
controlPanel.add(directionLabel);
controlPanel.add(directionArea);
north = new Button("North");
west = new Button("West");
south = new Button("South");
east = new Button("East");
controlPanel.add(north);
controlPanel.add(west);
controlPanel.add(south);
controlPanel.add(east);
Label speedLabel = new Label(" Speed ");
speedLabel.setFont(font);
speedChoice.add("5");
speedChoice.add("10");
speedChoice.add("15");
speedChoice.add("20");
speedChoice.add("25");
speedChoice.add("30");
speedChoice.add("35");
speedChoice.add("40");
speedChoice.add("45");
speedChoice.add("50");
speedChoice.addItemListener(this);
controlPanel.add(speedLabel);
controlPanel.add(speedChoice);
north.addActionListener(this);
west.addActionListener(this);
south.addActionListener(this);
east.addActionListener(this);
controlPanel.setSize(500,50);
controlPanel.setLocation(0,200);
message.setSize(490,30);
message.setLocation(5,10);
messageArea.add(message);
messageArea.setSize(500,50);
messageArea.setLocation(0,250);
add(drawingArea);
add(controlPanel);
add(messageArea);
}
public void init() {
setBackground(Color.white);
if (appletThread == null) {
appletThread = new Thread(this);
appletThread.start();
}
}
public void run() {
Graphics g = drawingArea.getGraphics();
while (true) {
if (direction.equals("South")) {
try {
y+=speed;
if ((y+40*scale)>=195) {
y-=speed;
throw new MyException("You can't go any farther South. Please choose another direction.");
}
} catch (MyException exc) {
System.out.println("Hello");
message.setText(exc.message);
}
drawFigure(g,Color.white,x,y-speed);
drawFigure(g,Color.black,x,y);
}
if (direction.equals("West")) {
try {
x-=speed;
if ((x-20*scale)<=5) {
x+=speed;
throw new MyException("You can't go any farther West. Please choose another direction.");
}
} catch (MyException exc) {
message.setText(exc.message);
}
drawFigure(g,Color.white,x+speed,y);
drawFigure(g,Color.black,x,y);
}
if (direction.equals("North")) {
try {
y-=speed;
if (y<=5) {
y+=speed;
throw new MyException("You can't go any farther North. Please choose another direction.");
}
} catch (MyException exc) {
message.setText(exc.message);
}
drawFigure(g,Color.white,x,y+speed);
drawFigure(g,Color.black,x,y);
}
if (direction.equals("East")) {
try {
x+=speed;
if ((x+20*scale)>=495) {
x-=speed;
throw new MyException("You can't go any farther East. Please choose another direction.");
}
} catch (MyException exc) {
message.setText(exc.message);
}
drawFigure(g,Color.white,x-speed,y);
drawFigure(g,Color.black,x,y);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
public void paint(Graphics g) {
}
public void drawFigure(Graphics g,Color c,int x,int y) {
g.setColor(c);
g.fillRect(x-10*scale,y,20*scale,10*scale);
g.fillRect(x-scale,y+10*scale,2*scale,10*scale);
g.fillRect(x-20*scale,y+20*scale,40*scale,2*scale);
g.fillRect(x-20*scale,y+22*scale,2*scale,8*scale);
g.fillRect(x+18*scale,y+22*scale,2*scale,8*scale);
g.fillRect(x-16*scale,y+22*scale,32*scale,18*scale);
g.fillRect(x-16*scale,y+40*scale,2*scale,10*scale);
g.fillRect(x+14*scale,y+40*scale,2*scale,10*scale);
}
public void actionPerformed(ActionEvent e) {
direction = e.getActionCommand();
directionArea.setText(direction);
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
speed = (Integer.valueOf((e.getItem().toString()))).intValue();
System.out.println(speed);
}
}
}
Make note of how the exceptions are handled.
Notes about the program.
There are several things you must do in your programming assignment.
- Create two button objects and respond to button clicks.
- Create three checkbox objects and respond to checks.
- Draw a figure on the screen.
- Decide how long the figure will remain on the screen.
- Decide whether or not there is a hit.
- Create textbox components and place various text in them based on activities in the game.
- Create a timer.
- Implement Exception Handling.
In order to generate random numbers, we use the static method random in the Math class. The return type of random is a double. It returns a random value
between 0 and 1.
In order to accomplish drawing, we have several methods available in the Graphics class.
public abstract void clearRect(int x,int y,int width,int height)
public abstract void drawLine(int xl,int yl,int x2,int y2)
public abstract void drawOval(int x,int y,int width,int length)
public void drawRect(int x,int y,int width,int height)
public abstract void drawString(String str,int x,int y)
public abstract void fillOval(int x,int y,int width,int height)
public abstract void fillRect(int x,int y,int width,int height)
public abstract void setColor(Color c)
public abstract void setFont(Font font)
public String toString()
You are free to draw the figure in any shape you want. An important question is how do you determine whether or not the figure has been hit. One way of
answering the question is to assume that the gun is at the middle of the lower part of the applet in a fixed location. When you draw the figure, you must
also randomly generated the amount of time that the figure will remain on the screen.
The criteria for the figure being hit are:
- The gun is aimed in the direction of the figure.
- The bullet has time to get to the figure.
In order to determine whether or not the gun is aimed in the direction of the figure, you may make use of methods from the Math class, in particular the
arcsin method.