# CSCI A202 - Introduction to Programming (II)

Lecture 8: Getting Mouse Input in Graphical Applications. Basic animations

The last function we defined last time describes what we do when the mouse is pressed. We know that it is invoked by the run time system when the mouse button is pressed and at invocation time it receives the `x` and `y` coordinates of the mouse pointer in its two parameters.

```public void mousePressed(int x, int y) {
for (int i = 0; i < radii.length; i++)
if (circles[i].inside(x, y)) {
selectedCircle = circles[i];
break;
}
}```
This function tries to find a circle that has the mouse pointer inside. To find the circle we loop through the array of references and ask each circle if the two coordinates are inside it.

So we need to define an `inside()` method:

```boolean inside(int xMouse, int yMouse) {
if (Math.sqrt((x + radius - xMouse) * (x + radius - xMouse) +
return true;
else
return false;
}```
This will be an instance method part of the `Circle` class, and it will return either `true` or `false` depending on whether the mouse is inside or outside of the circle.

We also need to define and use a `Circle` variable

`Circle selectedCircle;`
in which we will keep a reference to the first circle that replies with `true` when asked if the mouse pointer is `inside` it. Note that this should be `null` if no `Circle` is currently selected.

Notice that if more than one circle qualifies we select the one that has the smallest index in the array of circles that we maintain.

We also need to point out that we loop for `radii.length` number of times, and we do that relying on the fact that the arrays of `radii`, `xCoords`, `yCoords` and `colors` are parallel arrays with the same length.

For this example the `paint()` method of the application (`Step3`) will be the same as the one for the application we developed at the previous stage:

```public void paint(Graphics g) {
for (int i = 0; i < radii.length; i++)
circles[i].draw(g);
}```

For the drawing routine we will use a different approach though, in that we will make use of the `XOR` painting mode. In this mode the circle may appear in a slightly different color but when drawn twice the background is restored, so it's a very cheap (fast) way of simulating the movement of an object against a certain background.

```void draw(Graphics g) {
g.setColor(color);
g.setXORMode(Color.black);
}```

Now we need to define the other two methods that handle mouse input.

If we drag the mouse and a circle is selected we need to have it follow the mouse pointer.

```public void mouseDragged(int x, int y) {
if (selectedCircle != null)
selectedCircle.moveTo(getGraphics(), x, y);
}```
So we need to define a `moveTo` method as an instance method in the `Circle` class. I think the lab notes call this method `jumpTo` but a little change of notation never hurt anyone.
```void moveTo(Graphics g, int newX, int newY) {
draw(g);
draw(g);
}```
You notice that we first erase the circle by redrawing it at the same exact location and then drawing it fresh at the current location of the mouse pointer. (We remember that drawing in `XOR` mode twice in a row has the effect of restoring the background to what it was before we drew there for the first time).

You should also note that we need to subtract the `radius` from the current mouse pointer's position because we want the circle to move along with the mouse as if we would be holding it by its center, and the `x` and `y` that we store as instance variables are in fact the coordinates of the lower left corner of the circle's bounding rectangle (top left corner because the coordinates on the screen are reversed along the y axis).

When the mouse is released, and if there is a circle being moved at the time (that is, if the `selectedCircle` variable is not `null`) then we need to place the circle at that location and forget about carrying the circle around any more.

```public void mouseReleased(int x, int y) {
if (selectedCircle != null) {
selectedCircle.moveTo(getGraphics(), x, y);
selectedCircle = null;
}
}```
And we're done. Here's the framework of `Step3`:
```import java.awt.*;
import BreezyGUI.*;

public class Step3 extends GBFrame {

Color[] colors = ... ;

int[] xCoords = ... ;
int[] yCoords = ... ;

public void paint(Graphics g) {
for (int i = 0; i < radii.length; i++)
circles[i].draw(g);
}

int numberOfCircles = 6;

Circle[] circles = new Circle[numberOfCircles];

Step3() {
for (int i = 0; i < numberOfCircles; i++) {
circles[i] = new Circle(...); // same as in Step2
}
}

Circle selectedCircle;

public void mousePressed(int x, int y) {
...
}

public void mouseDragged(int x, int y) {
...
}

public void mouseReleased(int x, int y) {
...
}

public static void main(String[] args) {
Frame f = new Step3();
f.setSize(500, 300);
f.setVisible(true);
}
}

class Circle {
private Color color;
Circle( int xInitially, int yInitially,
x      = xInitially;
y      = yInitially;
this.color  = color;
} ```
Since the coordinates change but the radius and the color don't (at least in our examples here) we decide to make this distinction in the names of the parameters passed to the constructor. So we need to make use of the `this` variable to initialize the last two.
```  void draw(Graphics g) {
...
}
void moveTo(Graphics g, int newX, int newY) {
...
}
boolean inside(int xMouse, int yMouse) {
...
}
}```

Threads A thread is a single sequential flow of control within a process.

A single process can have multiple concurrently executing threads. Java provides a `Thread` class for threads just as it provides a `String` class for strings, etc., in the standard Java class libraries.

Here's a short example:

