CSCI A201/A597

Lecture Notes 17

Spring 2000


Developing a graphical application with mouse input: design and implementation.

Hoping that you already looked at lab notes 8 and chapter 2 in your textbook we will develop a graphical application with mouse input. We start by running a demo of the application, in class, thus making the desired functionality explicit. Then we describe in detail its design. Without careful design we have little chance of success. Then we look at the implementation aspects.

Here is the final product, the program that we we will develop today in lecture, so that you can run it and see it running.

import element.*; 
import java.util.Random; 
import java.awt.Color; 

class Mar06 {
    public static void main(String[] args) {
	DrawingWindow d = new DrawingWindow(); 
        Pt mouseClick; 
        Rect target; 
        int x0 = 10, y0 = 10, x1 = 190, y1 = 190, size = 10; 
        Rect border = new Rect(x0, y0, x1 - x0, y1 - y0); 
        d.draw(border); 
        boolean playGame,targetAlive; 
	Random gen = new Random(); 
	long start, stop; 
        int rounds = 0; 
        double time = 0.0; 

        mouseClick = d.awaitMouseClick();

        playGame = true; 
	while (playGame) { 

	    int xValue = gen.nextInt();
	    xValue = Math.abs(xValue);
	    xValue = x0 + xValue % (x1 - size - x0);

	    int yValue = gen.nextInt();
	    yValue = Math.abs(yValue);
	    yValue = y0 + yValue % (y1 - size - y0);

	    target = new Rect(xValue, yValue, size, size);

	    d.draw(target); d.setForeground(Color.blue);
	    d.fill(target);
	    start = System.currentTimeMillis();

	    targetAlive = true; 
            while (targetAlive) {
		mouseClick = d.awaitMouseClick(); 
		if (target.contains(mouseClick)) {
		    targetAlive = false; 
                    stop = System.currentTimeMillis(); 
                    rounds += 1; 
                    time += (stop - start); 
		    System.out.println("Round " + rounds + 
				       " time: " + (stop - start)); 
		} 
	    } 
            if (rounds > 10) {
		playGame = false; 
            } else {
		d.clear(d.bounds()); 
		d.setForeground(Color.black); 
		d.draw(border); 
		long now = System.currentTimeMillis(); 

    	        int number = gen.nextInt();
	        number = Math.abs(number);
	        int seconds = 1 + number % 3; 

		long then = now + seconds * 1000; 

		while (System.currentTimeMillis() < then) {

		} 

	    } 
	}        
        System.out.println("The game is over."); 
        System.out.println("Total time: " + time + " milliseconds."); 
        System.out.println("Your average: " + time / 10 + " millis."); 
        System.exit(0); 
    } 
}
Here's the diagram that describes its functionality:

The first question that we need to ask in terms of its implementation is whether we have the right language structures to implement it.

Here's the template for a loop in Java and its diagrammatic equivalent on its right:
while (cond) {
  body 
} 
With this in mind we can change the first diagram to include a more explicit loop mechanism (or implementation) for the two cyclic aspects of the diagram (loops are restarted at points indicated by D and E).

To check a condition that should tell us if we should keep generating rectangles and a condition that should tell us whether the current target has been hit or not we introduce two boolean variables:

playGame
and
targetAlive
with which we can stop (or continue) the game and mark the moment when the target was hit.

So here's the new diagram:

Now we need to look at the specifics.

1. Working with a drawing window.

Essentially you obtain one this way:
DrawingWindow d = new DrawingWindow();
You need to import the element package.

import element.*;
Appendix E page 308 is useful. We need to be able to read it.

2. Waiting for mouse input.
Any drawing window can be told to wait for mouse input. You need to ask your window to wait for mouse input. We choose to ask our drawing window to wait for a click of the mouse (that is, for a press and release of the mouse).

Pt mouseClick = d.awaitMouseClick();
The program blocks (does nothing) until mouse is pressed and then released in the window that waits for this event to happen. When this happens the program is resumed and the coordinates of the position where the mouse button was released are returned together as a Pt object.

Appendix E page 312 has all about Pt's and of course chapter 2.

3. Working with rectangles.
Appendix E page 316 describes the Rect class. There's more than one way to create a rectangle, and here we create it by specifying the location of its top left corner, together with its width and its height.

Rect border = new Rect(x0, y0, (x1 - x0), (y1 - y0));
Here x0, y0, x1, y1, are the coordinates of the area where we draw in our window.

Rectangles can tell whether a certain Pt is inside them or not.

target.contains(mouseClick)
evaluates to true or false depending on the actual position of
Pt mouseClick;
inside the rectangle target (of type Rect).

To clear the whole drawing window we can invoke

Rect window = d.bounds()
to obtain a Rect as large as the window itself.

Then we can call clear on that:

d.clear(window)
which can also be done in one step:
d.clear(d.bounds());
as page 51 mentions as well.

4. Working with random numbers.
You need to import a class from the util package:
import java.util.Random;
Page 30 in the first chapter has more about what we do here. Here is, for example, how we obtain a random integer between
x0
and
x1 - size
where size is the width of the target (10 pixels).

Random gen = new Random(); 
int x = gen.nextInt(); 
x = Math.abs(x); 
x = x % (x1 - size - x0) + x0; 
Taking the remainder with the width of the window makes sure that the relative distance from the left margin of the window will be random but not larger than the width. Adding the coordinate of the letf margin will position the point appropriately in the window. We use this procedure to position a new random target.

5. Using color.
You need to import the Color class from the awt package.
import java.awt.Color;
Here's how we draw the target:
Rect target = new Rect(xValue, yValue, size, size); 
d.setForeground(Color.blue); 
d.fill(target)
Chapter 2 and pages 56-57 have more on this.

6. Getting system time.
Pages 26-27 in chapter 1 describe the method used here.

long start, stop;
start = System.currentTimeMillis();
This takes the current system time. A few instructions later (perhaps as soon as we detect a mouse click) we set the value of stop in the same way:
stop = System.currentTimeMillis();
Now if we take the difference we obtain the number of milliseconds we waited. If we divide by 1000 we obtain the same time expressed in seconds.

The main new aspect here is that the return type of the function is long. This means it's also a whole number (like int) but from a larger range.

7. Waiting a random amount of time.
This method is explained on pages 102-103:
long now = System.currentTimeMillis();
long then = now + seconds * 1000; 
while (System.currentTimeMillis() < then) {

} 
Simply determine how many seconds you need to wait.

Then compute what the time will be in milliseconds after the number of seconds that you want to wait will have elapsed. Then keep checking the time and stay in a loop while you have to keep waiting.

In our program seconds is set randomly to 1-3 seconds.


Last updated on Mar 7, 2000 by Adrian German