Saturday 11 April 2009

FINAL VERSION

Mouse Events

Mouse events are the detection of mouse movements, button presses and releases. They are called events because the program does not wait for the mouse to be pressed, for example. Instead, an event handler is used that detects when the mouse has been pressed – this is called an event. Processing provides a simple way of detecting mouse events by providing a set of variables and functions that can be used to perform actions when a mouse event is detected.


Mouse Events in Processing


Processing provides event handlers for mouse presses, releases, clicks, movements and dragging. The simplest mouse event that Processing caters for is when a mouse button is pressed. This event detects any mouse button press – that is when the mouse button is pressed, not released.

To enable you to use these events, Processing provides both a mousePressed variable, and a mousePressed() function. We will describe their use these before explaining why there is a need for them both

mousePressed

The mousePressed variable is a boolean that has the value true if a mouse press event is currently detected, or the value false if there is no mouse press event detected. This means it can be used in the draw() function to determine if a mouse button is currently pressed. Each time the draw() function is run, the boolean will be evaluated, which will have the value true if the mouse button is still pressed. This means that keeping the mouse button pressed will continue to run the corresponding code each time the draw() function is called.

An example of this shown in the example below. Each time the draw method is called, the mousePressed boolean variable is evaluated. When the program is started, the background is filled with black. If the mouse is pressed, the background will be filled with white.

void draw() {
// if the mouse is pressed
if (mousePressed) {
// white background
background(255);
// else the mouse is not pressed
} else {
// black background
background(0);
}
}

You will see that, if the mouse button is held down, the background remains white until the mouse button is released – at that point the background reverts to black. It might seem that many mouse events are being generated if the mouse button is held. However a single event is detected when the button is pressed, which sets the mousePressed variable to true. It remains true until the mouse button is released, when it reverts to being false.

mousePressed()

In addition to the mousePressed variable, Processing provides the mousePressed() function. This function can be defined in your program and is called whenever a mouse press event is detected. An example of this is shown below

void draw() {
// black background
background(0);
}

void mousePressed() {
// white background
background(255);
}

This time you will see a slight change to how the previous example worked. Every time a mouse button is pressed, the screen flashes white, then back to black. If the mouse button is held, the period of time the screen is white does not change – it still flashes white then black. This is because the mousePressed() function operates in a different way to the mousePressed variable. Both are triggered by the mouse event - the mousePressed() function is called by the event, and the mousePressed variable is set by the event. However, the mousePressed() function is run once when the mouse is pressed whereas the mousePressed variable remains true until the button is released, meaning the corresponding code can be run many times for a single mouse press.

The reason both the variable and function exist is because the code corresponding to the event are run at subtly different times. Although the variable is set when the mouse event is detected, the corresponding code is only run when the

if (mousePressed)

condition is reached. The mousePressed() function, however, is run as soon as event is detected. Generally this won't make much difference to the way your program runs unless you are relying on the corresponding event code being run immediately.

Mouse Event Variables

In addition to the mousePressed variable, Processing provides other variables that can be used when programming mouse events

mouseButton

When we looked at the mousePressed variable above, it didn't matter which button we pressed. However, if you wanted to know which button was pressed, Processing provides the mouseButton variable. An example of its use is as follows:

void mousePressed() {
if (mouseButton == LEFT) {
// white background
background(255);
} else if (mouseButton == RIGHT) {
// blue background
background(0, 0, 255);
} else if (mouseButton == CENTER) {
// yellow background
background(255, 255, 0);
}
}

This time, the background colour will flash a different colour depending on which mouse button is pressed. The variable can be compared to some predefined variables that tell you which button was pressed – RIGHT, CENTER or LEFT – and action taken accordingly
mouseX and mouseY

The mouseX and mouseY variables provide a means of knowing where the mouse pointer is at any given time by assigning the x and y coordinate values respectively when a mouse event is detected. When used with the mousePressed() method, the exact coordinates of the mouse press can be obtained by accessing these variables.

void setup() {
// black background
background(0);
}

void draw() {

}

void mousePressed() {
fill(255);
// draw a white square
rect(mouseX, mouseY, 10, 10);
// output the coordinates to the console
println(mouseX + " " + mouseY);
}

