|
Chapter: User
Defined
Functions
Creating a user defined function
Datatyping a function
The first line of a function definition must be used to declare the
function, and as you are aware declaration in Processing means giving
the function (variable or other entity) a name and datatyping it. Some
programming languages might refer to the first line of a user defined
function as a function header. Naming a function is a very similar
process to that of naming a variable as you will see in the following
code fragment forming the first line of our user defined function:
boolean overButton()
The parenthesis following the function name are used to contain
declarative parameters. These parameters will be defined within the
function body, in our case this function does not accept any parameters
so we leave the parenthesis empty. As you have been using functions
that accept parameters user defined functions can also be created to
accept parameters that you define.
In comparison to setup() or draw() our function is being datatyped as a
boolean, all functions must return a datatype or use the void keyword
like setup() and draw(). As void does not return any data it is
subsequently not classed as a datatype within Processing (and
traditionally in C/C++) but as a structural element, this differs to
other higher level languages (some of which are closely tied to
Processing such as Arduino) that do consider void as a datatype.
Nonetheless our function is going to return data of type boolean, which
will be used to determine whether the user's mouse is over the slider
button or not.
Determining a range
In order to calculate whether the mouse is over the slider button or
not we will have to determine the range in which the slider button is
located. We already know where the slider button is in terms of X and Y
because these are values determined by parameters if the image()
function used to draw the image. We can use this information, along
with the width and height object variables to work out the slider
button's range.
Determining
the range of the button as the area covered in diagonal stripes.
In the previous image if A and B where variables the image() function
to render the slider button could be rewritten as:
image(sliderFd, A, B);
This method of expressing the X and Y parameters as variables is
particularly useful to us because, we would like the slider button to
be able to “slide” along the X axis, this means the value of A would
need to be dynamic.
As the slider button only moves along the X axis the variable B will
not change, however this value is used in more than one situation,
firstly to determine the Y position of the image that will form the
area along which the slider button can be dragged referred to as
sliderBk (short for slider background), secondly to determine the Y
position of the slider button referred to as sliderFd (short for slider
foreground) and thirdly referenced within the range we will set up
shortly to determine the clickable area of the button. As a result this
value has been declared as a variable of type int and named margin.
This way if at a later stage we decide to move the entire slider down
in order to make room for other graphical elements above it then all we
need to do is update the value associated with margin, instead of
having to find and change an explicit value scattered throughout the
source code.
The value described as A in the previous image requires a more
meaningful name, something that is self documenting. As a result this
value has been named buttonXPos, declared as a variable in the global
region and datatyped as an int:
int buttonXPos;
Eventually we'd like to replace the X parameter for the image()
function rendering sliderFd in the X position determined by buttonXPos.
As we are aware what the variable buttonXPos is going to represent
we're going to set it up with a temporary value within our sketch to
test our user defined function. So we're going to add a temporary
statement for testing and debugging purposes to the draw() function
which assigns a value to buttonXPos and then changes the image()
function of which sliderFd is associated with to reflect this
assignment statement. Once the buttonXPos variable is declared in
global space, you can edit the draw() structure to include the
first command and update the appropriate image command:
...
//temp for debugging
buttonXPos = width/2 - sliderBk.width/2;
...
image(sliderFd,buttonXPos ,margin);
Once we are sure that our function is working we will return to the
temporary statement that we adding for debugging and testing purposes
and include the buttonXPos variable assignment statement within an if()
structure.
We are now ready to proceed with setting up our function. To briefly
recap our function has been declared as type boolean and given the name
overButton(), setting up the range will occur within a conditional
consisting of multiple comparisons and will look like this:
boolean overButton(){
if (mouseX >= buttonXPos && mouseX <= buttonXPos
+ sliderFd.width && mouseY
>= margin && mouseY <= margin + sliderFd.height)
{
…
Although this conditional might look a little confusing at first, when
broken down into the four distinctive elements that it is comprised of
it tends too make a lot more sense. So lets have a look at what each
comparison is calculating and how these four different expressions put
together will either return a value of true or false, which will
ultimately determine whether the following code block of the if()
structure is run or not.
Comparison 1: mouseX >= buttonXPos
This checks if the mouse is anywhere in the highlighted area of the
following image. If the mouse is then a value of true is returned and
Processing will continue to evaluate the rest of the conditional.
Comparison 2: mouseX <= buttonXPos + sliderFd.width
This comparison is only evaluated if the previous comparison evaluated
to true because a logical AND operator (&&) separates the two
comparisons and as you are aware in order for a logical AND operator to
return a value of true all expressions within the conditional must
evaluate to true. So if one of these comparisons making up this
compound conditional (as it is sometimes referred to as) evaluates to
false, there is no need for Processing to continue to evaluate the rest
of the conditional as the value of the conditional will invariably
equate to false. This particular comparison will only return a value of
false if the mouse's X value is less than the right edge of the slider
button.
Comparison 3:mouseY >= margin
Once again this comparison is only evaluated if the previous comparison
was true because both comparisons are separated with &&. This
comparison returns a value of true only if the mouse is below the top
of the slider button.
Comparison 4: mouseY <= margin + sliderFd.height
Another && precedes this comparison which will finally only
return true and determine if the entire compound conditional evaluates
to true if the mouse's Y value is less than the bottom of the slider
button.
Now that we have the range setup we're going to tell Processing what to
do when the conditional evaluates to true or false.
|
|