CSC 012
Introduction to Computer Science
Summary of 11/13 Lecture
Review of 11-8 Lab Results; more on drawing;
introduction to arrays or lists; subscripts or
indexes; the NumberList class; (7.1, 7.2)
Review of 11-8 Lab Results
We had three lab exercises on 11-8:
11-8 Lab Exercise 1. Rewrite Circles2.java
so that the circles change color randomly each time the "new Circle" button is
pushed.
11-8 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.
11-8 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.
The key to doing exercise 1 is to combine the random number generator with a call to Color
with random arguments in the range of 0-255,
or to use a random selection from an array of colors. Let us look at the second option.
The standard colors we can use in java are:
black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, red, white and
yellow
for 13 colors in all. However, with a white background, a white circle would vanish, so
we only use 12.
//File: Circles3.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 Circles3 extends Applet implements ActionListener
{
Button circleButton = new Button("New Circle");
public void init()
{
//add the applet components here
add (circleButton);
circleButton.addActionListener(this);
setBackground (Color.white);
}
//The paint() method is called by the browser
// whenever the applet must be redrawn
public void paint (Graphics g)
{
// Add an array for random colors
Color [] myColors =
{ Color.black, Color.blue, Color.cyan,
Color.darkGray, Color.gray, Color.green,
Color.lightGray, Color.magenta, Color.orange,
Color.pink, Color.red, Color.yellow };
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());
// Set the color to one of the random colors
g.setColor (myColors[((int)(12*Math.random()))%12]);
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()
}
public void update (Graphics g)
{
//Our update doesn't clear the window first
paint(g);
}
}
The answers to the other two exercises build on each other. We will only examine the
combined answer:
//File: Surprise4.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Surprise4 extends Applet
{
//Exploding and imploding balloons
//With Small, Medium, Large, .. added
public void init()
{
setBackground (Color.white);
}
public void paint (Graphics g)
{
// Added array of size_labels
String [] size_labels = {
" Small ", "Medium", "Large", "XL", "XXL" };
// Note the extra blanks on Small
Dimension size = getSize();
int size_bin; // Added index for size_labels
int diameter = 0,
w = size.width,
h = size.height,
cmin = (int)Math.min(w, h);
// g.setColor(Color.yellow); // was here
while (diameter < cmin)
{
int ws, hf; // needed to position labels
Font current; // note the different style
FontMetrics metrics; // when we do this later
g.setColor(Color.yellow); //now here
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
// Note it is important to do this
size_bin = (5*diameter)/cmin;
// Before this
diameter++;
// Added code for the size labels
current = getFont();
metrics = getFontMetrics (current);
ws = metrics.stringWidth(size_labels[size_bin]);
hf = metrics.getHeight();
g.setColor(Color.blue);
g.drawString(size_labels[size_bin],
(w-ws)/2, (h+hf)/2);
try
{
Thread.sleep(10); // sleep for 10 msec
}
catch (InterruptedException t)
{
}
}
g.setColor(Color.yellow); //need to draw oval again
//to overwrite old labels
g.fillOval((w-diameter)/2, (h-diameter)/2,
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);
try
{
Thread.sleep(1000); // sleep for 1 sec
}
catch (InterruptedException t)
{
}
while (diameter > 1)
{
//The following draws circles in yellow,
//pauses, then redraws them in white (the background color),
//thus effectively erasing them. It then changes the color
//back to yellow and repeats the process for a circle
//of diameter one less than the previous one.
//Note that we have to rewrite the labels in white
//or medium will show behind small
// int ws, hf; // already declared above
// Font current;
// FontMetrics metrics;
g.setColor(Color.yellow);
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
// Note the -1
size_bin = (5*(diameter-1))/cmin;
// Added code for the size labels again
current = getFont();
metrics = getFontMetrics (current);
ws = metrics.stringWidth(size_labels[size_bin]);
hf = metrics.getHeight();
g.setColor(Color.blue);
g.drawString(size_labels[size_bin],
(w-ws)/2, (h+hf)/2);
try
{
Thread.sleep(10); // sleep for 10 msec
}
catch (InterruptedException t)
{
}
g.setColor (Color.white);
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
g.drawString(size_labels[size_bin],
(w-ws)/2, (h+hf)/2);
diameter--;
}
repaint(); //calls update() which CLEARS THE WINDOW,
//then calls paint()
}
}
More on Drawing
Java has solid basic drawing capabilities defined in the Graphics class. Let us look at an
applet to draw a crude expanding head instead of a balloon to understand some of the
graphics methods and see two problems: image flicker caused by partial updates and
the non-intuitive coordinate system used.
//File: Head.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Head extends Applet {
//Surprise with an exploding balloon
// Author: rachel McDermott, September 27, 1996
//Modified to be a head
// H. J. Bernstein, 11 November 2001
public void init() {
setBackground (Color.white);
}
public void paint (Graphics g) {
Dimension size = getSize();
int diameter = 0,
cx = size.width,
cy = size.height,
cmin = (int)(.8*Math.min(cx, cy));
// note: we adjust the size of the
// head to leave room for the ears
while (diameter < cmin) {
// Draw hair
g.setColor(Color.red);
g.fillOval(cx/2-diameter/6,(cy+diameter)/2-diameter/6,
diameter/3, diameter/3);
// Draw the head itself
g.setColor(Color.yellow);
g.fillOval((cx-diameter)/2, (cy-diameter)/2,
diameter, diameter);
// Draw two ears
g.fillOval((cx-diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);
g.fillOval((cx+diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);
// Draw brow line and smile
g.setColor(Color.blue);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, 50, 80);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, -50, -80);
// Now draw two eyes
g.setColor(Color.blue);
g.drawOval((cx-3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx-3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
g.drawOval((cx+3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx+3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
diameter++;
try {
Thread.sleep(20); // sleep for 20 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!", (cx-ws)/2, (cy+hf)/2);
try {
Thread.sleep(1000); // sleep or 1 sec
} catch (InterruptedException t) {}
repaint();
}
}
The hair has been drawn as a beard. That is because java uses a default coordinate system which
is upside-down compared to the one commonly used in when laying out drawings by hand or drawing
graphics in a physics class. The point with the coordinates (0,0) is at the top left and increasing
y-coordinates go down the screen. This arises from the natural conflict between laying out
images, for which it is common to place (0,0) at the bottom left corner, and laying out text, in which
the first character of the first line is normally placed at the top left. Unless we introduce
special transformations, when writing java, we have to use the text-oriented convention.
On most computers, the applet will show a disturbing flicker of partially drawn images. In the
next applet, we cure the inverted image by changing a + to a -, and we cure the flicker by drawing
using a Graphics object in memory and then transferring
all the pixels at once to the displayed Graphics object:
//File: BufferedHead.java
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.applet.*;
public class BufferedHead extends Applet {
//Surprise with an exploding balloon
// Author: rachel McDermott, September 27, 1996
//Modified to be a head
//Modified to use an off-screen buffer
// H. J. Bernstein, 11 November 2001
public void init() {
setBackground(Color.white);
}
public void paint (Graphics g_real) {
Image image_g;
Graphics g;
Dimension size = getSize();
int diameter = 0,
cx = size.width,
cy = size.height,
cmin = (int)(.8*Math.min(cx, cy));
// note: we adjust the size of the
// head to leave room for the ears
image_g = createImage(cx,cy);
g = image_g.getGraphics();
while (diameter < cmin) {
// Draw hair
g.setColor(Color.red);
g.fillOval(cx/2-diameter/6,(cy-diameter)/2-diameter/6,
diameter/3, diameter/3);
// Draw the head itself
g.setColor(Color.yellow);
g.fillOval((cx-diameter)/2, (cy-diameter)/2,
diameter, diameter);
// Draw two ears
g.fillOval((cx-diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);
g.fillOval((cx+diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);
// Draw brow line and smile
g.setColor(Color.blue);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, 50, 80);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, -50, -80);
// Now draw two eyes
g.setColor(Color.blue);
g.drawOval((cx-3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx-3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
g.drawOval((cx+3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx+3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
g_real.drawImage(image_g,0,0,this);
diameter++;
try {
Thread.sleep(20); // sleep for 20 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!", (cx-ws)/2, (cy+hf)/2);
g_real.drawImage(image_g,0,0,this);
try {
Thread.sleep(1000); // sleep or 1 sec
} catch (InterruptedException t) {}
repaint();
}
}
Arrays
We began with a motivational example. Suppose you want to calculate
the average of a list of numbers (int or double) followed by a calculation of the standard
deviation. You quickly realize that by the time you're ready to do the standard
deviation, you only have access to the last number in the list. The solution is
provided by arrays since they allow you to name a collection of memory locations with one
identifier. Subscripts or indexes then allow you to access each individual memory
location. The following example illustrates this.
//File: NumberList.java
//This class will gather together in one place
//functions (or methods) which process lists of
//numbers (int or double).
import iostuff.*;
public class NumberList
{
//The following two methods calculate the average of a list
//of int's or double's respectively
public static int average (int [] a)
{
int sum=0;
for (int k=0;
k<a.length; k++)
{
sum = sum + a [k];
}
return sum/a.length;
}
public static double average (double
[] a)
{
double sum=0;
for (int k=0;
k<a.length; k++)
{
sum = sum + a [k];
}
return sum/a.length;
}
}
//File: Average.java
import NumberList;
import iostuff.*;
import java.text.DecimalFormat;
public class Average
{
public static void main (String [] args)
{
double number [];
System.out.print ("How many numbers?
");
int n = Keyboard.readInt();
number = new double [n];
//inputs the numbers into the array
for (int k=0; k<n;
k++)
{
System.out.print("Next score please: ");
number [k]=
Keyboard.readInt();
}
//The following code displays
the list to the screen
for (int k=0;
k<number.length; k++)
{
System.out.println
(number[k]);
}
System.out.println();
double avg =
NumberList.average(number);
DecimalFormat output = new
DecimalFormat("0.00");
System.out.println ("The average is:
" + output.format(avg));
}
}
Note that arrays "know" their length. That is, it is not
necessary to pass the number of items as a parameter to any of the methods in NumberList.
Instead, when that information is required, the length of the array is retrieved
from the array itself; e.g., a.length or number.length.
Lab Exercise 1. Add a method that displays a list of int's to the
NumberList class. The signature for the method will look like:
public static void display (int [] a)
HINT: This method should incorporate the section of Average.java (above) that
"displays the list to the screen".
Lab Exercise 2. Add a method that calculates the standard
deviation of a list of int's to the NumberList class. The signature for the method
will look like:
public static int sd (int [] a, int
average)
Feel free to consult Prof. Steinmetz's version if you get
exasperated.
Adapted from Bill Steinmetz's course summary by H. J. Bernstein, 12 Nov 01
Back to CSC 012 Home Page