If you run the above example you will see that the coordinates of each mouse press is printed to the console, and a little white square is drawn at the point where the mouse is pressed, as shown in figure 1


Figure 1: White squares drawn at the mouse coordinates

The mouseX and mouseY variables can be used anywhere, not just in mouse event methods. As an example, you might print out the values of the variables in the draw() method, which would continuously print the coordinates of the mouse pointer

void draw() {
// output the coordinates to the console
println(mouseX + " " + mouseY);
}

If you run this you will see that '0 0' is printed out unless you move the mouse pointer over the Processing window, when the mouse pointer coordinates will be printed

pmouseX and pmouseY

The pmouseX and pmouseY variables are similar to the mouseX and mouseY variables in that they hold the coordinates of the mouse pointer. However, the pmouse variables hold the previous coordinates, whilst the mouse variables hold the current coordinates. This can be demonstrated simply by drawing a line from the previous to the current mouse coordinates, as shown below:

void setup() {
// black background
background(0);
}

void draw() {
// draw a line from the previous mouse coordinates
stroke(255);
line(pmouseX, pmouseY, mouseX, mouseY);
}

If you run this, you will see that, as you move the mouse, a line will be drawn wherever you move. Although the effect looks complicated, all that is happening is that a line is being drawn from the previous mouse coordinate pmouseX and pMouseY to the current mouse coordinates mouseX and mouseY. As the draw() function is run continuously, every mouse move will draw a line


Figure 2: Lines drawn by mouse movement

Other Mouse Event Functions

As well as the mousePressed() function, Processing provides other mouse event functions that can be used to interact with the program.

Mouse Release

The mouseReleased() function is the opposite of the mousePressed() function. This mouse event is detected when a mouse button is released after being pressed. As with mousePressed(), it doesn't matter which mouse button is released, the event is detected for any button release.

void setup() {
// black background
background(0);
}

void draw() {

}

void mousePressed() {
// yellow
fill(255,255,0);
// draw a white square
rect(mouseX, mouseY, 10, 10);
}

void mouseReleased() {
// white
fill(255);
// draw a white square
rect(mouseX, mouseY, 10, 10);
}

Running this will show you how the mousePressed() and mouseReleased() functions are detected independently. When a mouse button is pressed, a yellow square is drawn on the screen. A white square is drawn when the mouse button is released. If you press a mouse button, then move the mouse before releasing it, you will see that both squares are drawn. Now try pressing a mouse button, moving the mouse, then pressing another mouse button. Then do the same with releasing the mouse buttons. Both sets of squares are drawn on the screen, showing that both sets of events are detected as they occur, drawing the square at the current mouse coordinates


Figure 3: Squares drawn by mousePressed() and mouseReleased() events

Mouse Click

The mouseClicked() function is like a combination of mousePressed() and mouseReleased(). This event is detected when a mouse button is pressed and then released. Again, the event is detected for any mouse button clicked.

void setup() {
// black background
background(0);
}


void draw() {

}

void mouseClicked() {
//red
fill(255,0,0);
// draw a red square
rect(mouseX, mouseY, 10, 10);
}

The above example shows the mouseClicked() function. Running it will show that clicking a mouse button will draw a red square at the mouse coordinates. You can also use it to see the difference between a mouse click, a mouse press and a mouse release. If you press a mouse button, then move the mouse, then release it, the mouseClicked() function will not be run and no square will be drawn. This tells us that a 'click' is defined by a mouse button being pressed then released without the mouse being moved in between these two events. The difference can be seen more clearly if we include the press and release events as well

void setup() {
// black background
background(0);
}


void draw() {

}

void mouseClicked() {
//red
fill(255,0,0);
// draw a red square
rect(mouseX, mouseY, 10, 10);
}

void mousePressed() {
// yellow
fill(255,255,0);
// draw a white square
rect(mouseX, mouseY, 10, 10);
}

void mouseReleased() {
// white
fill(255);
// draw a white square
rect(mouseX, mouseY, 10, 10);
}

Running this example will show you how mouse click, press and release events differ. If the mouse is clicked without moving, a red square is drawn. However, if you press the mouse, then move it, a yellow square is drawn. Then, when the button is released a white square is drawn.


Figure 4: Squares drawn by mousePressed(), mouseReleased() and mouseClicked() events

