CS 4773 Object Oriented Systems
The Java Language (continued)
A Ping Pong Applet
- The PingPong class will have to write to the window rather
than to standard output.
- It will do this by calling a print method in the applet.
- We create a class PrintApp abstract class which extends
Applet to do this.
The file PrintApp.java
package threadtests;
import java.awt.*;
import java.applet.*;
public abstract class PrintApp extends Applet {
protected abstract void write_string(String str);
public synchronized void printit(String str) {
write_string(str);
}
}
The file PingPongA.java is a modification of PingPong.java
which sends output to an applet.
package threadtests;
public class PingPongA extends Thread {
String word; // what word to print
int delay; // how long to pause
int count; // number of iterations
PrintApp caller;
PingPongA(PrintApp caller, String What, int Time, int number) {
word = What;
delay = Time;
count = number;
this.caller = caller;
setName(What);
}
public void run() {
try {
for(int i=0;i < count;i++) {
caller.printit(i+": "+word);
sleep(delay); // wait until next time
}
} catch (InterruptedException e) {
return; // end this thread
}
}
}
Here is the actual applet.
We do not use join because you are not allowed to suspend
the applet itself.
/*
< applet code="threadtests.test3a" width=600 height = 400 >
< /applet >
*/
package threadtests;
import java.awt.*;
import java.applet.*;
public class test3a extends PrintApp {
Graphics tempGC;
Graphics foreGC;
Image tempimage;
Image foreground;
int sizex;
int sizey;
int strnum;
public void paint(Graphics g) {
g.drawImage(foreground,0,0,this);
}
public void update(Graphics g) {
paint(g);
}
public void init() {
Thread current;
sizex = bounds().width;
sizey = bounds().height;
foreground = createImage(sizex,sizey);
tempimage = createImage(sizex,sizey);
foreGC = foreground.getGraphics();
tempGC = tempimage.getGraphics();
strnum = 0;
foreGC.setColor(Color.red);
current = Thread.currentThread();
current.setName("test3a-main");
show_threads("init");
}
private int pos_x(int num) {
return (num/20);
}
private int pos_y(int num) {
return (num%20);
}
protected void write_string(String str) {
foreGC.drawString(str,300*pos_x(strnum)+10,15*pos_y(strnum)+15);
strnum++;
repaint(1);
}
public void start() {
repaint(1);
start_ping_pong();
}
public void show_threads(String msg) {
String str;
Thread[] tlist = new Thread[50];
int count;
count = Thread.enumerate(tlist);
str = msg + ": Th:("+count+"):";
for (int I=0;i < count;i++)
str = str + " " + tlist[i].getName() + ",";
printit(str);
}
private void start_ping_pong(){
PingPongA ping;
PingPongA pong;
show_threads("Start of main");
ping = new PingPongA(this,"ping", 1000, 20);
show_threads("ping created");
pong = new PingPongA(this,"PONG", 3000, 10);
show_threads("pong created");
ping.start();
pong.start();
show_threads("started");
}
}
Click Here to run this applet.
An Animation Example
The file Animation.java:
package animations;
import java.awt.*;
import java.applet.*;
abstract class Animation {
protected Applet app;
protected void init (Applet app) {
this.app = app;
}
public abstract void advance ();
public abstract void paintFrame(Graphics g,
Graphics g1, Image im1, Image im2);
}
An Abstract class is one in which not all of the methods are implemented.
A class which extends an abstract class must override all of these
unimplemented methods.
- When initialized it stores the calling applet in app
- advance does the next step of the animation.
- paintFrame is called by paint to draw the
images from one time step.
- g is the graphics context passed to paint.
- im1 is a temporary image for writing into.
- g1 is a graphics context for im1.
- im2 is a background image.
Rectangle Animation
The file RectangleAnimation.java
package animations;
import java.awt.*;
import java.applet.*;
class RectangleAnimation extends Animation {
private int cx = 0;
private int cy = 0;
public void advance () {
cx = cx + 1;
cy = cy + 1;
}
public void paintFrame(Graphics dispGC, Graphics bufGC,
Image bufImage, Image backImage) {
bufGC.drawImage(backImage,0,0,app);
bufGC.fillRect(cx,cy,50,20);
dispGC.drawImage(bufImage,0,0,app);
}
}
- (cx,cy) is the top left corner of the rectangle to draw.
- advance sets the next rectangle to be offset by one pixel.
- paintFrame draws the new rectangle on the screen.
- dispGC is the graphics context passed from paint.
- backImage is the background image.
- bufGC is used for drawing into bufImage.
- First, the background is copied into bufImage.
- Next, the rectangle is drawn in bufImage.
- Finally, bufImage is copied onto the screen.
The Applet
The file AnimationApplet.java
/* < Applet code = "animations.AnimationApplet"
width = 200 height = 200 >
< PARAM NAME = SLEEPTIME VALUE = 50 >
< /applet > */
package animations;
import java.awt.*;
import java.awt.*;
import java.applet.*;
public class AnimationApplet extends Applet
implements Runnable {
int sleep_time;
Thread mythread;
Animation animation;
Graphics bufferGC;
Graphics backGC;
Image bufferimage;
Image backgroundimage;
public void init() {
set_layout();
sleep_time =
Integer.parseInt(getParameter("SLEEPTIME"));
backgroundimage =
createImage(bounds().width,bounds().height);
backGC = backgroundimage.getGraphics();
backGC.setColor(Color.blue);
backGC.drawString("This is the background ("+
sleep_time+")",5,50);
bufferimage =
createImage(bounds().width,bounds().height);
bufferGC = bufferimage.getGraphics();
bufferGC.setColor(Color.red);
}
private void set_layout() {
setLayout(new BorderLayout());
add("South", new Button("Start"));
}
public void start() {
if (mythread == null)
return;
if (mythread.isAlive())
mythread.resume();
else
mythread.start();
}
public void stop() {
if (mythread == null) return;
mythread.suspend();
}
void slow_it_down(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {}
}
public void run() {
for (int i=0; i<100;i++) {
repaint(1);
slow_it_down(sleep_time);
animation.advance();
}
}
public void update (Graphics g) {
paint(g);
}
public void paint (Graphics g) {
if (animation == null) return;
animation.paintFrame(g, bufferGC,
bufferimage, backgroundimage);
}
public boolean action(Event e, Object arg) {
if ("Start".equals(arg)) {
showStatus("Start button pushed");
animation = new RectangleAnimation();
animation.init(this);
mythread = new Thread(this);
mythread.start();
repaint(1);
return true;
}
return super.action(e,arg);
}
}
About AnimationApplet.java:
- The sleep_time is the time between animation steps.
It is gotten from the HTML file.
- Some images and graphics contexts are set up.
- start is called both when the applet it started and when the
browser revisits the page.
- stop is called when the browser leaves the page.
- mythread may be null when start or
stop are called.
- slow_it_down just sleeps for a number of milliseconds.
- new Thread(this) creates a new thread which uses the
applet's runmethod.
- run does one step of the animation every sleep_time
milliseconds.
- repaint(1) requests that the screen be repainted as soon as
possible.
- animation_advance just sets the coordinates of the next rectangle.
- update is there so that the background will not be repainted
first.
- paint just calls the paint routine from aniamtion of the RectangleAnimation class.
Click Here to run this applet.
More About Threads
Why a thread is needed for animation:
- The animation routine needs to sleep after each step.
- If you suspend the applet, it cannot update the screen
Thread groups:
- Threads are split into groups for security reasons.
- Thread groups are organized in a tree structure.
- Threads can modify other threads in its group or those in groups below it.
Threads of the animation example:
- There is a main group containing 4 threads:
- a main thread
- an input thread
- a Motif thread
- a Screen Updater thread
- A group called applet-animations.AnimationApplet
- the original thread
- the thread to do the animation
A Function that lists threads
public void show_threads(String msg) {
Thread current;
Thread[] tlist = new Thread[50];
int count;
current = Thread.currentThread();
count = Thread.enumerate(tlist);
System.out.println("\n"+msg+" :Current thread: "+
current+" total:"+count);
for (int i=0;i
Thread Scheduling
- Threads have priorities between MIN_PRIORITY and
MAX_PRIORITY.
- Scheduling is pre-emptive.
- The scheduling algorithm has not been fully specified.
- If there is more than one thread of the highest priority:
- one may starve out the other unless it yields
- they might be scheduled round-robin
- it depends on the implementation
- If two threads have different priorities:
- the higher priority thread might starve the lower one
- the lower one might get a small fraction of the running time
- it depends on the implementation
Creating an Animation Library
- Generalize the previous example
- Move an arbitrary object along a path
- The size and color should be able to change along the path
- Move more than one object at a time
- Synchronize the movements of several objects