More on loops. Difference between "headers" and "trailers". Looping applets and the Surprise balloon examples. Slowing things down with the Thread.sleep() method. (6.7)
Loop control is used for many reasons. On of those reasons is to index through arrays.
There are three major loop control structures in java
The behavior of these control structures is modified by the following statements
The break statement causes an immediate termination of the enclosing while, do or for statement (or of an enclosing switch statement). Control passes out only one level, so that if the break statement is within a nested statement for which it is also effective, further action may be needed to return control to the desired level.
The continue statement causes an immediate termination of the current pass through the enclosing while, do or for statement. Control passes to the logic that determines if another pass should be made, and is only effective for the immediately enclosing level, so that if the continue statement is within a nested statement for which it is also effective, further action may be needed to return control to the desired level.
Execution of a loop within a method/constructor body may also be terminated by a return statement.
The while statement evaluates the expression. If the result is non-zero, the associated statement is executed and then the process is repeated. Exection continues to loop until the expression evalutes to zero.
The do while statement is similar in effect, except the associated statement is executed at least once.
The for statement is typically used to control iteration with some variable that is being stepped through a range of values, e.g. for ( i = 0; i < limit; i++) statement will be executed for values of I equal to 0, 1, limit-1.
Such control constructs are often used for arrays.
Arrays are a means of giving multiple objects a single name. Individual objects are
identified by combining the name of the array one or more numeric indices. If there
is one index, it indicates which item in a single row of array elements is desired.
If there are two indices, they indicate by row and column which element is desired. More
indices are allowed.
Arrays are declared in java as follows:
Array variable declarations:
Assigning array objects to previously declared array variables:
Declaring an array and assigning simulataneously
The declaration of an array variable allocates the storage to hold a reference to an array, not the array itself. The use of new with explicit array dimensions allocates the necessary storage for the indicated number of copies of objects of the indicated type and declares the indicated variable to be a reference to the first element of the array. In actual use, the indices run from 0 through one less than the indicated dimension.
The variable declared as the array name is a reference to the first element of the array (the one with all indices equal to zero), and array indexing is done by adding the value implied by the indices to the memory location implied by the reference.
In this lecture we will do some looping in applets. First we will need to set up to do some drawing.
We created a program to place circles at random on our applet. Each time we press the circle button, the circle moves to a new (randomly chosen) location.
//File: Circles.java
//The following packages are necessary for any applet
import java.applet.*;
import java.awt.*;
//The following package is necessary if we are to have
//an interactive applet, one that responds to events
import java.awt.event.*;
public class Circles extends Applet implements
ActionListener
{
Button circleButton = new Button("New
Circle");
public void init()
{
//add the applet components here
add (circleButton);
circleButton.addActionListener(this);
}
//The paint() method is called by the browser
//whenever the applet must be redrawn
public void paint (Graphics g)
{
Dimension d=getSize();
int w=d.width;
int h=d.height;
int x,y,radius;
radius=25;
x = (int) (w * Math.random());
y = (int) (h * Math.random());
g.setColor (Color.red);
g.fillOval(x-radius, y-radius, 2*radius,
2*radius);
}
//The actionPerformed() method from the ActionListener
// interface must be implemented
public void actionPerformed (ActionEvent event)
{
//Here is where the ActionListener components
respond to events
repaint(); //calls update()
which clears the window,
//then calls paint()
}
}
Each time I press the "new Circle" button, the circle reappears in a new location. In fact, you should play with this a little bit. That is, try minimizing and then maximizing the applet. You'll see that anytime the applet has to be redrawn, the web browser (Netscape in my case) has to call the repaint() method itself, which results in another random move of the circle.
Now suppose we want each press of the button to place another circle at random on the applet, but LEAVE THE PREVIOUSLY GENERATED CIRCLES IN PLACE. This requires that we expose the Wizard of Oz behind the scenes. When your applet (or the browser) for that matter invokes repaint(), it actually invokes a method called update() which clears the applet and then calls paint(). Our challenge is to override this default behavior. We can accomplish this by adding our own version of update() to the applet, one that does NOT clear the applet before calling paint(). It will look as follows:
//Overrides the default update() method
public void update (Graphics g)
{
//Our version of update doesn't clear the
window
//before calling paint()
paint(g);
}
Adding this to our previous Circles.java program gives the following output:
and so forth. Each time we press the "new Circle" button, another circle appears. By the way, if you resize the applet, you'll see that the applet is cleared. This is not surprising since the browser makes a call on the default version of update(), not the one in our program. (Download: Circles2.java)
Lab Exercise 1. Rewrite Circles2.java so that the circles change color randomly each time the "new Circle" button is pushed.
The following applet can be found in your textbook. It draws a sequence of expanding circles that end with the word Surprise.
//File: Surprise0.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Surprise0 extends Applet
{
// Surprise with an exploding balloon
// Author: Rachel McDermott, September 27, 1996
public void paint (Graphics g)
{
Dimension size = getSize();
int
diameter = 0,
w = size.width,
h = size.height,
cmin = (int)Math.min(w, h);
g.setColor(Color.yellow);
while (diameter < cmin)
{
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
diameter++;
}
Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws =
metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();
g.setColor(Color.red);
g.drawString("Surprise!", (w-ws)/2,
(h+hf)/2);
}
}
The above version creates the circles so rapidly that you don't get the full experience of an expanding balloon. Clearly, we need to slow this thing down. That's where the Thread.sleep() method comes in.
//File: Surprise.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Surprise extends Applet
{
// Surprise with an exploding balloon
// Author: Rachel McDermott, September 27, 1996
public void paint (Graphics g)
{
Dimension size = getSize();
int
diameter = 0,
w = size.width,
h = size.height,
cmin = (int)Math.min(w, h);
g.setColor(Color.yellow);
while (diameter < cmin)
{
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
diameter++;
try
{
Thread.sleep(10); // sleep for 10 msec
}
catch
(InterruptedException t)
{
}
}
Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws =
metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();
g.setColor(Color.red);
g.drawString("Surprise!", (w-ws)/2,
(h+hf)/2);
}
}
We still have an expanding balloon that ENDS with the word balloon. If you'd like the balloon to repeat its cycle indefinitely, then we need to introduce an infinite loop. This is accomplished by reducing the paint() method to an infinite loop that repeats another method which we call animate().
//File: UnpleasantSurprise.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class UnpleasantSurprise extends Applet
{
// Surprise with an exploding balloon
// Author: Rachel McDermott, September 27, 1996
public void paint (Graphics g)
{
while (true)
{
animate (g);
}
}
public void animate (Graphics g)
{
Dimension size = getSize();
int
diameter = 0,
w = size.width,
h = size.height,
cmin = (int)Math.min(w,
h);
g.setColor(Color.yellow);
while (diameter < cmin)
{
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
diameter++;
try
{
Thread.sleep(10); // sleep for 10 msec
}
catch
(InterruptedException t)
{
}
}
Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws =
metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();
g.setColor(Color.red);
g.drawString("Surprise!", (w-ws)/2,
(h+hf)/2);
}
}
Unfortunately, this version doesn't give us the effect we desire. The balloons expand, the word Surprise appears, disappears, reappears, etc. The repetition of an expanding balloon is not achieved. The reason is that the applet is not redrawn. Once the large circle is drawn, it cannot be "undrawn". But remember, this is similar to the problem we had with the random balloons. In that case, each time a random balloon appeared, the last one was erased. It was the repaint() method that accomplished that, and that is exactly what we need here.
//File: Surprise2.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Surprise2 extends Applet
{
// Surprise with an exploding balloon
// Author: Rachel McDermott, September 27, 1996
public void paint (Graphics g)
{
Dimension size = getSize();
int
diameter = 0,
w = size.width,
h = size.height,
cmin = (int)Math.min(w, h);
g.setColor(Color.yellow);
while (diameter < cmin)
{
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
diameter++;
try
{
Thread.sleep(10); // sleep for 10 msec
}
catch
(InterruptedException t)
{
}
}
Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws =
metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();
g.setColor(Color.red);
g.drawString("Surprise!", (w-ws)/2,
(h+hf)/2);
try
{
Thread.sleep(1000); //
sleep for 1 sec
}
catch (InterruptedException t)
{
}
repaint(); //calls
update() which CLEARS THE WINDOW,
//then calls paint()
}
}
At last, we achieve the desired effect.
Lab Exercise 2. Change the animations in Surprise2.java so that the circle grows larger and then grows smaller and disappears. Spend some time on this one. If you want to see Bill Steinmetz's solution, take a look at
Lab Exercise 3. Change the animations in Surprise3.java so that as the circle grows larger and then grows smaller and disappears, a label is applied which says "Small", "Medium", "Large", "XL", "XXL", as appropriate. Hint: it can help to use an array. Spend some time on this one. If you want to see my solution, take a look at
Adapted from Bill Steinmetz's course summary by H. J. Bernstein, 8 Nov 01