Mouse Moving

The mouseMoved() function detects events whenever the mouse pointer is moved. This means that anything in the mouseMoved() function will run every time the mouse is moved. An example of this is shown below

void draw() {
background(0);
}

void mouseMoved() {
// draw a square wherever the mouse pointer is
rect(mouseX, mouseY, 20, 20);
}

The result of this is that a square is drawn on the screen at the current coordinates of the mouse pointer, but only when the mouse is moving. If the mouse pointer is stationary, no square will be drawn as the background is refreshed every time the draw() function is run


Mouse Dragging


The mouseDragged() function is run while the mouse is moving with a mouse button held. It can be thought of as a combination of the mouseMoved() and mousePressed() functions. Like the mouseMoved() function, the code inside the function is only run if the mouse is moving and, like the mousePressed() function, a mouse button must be pressed but it doesn't matter which button. We can easily convert the previous example by changing the mouseMoved() to be mouseDragged()

void draw() {
background(0);
}

void mouseDragged() {
// draw a square wherever the mouse pointer is
rect(mouseX, mouseY, 20, 20);
}

You will see that this works exactly as before except that now you have to press and hold a mouse button to see the square. If you either stop moving the mouse, or pressing a button, the square is not displayed. Because a mouse button has to be pressed for this event to be triggered, the mouseDragged() function cannot be run at the same time as the mouseMoved() function. This can be demonstrated by defining both functions

void draw() {
background(0);
}

void mouseDragged() {
// draw a size 20 square wherever the mouse pointer is
rect(mouseX, mouseY, 20, 20);
}

void mouseMoved() {
// draw a size 40 square wherever the mouse pointer is
rect(mouseX, mouseY, 40, 40);
}

Running this will show you that the two functions cannot run at the same time. Either the large yellow circle is displayed when the mouse is moved, or the small white square is displayed when a mouse button is pressed whilst the mouse is moving, but never both

Putting It All Together

To put these ideas together, we have created a small space simulation. It doesn't use every mouse event, but includes mouseDragged(), mouseClicked() and the mouse event variables. Running it lets you interact with it in several ways:
- Clicking the left mouse button will draw a single-point white star at the mouse coordinates
- Clicking the right mouse button will draw a red planet at the mouse coordinates
- Clicking any other mouse button (eg the middle one) will draw a yellow planet with a red ring at the mouse coordinates
- Dragging the mouse pointer left or right will cause the stars and planets to scroll in that direction

// colours used in the program
int white = color(255);
int black = color(0);
int red = color(255,0,0);
int yellow = color(255,255,0);

boolean left;

void setup() {
// black background
background(black);
// start going right
left = false;
// smooth edges
smooth();
}

void draw() {
// load the pixels
loadPixels();
// if going left
if (left) {
// set every pixel to the one before it
for (int i = pixels.length-1; i > 0; i--) {
pixels[i] = pixels[i-1];
}
} else {
// otherwise going right, so set every pixel
// to the one after it
for (int i = 0; i < pixels.length-1; i++) {
pixels[i] = pixels[i+1];
}
}
// update the altered pixels
updatePixels();
}

void mouseDragged() {
// if the last mouse position is lower than the current
if (pmouseX < mouseX) {
// we are going left
left = true;
} else {
// otherwise we are going right
left = false;
}
}

void mouseClicked() {

if (mouseButton == LEFT) {
// draw a single dot for a star
stroke(white);
point(mouseX, mouseY);
} else if (mouseButton == RIGHT) {
// draw a red planet
stroke(black);
fill(red);
ellipse(mouseX, mouseY, 10, 10);
} else {
// draw a planet ring
strokeWeight(2);
stroke(red);
noFill();
arc(mouseX, mouseY, 40, 8, 0, TWO_PI);
// draw a yellow planet
stroke(yellow);
fill(yellow);
ellipse(mouseX, mouseY, 10, 10);
// reset the stroke weight
strokeWeight(1);
}

}


You can create as many stars and planets as you like


Figure 5: Space simulation

1 comment:

Anonymous said...

Nice, I'm a bit of fan of the space theme myself. I've also discovered how to get that console look on full width, so I've now converted my chunk. However what my blog lacks is those cool console inserts to display the code, I've opted for syntax highlighting instead.