```tucotuco.cs.indiana.edu% vi ThreadsTest.java
public static void main(String[] args) {
PingPong a = new PingPong("Ping", 300);
PingPong b = new PingPong("Pong", 700);
b.start();
a.start();
}
}

private String word;
private int delay;
PingPong (String w, int d) {
word = w;
delay = d;
}
public void run() {
while (true) {
try {
System.out.println(word + "...");
sleep(delay);
} catch (InterruptedException e) {
return;
}
}
}
}
Pong...
Ping...
Ping...
Ping...
Pong...
Ping...
Ping...
Pong...
Ping...
Ping...
Pong...
Ping...
Ping...
^Ctucotuco.cs.indiana.edu% ```
Enough about threads, let's get back to `Step 4`.

We need to write a function that describes a simulation step:

```public void run() {
Graphics g = getGraphics();
for (int i = 0; i < numberOfCircles; i++)
repaint();
}```
This is one simulation step only. Its name is probably unfortunate. We should have called it `simulationStep()` or something of that kind, to avoid any confusion with any terminology for threads.

We'll call this repeatedly, every 300 milliseconds, from a driver thread.

```class Driver extends Thread {
Step4 myFrame;
Driver (Step4 passedFrame) {
myFrame = passedFrame;
}
public void run() {
while (true) {
try {
sleep(300);
myFrame.run();
} catch (InterruptedException e) { }
}
}
}```
`Step 4`'s `main` will initialize a `Driver` and `start()` it.
```public static void main(String[] args) {
Step4 f = new Step4();
f.setSize(500, 300);
f.setVisible(true);
Driver d = new Driver(f);
d.start();
}```
We need to devine `advance()` for the simulation.

Each circle should know how to `advance()` so it's an instance method.

```void advance(Graphics g) {
int newX, newY;

newX = currentX + deltaX;

if (newX < Step4.LOW_X) {
newX = Step4.LOW_X + (Step4.LOW_X - newX);
deltaX = -deltaX; }

if (newX + radius * 2 > Step4.HIGH_X) {
newX = Step4.HIGH_X - 2 * radius -
(newX + radius * 2 - Step4.HIGH_X);
deltaX = -deltaX;
}

newY = currentY + deltaY;

if (newY < Step4.LOW_Y) {
newY = Step4.LOW_Y + (Step4.LOW_Y - newY);
deltaY = -deltaY;
}

if (newY + radius * 2 > Step4.HIGH_Y) {
newY = Step4.HIGH_Y - 2 * radius -
(newY + radius * 2 - Step4.HIGH_Y);
deltaY = -deltaY;
}

moveTo(g, newX, newY);
}```
The part in `blue` controls the bouncing and will be explained in class.

We need to define the constants in `Step4` for the bounding rectangle of our simulation.

```public final static int LOW_X = 30,
LOW_Y = 30,
HIGH_X = 400,
HIGH_Y = 300;```
The `paint()` changes only slightly:
```public void paint(Graphics g) {
g.setColor(Color.black);
g.drawRect(LOW_X - 1,
LOW_Y - 1,
HIGH_X+1 - LOW_X,
HIGH_Y+1-LOW_Y);
for (int i = 0; i < numberOfCircles; i++)
circles[i].draw(g);
}```
The only thing that's left is to describe how the `Circle` class is representing movement.

In the snippet below we use `currentX`, and `currentY` for the location variables and `deltaX` and `deltaY` for the direction of movement.

```private int currentX, currentY, radius;
private int deltaX, deltaY;
```
There are eight directions of movement and they correspond to adding 1 or subtracting 1 from the current values of the coordinates. The 9th case is the one when the circle doesn't move, so the coordinates are changed with `0` each one of them (they, in fact, remain unchanged).

Here's the initialization part:

```Circle( int xInitially, int yInitially,
currentX      = xInitially;
currentY      = yInitially;
color         = colorInitially;

deltaX = (int)(Math.random() * 3) - 1; // { -1, 0, 1}
deltaY = (int)(Math.random() * 3) - 1; // { -1, 0, 1}

if (deltaX == 0 && deltaY == 0) { // everybody should be moving
switch (((int)Math.random() * 8 + 1)) {
case  1: deltaX = -1; deltaY = -1; break;
case  2: deltaX = -1; deltaY =  0; break;
case  3: deltaX = -1; deltaY =  1; break;
case  4: deltaX =  1; deltaY = -1; break;
case  5: deltaX =  1; deltaY =  0; break;
case  6: deltaX =  1; deltaY =  1; break;
case  7: deltaX =  0; deltaY = -1; break;
case  8: deltaX =  0; deltaY =  1; break;
default: break;
}
}
}```
Since we no longer use `XOR` mode of painting
```void draw(Graphics g) {
g.setColor(color);
the image will have a bit of flickering. We can fix this in several ways (for example doing double buffering, but that's outside of the scope of what we want to do now) but at least the `moveTo` method is shorter
```void moveTo(Graphics g, int newX, int newY) {
since all drawing happens in `paint()`.
You now have everything you need to put together `Step 3` and `Step 4` to finish your assignment.