Step 4: Mouse Events

Before we start coding, let's plan exactly what PaintApp should do. We will let the user scribble by pressing and holding down the left mouse button, and releasing the left button stops drawing. Also, pressing the right mouse button clears the drawing area.

How do we implement this in PaintApp? Let's see what should happen when the user presses a button, moves the mouse, and releases the button.

Based on our thought processes, we'll need two additional fields: one to hold the current position, and one to signal whether we're drawing or not. So, add the following lines to the end of the Fields section of PaintApp:

private Point prevPoint;
private boolean isDrawing = false;

We create an object of class Point called prevPoint; this will hold the current (previous) mouse position. A Point object has two fields, x and y.

We also add a boolean field called isDrawing that is initially false. When isDrawing is true, that means that the user is currently drawing.

Finally, we get to the mouse-handling routines. Add the following methods after update():

public boolean mouseDown(Event evt, int x, int y) {
	if(evt.modifiers == Event.META_MASK) {
		clearImage();
		repaint();
	} else {
		prevPoint = new Point(x, y);
		isDrawing = true;
	}

	return true;
}

public boolean mouseDrag(Event evt, int x, int y) {
	if(isDrawing) {
		gDraw.drawLine(prevPoint.x, prevPoint.y, x, y);
		prevPoint.move(x, y);
		repaint();
	}

	return true;
}

public boolean mouseUp(Event evt, int x, int y) {
	isDrawing = false;
	return true;
}

These methods are basically translations of the "thought processes" above into Java.

Mouse Events

Event handlers are public methods that Java calls whenever the user performs some action, such as pressing a key or moving the mouse. The Applet class provides many event handlers that we can override to respond to these events. In PaintApp, we override three to respond to various mouse events: mouseDown(), mouseDrag(), and mouseUp().

Each of these methods takes three arguments: an Event object that contains additional information about the event, and two integers that hold the x and y coordinates of the mouse. If you examine the listing above, you'll see that the methods are declared type boolean, so the methods are also functions. Event handlers return a boolean value indicating whether or not they handled the event. In all three methods above, the last statement returns true ("yes, I handled the event").

Now that that's over with, let's move on to each of the methods, starting with mouseDown(), which is called whenever the user presses a mouse button over the applet:

public boolean mouseDown(Event evt, int x, int y) {
	if(evt.modifiers == Event.META_MASK) {
		clearImage();
		repaint();
	} else {
		prevPoint = new Point(x, y);
		isDrawing = true;
	}

	return true;
}

We first check whether the user pressed the right mouse button by using an if statement. The syntax of an if statement is as follows:

if(boolean-expression)
	code-executed-if-expression-is-true
[else
	code-executed-if-expression-is-false]

After the if keyword is a Boolean expression enclosed in parentheses. A Boolean expression evaluates to either true or false. (For example, a comparison of two values is a Boolean expression.) Then comes the statement executed if the expression is true. To execute more than one statement, enclose them in curly braces. As indicated by the brackets above, the else part is optional. If present, the following statement (or group of statements, if enclosed in curly braces) is executed if the expression is false.

So, going back to our listing, we compare the modifiers field of evt to the Event.META_MASK constant using the equality operator (double ='s). If they are equal, meaning the right mouse button was pressed, we call clearImage() to erase the drawing buffer, and then call repaint() to update the screen.

If the two values aren't equal (the left button was pressed), we create a Point object, using the new operator, representing the current position and save it in prevPoint. Then we set our isDrawing flag to true, indicating that the user is now drawing.

Finally, we return true to tell Java that we handled the event.

Next, take a look at the mouseDrag() method, called whenever the user moves the mouse over the applet with a button down:

public boolean mouseDrag(Event evt, int x, int y) {
	if(isDrawing) {
		gDraw.drawLine(prevPoint.x, prevPoint.y, x, y);
		prevPoint.move(x, y);
		repaint();
	}

	return true;
}

We first see if the user is drawing by checking the isDrawing flag. If so, we draw a line from the previous point to the current point, using the drawLine() method of gDraw. This method takes four arguments, the x and y coordinates of the starting and ending points.

Then we set the previous point to the current point (a bit confusing?) using the move() method of prevPoint. Finally, we update the screen with a call to repaint() and return true.

Our last method of the day is mouseUp(), a rather short method here, that is called whenever the user releases a mouse button:

public boolean mouseUp(Event evt, int x, int y) {
	isDrawing = false;
	return true;
}

We simply turn off drawing by setting isDrawing to false, and then return true. Simple, wasn't it?

Our applet is now fully functional. Go ahead and compile PaintApp, then view it in a browser. Scribble away to your heart's content.

In the next step, we'll add support for applet parameters to complete PaintApp.


1