Book Fragment 83
Buttons
Imagine a computer program without buttons. It is almost impossible. Buttons have become an integral part of any interface design kit when developing software.
The illustrations below show buttons from a few programs. A great deal of the programs' functionality have been captured in these buttons:Illustration 1: Buttons from OpenOffice.org
Illustration 2: A couple of more "traditional" buttons
Illustration 3: Buttons from Microsoft Messenger
Buttons and other graphical user interface (GUI) elements such as sliders, list boxes and spinners are usually referred to as widgets. These are used to enhance the users experience of an application and allows the user to interact with it. A button executes or launches some action such as allowing the user to select a file for opening or as in illustration 3, above, the third button from the left is used to initiate a video call to another user.
Unlike some more extensive languages such as Java, Processing does not provide libraries with ready made widgets. The process of creating buttons is not complex, but it is quite painstaking.
As the purpose of a button is, off course, to start or stop some process, each button is usually associated with some action. We can therefore summarise the process of creating a button in the following steps:
- Define an area on the screen which will serve as a button. This is usually done by drawing some shape, such as a square or a circle in that area. Processing's own buttons are good examples of this:
Illustration 4: Processing's buttons - Determine whether the mouse button was pressed and if so, whether it was pressed in the button area.
- Execute the process that the button is meant to initiate.
Earlier in this book, we have already covered all the processes and skills required to complete these steps. All that is now required is to put it into practice.
Let's start by writing a program with one button that will switch on a light bulb if it is off, or switch it off it is on.
Step one can be accomplished with the following few lines of code:
// Define the area on the screen that will serve
// as a button and draw a shape in that area.
// We will be using a black square
int button_top_left_x = 10;
int button_top_left_y = 10;
int button_width = 20;
int button_colour = color(0x00 ,0x00 ,0x00);
void setup() {
// Draw window of 200 pixels wide by 200 pixels high
size(200,200);
}
void draw() {
// draw the button
fill(button_colour);
rect(button_top_left_x, button_top_left_y, button_width, button_width);
}
We now have a window with a button displayed in the top left hand corner:
Illustration 5: Drawing the button
To accomplish step two you might have to refer back to chunk 82 (Mouse events). Firstly we need to determine whether the mouse button is pressed. This is done by adding the mousePressed() function to our program. Secondly we need to determine whether the mouse is being pressed over the square we drew that serves as our button. Our program can now be extended with the following code:
// Handle mouse event
void mousePressed() {
// check whether the mouse button was pressed within the boundaries of the shape
// defined by our button, which in this case is a rectangle.
// mouseX and mouseY holds the x and y co-ordinates on which the mouse was clicked.
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
// Code to be executed when the mouse button is pressed in this area
}
}
Since we want to switch a light bulb on and off we will need to draw the light bulb in its off state or in its on state. We will keep things very simple so we are going to draw the light bulb using a grey square for the base and a white circle when the bulb is switched off or a yellow circle when the bulb is switched on. We will also need a boolean variable that will be true when the bulb is on or false when it is off. When we are done the light bulb should look like illustration 6 when it is on and illustration 7 when it is off:
Illustration 6: Bulb off
Illustration 7: Bulb on
In the very first section of our program we need to add the boolean variable that signifies the state of our light bulb. The light is switched off when the program first begins and therefore the variable is given an initial value of false. The line is shown in bold in the following code fragment:
// Define the area on the screen that will serve
// as a button and draw a shape in that area.
// We will be using a black square
int button_top_left_x = 10;
int button_top_left_y = 10;
int button_width = 20;
int button_colour = color(0x00 ,0x00 ,0x00);
// a boolean value to indicate whether the light bulb is on or off
// if it is on bulb_on will be true, if it is off, bulb_on will be false;
boolean bulb_on = false;
We now need to reflect the state of the light bulb. To do this the draw function can be extended to draw the light bulb in one of its two states:
void draw() {
// draw the button
fill(button_colour);
rectMode(CORNER);
rect(button_top_left_x, button_top_left_y, button_width, button_width);
// draw the light bulb base
fill(64,64,64);
rectMode(CENTER);
rect(100,100,15,20);
// draw a circle for the light bulb
if (bulb_on) {
fill(0xFF, 0xCC, 0x33); // an orange fill when the bulb is on
} else {
fill(0xFF, 0xFF, 0xFF); // a white fill when the bulb is off
}
ellipseMode(CENTER);
ellipse(100,80,30,30);
}
Notice that before drawing the circle for the light we set the ellipse mode to CENTER. This means that the x and y co-ordinates provided will be used as the centre point of the circle. Refer to the Processing documentation for more information of mode settings.
Everything is now in place for us to switch the light bulb on and off using our button. All that is left to do is to add the code that will toggle the boolean value bulb_on between true and false in the mousePressed() function:
void mousePressed() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
if (bulb_on) {
bulb_on = false;
} else {
bulb_on = true;
}
}
}
The complete code listing for the program:
// Define the area on the screen that will serve
// as a button and draw a shape in that area.
// We will be using a black square
int button_top_left_x = 10;
int button_top_left_y = 10;
int button_width = 20;
int button_colour = color(0x00 ,0x00 ,0x00);
// a boolean value to indicate whether the light bulb is on or off
// if it is on bulb_on will be true, if it is off, bulb_on will be false;
boolean bulb_on = false;
void setup() {
// Draw window of 200 pixels wide by 200 pixels high
size(200,200);
}
void draw() {
// draw the button
fill(button_colour);
rectMode(CORNER);
rect(button_top_left_x, button_top_left_y, button_width, button_width);
// draw the light bulb base
fill(0x40 ,0x40 ,0x40);
rectMode(CENTER);
rect(100,100,15,20);
if (bulb_on) {
fill(0xFF ,0xCC ,0x33); // an orange fill when the bulb is on
} else {
fill(0xFF ,0xFF ,0xFF); // a white fill when the bulb is off
}
ellipseMode(CENTER);
ellipse(100,80,30,30);
}
void mousePressed() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
if (bulb_on) {
bulb_on = false;
} else {
bulb_on = true;
}
}
}
I'm sure you will agree that this is not a very exciting button we have created. Nowadays, in the graphical environments we are used to, we can see when a button has focus. For example, when the mouse is hovered over the button, it might change colour or it might be outlined as in illustrations 8 and 9 below:
And when the mouse button is pressed down on the button it changes again:
Illustration 10: A Processing button when the mouse button is pressed down. | <><></> </> Illustration 11: An Open Office button being pressed down. | <><></></>
To mimic this behaviour we need to code behaviours for the mouse when it is pressed, released or moved. The three functions, you might recall, that we need to use are:
- void mousePressed();
- void mouseReleased();
- void mouseMoved();
The button's normal colour would be black. If the mouse is pressed down while inside the button area we want to fill the button with the colour red. If the mouse is only hovering above the button, we want to fill it with a light blue colour.
Illustration 12: Button in normal state | <><></> </> Illustration 13: Mouse hovering over button. |
Illustration 14: Mouse pressed over button | <><></></>
We need to define three new variables to hold the colours for the three different states. To do this the following lines are added to the declarations at the beginning of the program:
// Define the colours for the button in its various states
int button_up_colour = color(0x00 ,0x00 ,0x00);
int button_down_colour = color(0xff, 0x00 ,0x00);
int button_over_colour = color(0x99, 0xff, 0xff);
When the mouse is pressed inside the button area, the colour of the button should change to red. The mousePressed() function is enhanced to do this by adding one line.
void mousePressed() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
button_colour = button_down_colour;
if (bulb_on) {
bulb_on = false;
} else {
bulb_on = true;
}
}
}
If the mouse is moved to a point inside the button area, the colour is changed to light blue. If the mouse is moved to a point outside the button area, the colour is changed to black:
void mouseMoved() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
button_colour = button_over_colour;
} else {
button_colour = button_up_colour;
}
}
When the button is released after being pressed down, the colour should change to light blue if the mouse is over the button area. If it is release elsewhere the colour of the button should be set to black:
void mouseReleased() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
button_colour = button_over_colour;
} else {
button_colour = button_up_colour;
}
}
Following is the complete listing for the program :
// Define the area on the screen that will serve
// as a button and draw a shape in that area.
// We will be using a square
int button_top_left_x = 10;
int button_top_left_y = 10;
int button_width = 20;
// Declare a variable that will hold the colour for the button
// in its current state
int button_colour = color(0x00 ,0x00 ,0x00);
// Define the colours for the button in its various states
int button_up_colour = color(0x00 ,0x00 ,0x00);
int button_down_colour = color(0xFF, 0x00,0x00);
int button_over_colour = color(0x99, 0xFF, 0xFF);
// a boolean value to indicate whether the light bulb is on or off
// if it is on bulb_on will be true, if it is off, bulb_on will be false;
boolean bulb_on = false;
void setup() {
size(200,200);
}
void draw() {
// draw the button
fill(button_colour);
rectMode(CORNER);
rect(button_top_left_x, button_top_left_y, button_width, button_width);
// draw the light bulb base
fill(0x40 ,0x40 ,0x40);
rectMode(CENTER);
rect(100,100,15,20);
if (bulb_on) {
fill(0xFF ,0xCC ,0x33); // an orange fill when the bulb is on
} else {
fill(0xFF ,0xFF ,0xFF); // a white fill when the bulb is off
}
ellipseMode(CENTER);
ellipse(100,80,30,30);
}
void mousePressed() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
button_colour = button_down_colour;
if (bulb_on) {
bulb_on = false;
} else {
bulb_on = true;
}
}
}
void mouseMoved() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
button_colour = button_over_colour;
} else {
button_colour = button_up_colour;
}
}
void mouseReleased() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
button_colour = button_over_colour;
} else {
button_colour = button_up_colour;
}
}
In the next listing we have a created a slightly more sophisticated and realistic button. Rather than using just a square for a button, we will draw a button using triangles, a line and rectangles. We create the illusion of a 3D button that moves up and down, when clicked ,by drawing a bevel that is shaded on the right and the bottom. The bevel at the top and left is in a lighter colour. This gives the impression of light shining on a button from the left. When the button is clicked, the two colours are switched around so that the top and left of the bevel is the darker colour and the right and bottom of the bevel is the lighter colour giving the impression that the button is being pressed down.
Step 1: Draw two triangles, the one on the left white and the one on the right grey.
Step 2: Draw line from top left to bottom right. These diagonal lines help to create the illusion of a bevel.
Step 3: Draw a smaller darker square on top
Step 4: To give the appearance of the button being depressed merely switch the colours of the two triangles.
The listing below will show this in action, switching the light bulb on and off as before. Try this code in Processing to see how the button works:
// Define the area on the screen that will serve
// as a button and draw a shape in that area.
// We will be using a black square
int button_top_left_x = 10;
int button_top_left_y = 10;
int button_width = 20;
// Declare a variable that will hold the colour for the button
// in its current state
int button_top_colour = color(0x80, 0x80, 0x80);
// Define the colours for the button in its various states
int button_up_colour = color(0xC0, 0xC0, 0xC0); // grey
int button_down_colour = color(0xFF, 0xFF, 0xFF); // white
int button_over_colour = color(0x80, 0x80, 0x80);
int background_colour = color(0xC0, 0xC0, 0xC0);
int button_left_colour = button_down_colour;
int button_right_colour = button_up_colour;
int hover_colour = background_colour;
// a boolean value to indicate whether the light bulb is on or off
// if it is on bulb_on will be true, if it is off, bulb_on will be false;
boolean bulb_on = false;
void setup() {
background(background_colour);
size(200,200);
}
void draw() {
rectMode(CORNER);
// highlight square
noStroke();
fill(hover_colour);
rect(button_top_left_x - 3, button_top_left_y - 3, button_width + 6, button_width + 6);
// draw the button
stroke(0x00, 0x00, 0x00);
fill(button_right_colour);
triangle(button_top_left_x + button_width, button_top_left_y, button_top_left_x + button_width, button_top_left_y + button_width, button_top_left_x, button_top_left_y + button_width);
fill(button_left_colour);
triangle(button_top_left_x, button_top_left_y, button_top_left_x + button_width, button_top_left_y, button_top_left_x, button_top_left_y + button_width);
line(button_top_left_x, button_top_left_y, button_top_left_x + button_width, button_top_left_y + button_width);
// little square
fill(button_top_colour);
rect(button_top_left_x + 3, button_top_left_y + 3, button_width - 6, button_width - 6);
// draw the light bulb base
fill(0x40, 0x40, 0x40);
rectMode(CENTER);
rect(100,100,15,20);
if (bulb_on) {
fill(0xFF, 0xFF, 0xFF); // an orange fill when the bulb is on
} else {
fill(0xFF, 0xFF, 0xFF); // a white fill when the bulb is off
}
ellipseMode(CENTER);
ellipse(100,80,30,30);
}
void mousePressed() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
// if the button is pressed, switch the bevel colours
// so that the button appears to be pressed down
int tmp = button_left_colour;
button_left_colour = button_right_colour;
button_right_colour = tmp;
if (bulb_on) {
bulb_on = false;
} else {
bulb_on = true;
}
}
}
void mouseMoved() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
hover_colour = button_over_colour;
} else {
hover_colour = background_colour;
}
}
void mouseReleased() {
if (mouseX >= button_top_left_x &&
mouseX <= button_top_left_x + button_width &&
mouseY >= button_top_left_y &&
mouseY <= (button_top_left_y + button_width)) {
// When the mouse button is released, switch the button bevel colours
// so that the button displays in its upper position
int tmp = button_left_colour;
button_left_colour = button_right_colour;
button_right_colour = tmp;
}
}
The illustrations below show our final program:
Illustration 12: Final program with the button in the up position
Illustration 14: When the mouse hovers over the button we highlight the background
Illustration 13: The button in the down position when the mouse button is pressed down
Making a button behave as we have just done is, of course, only one option. It is a very simple button and its behaviour merely serves to demonstrate how buttons can be implemented. If you were to look at different programs or sometimes different buttons in the same program, you would probably find that buttons can respond to mouse events in many ways.
Our program, for instance, executes the process we want the button to initiate when the mouse button is pressed. If one looks at programs such as Word, Open Office or Firefox, the required process is executed on release rather than on the press of the mouse button.
In the next chunk we will discuss this option and look at slightly more advanced buttons.
No comments:
Post a Comment