Introduction to Computer Graphics and Java Programming for Artists


School of the Museum of Fine Arts ::: Continuing Education

George Aroush, instructor


Lecture Eleven -- Using the Mouse; Working with Classes; Overloading


 

Readings

  1. The handouts named:
  2. Sample Programs in Batch Eleven:

 

Exercises

    Do before our next lecture

  1. Re-write one of your bouncing ball/square/object applet so that the object moves towered the mouse as the mouse is moved on the screen.
  2. Re-write any of your 2D or 3D project so that the methods that deal with the rotation, movement, scaling, etc. are now part of a class (look at BounceClass.java for an example.)

Back to the top of this page. Back to main Index

 

Using the mouse

Events

Every time we perform an action while running a Java application, such as clicking a mouse button or dragging a window, or pressing the keyboard, an event occurs. But, of course, events can also be triggered by internal actions that occur within a program. Many of the common events that occur in Java programs are handled by classes in the AWT package (java.awt.*)

Events in Java can be split into three main groups: mouse, keyboard, and system events. All of those events can be handled very similarly. For the goal of this lecture, we will focus on mouse events (we did look at keyboard event in a previous lecture.)

Mouse Event

By default, Java gives us predefined methods that are triggered when an event happens. To intercept those events we must provide (override really -- more on this in an upcoming lecture) one of the pre-defined mouse events. Java provides a number of mouse event for us to work with. In most programs we don't need them all. All of them are defined to return boolean true or false. If our applet handles the event it should then return true, otherwise it should return false. Each of those mouse event objects take three arguments. The first argument is an Event object that holds all the information about the event that has occurred. The second and third arguments are the x and y coordinates representing where the event took place.

The available methods for mouse events are:

public boolean mouseDown(Event e, int x, int y);
public boolean mouseUp(Event e, int x, int y);

Clicking on a mouse button creates two distinct events, mouseDown() and mouseUp(). The mouseDown() event occurs when a button is initially pressed and the mouseUp() event occurs when a button is released.

public boolean mouseMove(Event e, int x, int y);
public boolean mouseDrag(Event e, int x, int y);

The mouseMove() event method is used to constantly give feedback when the mouse pointer is over a component. The mouseDrag() event method tells us the same thing, but only while one of the mouse buttons is pressed.

public boolean mouseEnter(Event e, int x, int y);
public boolean mouseExit(Event e, int x, int y);

These two events come in handy for certain situations. For example, if we want to provide feedback to the user when he or she moves the mouse pointer into or out of a button, we may want to display a message in the status bar. We can get basically the same effect by checking the mouseMove() method, but this method gets called many times while the mouse is over a button and the mouseEnter() and mouseExit() methods get called only once.


Back to the top of this page. Back to main Index

 

Java's Classes and Overloading

What are classes

Classes are the building blocks of a Java application. A class contains methods and variables; it serves as a blueprint for making class instances, which are run-time objects that implement the class structure. We declare a class with the class keyword. Methods and variables of the class appear inside the braces of the class declaration:

class Pendulum
{
    float mass;
    float length = 1.0f;
    int   cycles;          // some variables in a class

    float Position(float time)  // a method in the class
    {
        ....
    }
    ....
}

The above class contains three variables and one method. Variable and method declarations can appear in any order, but variable initializes can't use forward references to uninitialized variables.

Now that we have defined the Pendulum class, we can create an actual Pendulum object as follows:

Pendulum p;
p = new Pendulum();

The declaration of the variable p does not create a Pendulum object; it simply creates a variable that refers to an object of type Pendulum. We still have to create the object dynamically, using the new keyword. Now that we've created a Pendulum object, we can access its variables and methods:

p.mass = 5.0;
float pos = p.Position(1.0f);

This should be familiar as it look similar to the way we created a Color object. Just like the color object we can create more then one Pendulum object:

Pendulum a, b;

a = new Pendulum();
b = new Pendulum();

a.mass = 10.0f;
float posA = a.Position(1.1f);

b.mass = 3.0f;
float posB = b.Position(2.0f);

In this example we have two objects of type Pendulum: a and b which we can use for calculating the position independently.

Accessing Members

Inside of a class, we can access instance variables and call instance methods of the class directly by name. Here's an example that expands upon our Pendulum:

class Pendulum
{
    float mass;
    float length = 1.0f;
    int   cycles;           // some variables in a class

    float Position(float time)  // a method in the class
    {
        ....
    }

        // note how this method can access everything
        // inside the class that it belongs to.
    void  ResetEverything()
    {
        cycles = 0;
        mass = 1.0f;

        float startingPosition = Position(0.0);
    }
}

Other classes access members of an object through a reference using the dot notation:

class TextBook
{
    void Showendulum()
    {
        Pendulum bob;
        int      i;

        bob = new Pendulum();
        i = bob.cycles;
        bob.ResetEverything();
        bob.mass = 1.01f;
    }
}

Here we created a second class, TextBook (more about creating new class later) that uses a Pendulum object. It creates an instance in ShowPendulum() and then invokes methods and accesses variables of the object through the reference bob.

Class member access control

Several factors affect whether class members can be accessed from outside the class. We can use the visibility modifiers, public, private and protected to restrict access. The private modifier designates a variable or method for use only by other members inside the class itself. In the previous example, we could change the declaration of our variable cycles to private:

class Pendulum
{
    ....
    private int cycles;
    ....
}

Now we can't access cycles from TextBook:

class TextBook
{
    ....
    void ShowPendulum()
    {
        ....
        i = bob.cycles;    // ERROR: compile time error
        ....
    }
}

The same can be done to the method Position() in the class Pendulum. In a class we can mix and match between private and public as follows:

class Pendulum
{
        // only 'cycles' can be accessed outside this class
    private float mass;
    private float length = 1.0f;
    public  int   cycles;

        // this method is accessible by outsiders
    public float Position(float time)
    {
        ....
    }

        // this method is not accessible by outsiders
    private void  ResetEverything()
    {
        cycles = 0;
        mass = 1.0f;

        float startingPosition = Position(0.0);
    }
}

In this example we used the keywords private and public to selectively define areas in the class Pendulum to be private or public. Regarding the protected keyword, we will look at it at a later lecture.

Local Variable Initialization

Unlike instance variables (variables declared at a class level) local variables must be initialized before they can be used. It's a compile-time error to try to access a local variable without first assigning it a value:

class Pendulum
{
    float   mass;           // declare 'mass' and assign it 0.0f (the default)
    float   length = 1.0f;  // declare 'length' and assign it 1.0f
    int     cycles;         // declare 'cycles' and assign it 0 (the default)

    void    ResetEverything()
    {
        int     foo = 42;   // declare and then assign 42 to 'foo'
        int     bar;        // just declare 'bar'

        bar += 1;      // ERROR: compile time error

        bar = 99;
        bar += 1;      // OK

        mass += 1.0;   // OK, 'mass' by default was assigned 0.0f
        length += 0.1; // OK, 'length' was assigned 1.0f during declaration
    }
}

Note that this doesn't imply local variables have to be initialized when declared, just that the first time they are referenced must be in an assignment.

Method Overloading

Method overloading is the ability to define multiple methods with the same name in the same class; when the method is invoked, the compiler picks the correct one based on the arguments passed to the method. This implies, of course, that overloaded methods must have different numbers or types of argument. The idea is to create methods that act in  the same way on different types of arguments and have what appears to be a single method that operates on any of the types:

public class MyClass extends java.applet.Applet
{
    void    Test()
    {
        int     i;
        float   f;

        i = Random(10);       // calls the int version
        f = Random(0.9f);     // calls the float version
        i = Random(20, 30);   // the the range version
    }

        // will give us back random ints
    int     Random(int r)
    {
        ....
    }

        // will give us random floats
    float   Random(flaot r)
    {
        ....
    }

        // will give us random numbers ranging from a to b
    int     Random(int a, int b)
    {
    }
}

In this example, we have the class MyClass that has in it three methods with the same name. What makes them different is the argument that they take. One takes float while the other takes int and a third takes two ints. Note that, if two that take one argument were taking an int argument (or a float) and they only differ in the return type (one returns float while the other returns int) then the compiler will give us an error as Java doesn't support return type overloading.


Back to the top of this page. Back to main Index

 

Sample Programs -- Batch Eleven

MouseOne.java

/*
 *  Program:    MouseOne.java
 *  Purpose:    Mouse example
 *  Author:     George Aroush
 *  Date:       1/1/1998
 *  Change Log: None
 *
 *  Full description of Program:
 *      A very simple example of how to use the mouse to draw connect lines
 *      as the user moves the mouse on the screen a clicks.
 */

import java.applet.*;
import java.awt.*;

public class MouseOne extends Applet
{
    int     mouseXPos, mouseYPos;
    int     mouseXPosOld, mouseYPosOld;

        /* we will use the init() method to setup */
        /* few thing for our program */
    public void     init()
    {
        mouseXPos = -1;
        mouseYPos = -1;
    }

        /* we can't use paint() because update() calls paint */
        /* AFTER when it has erased the screen which is the */
        /* default behavior of the update() method so here */
        /* we will over-ride the update method to prevent it */
        /* from cleaning the previous image */
    public void update(Graphics g)
    {
        g.drawLine(mouseXPosOld, mouseYPosOld, mouseXPos, mouseYPos);
    }

        /* any time the mouse button is pressed down this */
        /* method is called with the location of the mouse */
        /* on the screen; the location of the mouse is */
        /* stored inside 'x' and 'y' respectively */
    public boolean  mouseDown(Event evt, int x, int y)
    {
            /* for the first click we make the mouse */
            /* click nothing but a pixel drawing */
        if (mouseXPos == -1)
            mouseXPos = x;
        if (mouseYPos == -1)
            mouseYPos = y;

            /* remember the old location of the mouse */
        mouseXPosOld = mouseXPos;
        mouseYPosOld = mouseYPos;

            /* record the new location of the mouse */
        mouseXPos = x;
        mouseYPos = y;

            /* so that the update method gets called */
        repaint();

        return (true);
    }
}

MouseOne.htm

<html>
<head>
<title>MouseOne</title>
</head>
<body>
    <hr>
    <applet code=MouseOne width=640 height=480></applet>
    <hr>
</body>
</html>

MouseTwo.java

/*
 *  Program:    MouseTwo.java
 *  Purpose:    Mouse example
 *  Author:     George Aroush
 *  Date:       1/1/1998
 *  Change Log: None
 *
 *  Full description of Program:
 *      Using the mouse to draw and then move objects on the screen.
 */

import java.applet.*;
import java.awt.*;

public class MouseTwo extends Applet
{
    final int   X_DONE = 550;   /* define "Done" box: starting position */
    final int   Y_DONE = 410;

    final int   B_WIDTH = 39;   /* define "Done" box: size */
    final int   B_HEIGHT = 15;

    final int   MAX_PTS	= 1000; /* define how big the array will be */

    final int   X = 0;          /* define the X part of 2D array */
    final int   Y = 1;          /* define the Y part of 2D array */

    int         mouseXPos, mouseYPos;
    int         mouseXPosOld, mouseYPosOld;

    int         xy[][];     /* the array to hold our object */
    int         count;      /* how many points are in the array */
    boolean     first;      /* indicates that this is the very first pixel */
    boolean     done;       /* set to true when the user clicks inside the 'done' box */


    /* 
     *  void    init()
     *
     *  we will use the init() method to setup
     *  few thing for our program 
     */
    public void     init()
    {
        xy = new int[MAX_PTS][2];
        count = 0;
        first = true;
        done = false;

        mouseXPos = -1;
        mouseYPos = -1;

        repaint();
    }


    /*
     *  void update()
     *
     *  This is where our action will take place
     */
    public void update(Graphics g)
    {
        int     i, x1, y1, x2, y2;
        int     xOffset, yOffset;

        if (first == true)
        {
            g.drawRect(X_DONE, Y_DONE, B_WIDTH, B_HEIGHT);
            g.drawString("DONE", X_DONE + 4, Y_DONE + 12);

            first = false;
        }
        else
        {
                /* if the mouse was not clicked inside the rectangle, */
                /* do more drawings as long as we have room to store */
                /* the new drawing in our array */
            if (!InBox(mouseXPos, mouseYPos, X_DONE, Y_DONE, B_WIDTH, B_HEIGHT) && 
                count < MAX_PTS &&
                done == false)
            {
                    /* save x and y from mouse_x and mouse_y */
                xy[count][X] = mouseXPos;
                xy[count][Y] = mouseYPos;

                count++;        /* increment the array index */

                g.drawLine(mouseXPosOld, mouseYPosOld, mouseXPos, mouseYPos);

                g.fillOval(mouseXPos, mouseYPos, 2, 2);     /* fatten point */
            }
            else
            {
                    /* we can make it follow the mouse */
                done = true;

                g.clearRect(0, 0, 640, 480);

                xOffset = xy[0][X];
                yOffset = xy[0][Y];

                for (i = 1; i < count; i++)
                {
                    x1 = xy[i - 1][X] - xOffset;
                    y1 = xy[i - 1][Y] - yOffset;
                    x2 = xy[i][X] - xOffset;
                    y2 = xy[i][Y] - yOffset;

                    x1 += mouseXPos;
                    y1 += mouseYPos;
                    x2 += mouseXPos;
                    y2 += mouseYPos;

                    g.drawLine(x1, y1, x2, y2);
                }
            }
        }
    }


    /* 
     *  boolean mouseDrag()
     *
     *  Deals with mouse-drag event
     */
    public boolean  mouseDrag(Event evt, int x, int y)
    {
            /* for the first click we make the mouse */
            /* click nothing but a pixel drawing */
        if (mouseXPos == -1)
            mouseXPos = x;
        if (mouseYPos == -1)
            mouseYPos = y;

            /* remember the old location of the mouse */
        mouseXPosOld = mouseXPos;
        mouseYPosOld = mouseYPos;

            /* record the new location of the mouse */
        mouseXPos = x;
        mouseYPos = y;

            /* so that the update method gets called */
        repaint();

        return (true);
    }


    /*
     *	boolean InBox()
     *
     *	Makes a check and returns 1 if (x, y) are in box bounded by (bx, by) & (bx + w, by + h)
     */
    boolean InBox(int x, int y, int bx, int by, int w, int h)
    {
        if ( x >= bx && x <= (bx + w) && y >= by && y <= (by + h) )
            return (true);      /* in the boundary */
        else
            return (false);     /* sorry, not in the boundary */
    }
}

MouseTwo.htm

<html>
<head>
<title>MouseTwo</title>
</head>
<body>
    <hr>
    <applet code=MouseTwo width=640 height=480></applet>
    <hr>
</body>
</html>

BounceClass.java

/*
 *  Program:    BounceClass.java
 *  Purpose:    Class creation
 *  Author:     George Aroush
 *  Date:       1/1/1998
 *  Change Log: None
 *
 *  Full description of Program:
 *      Shows how to create our own class
 */

import java.applet.*;
import java.awt.*;

public class BounceClass extends Applet
{
    final int   NUM_OF_OBJECTS = 1000;
    Bounce      a[];

    public void init()
    {
        Randomizer  rand = new Randomizer();
        int         i;

            /* creates 1000 empty objects of type */
            /* 'Bounce' in the array 'a' */
        a = new Bounce[NUM_OF_OBJECTS];

            /* initialize each object in the array */
        for (i = 0; i < NUM_OF_OBJECTS; i++)
        {
            a[i] = new Bounce();    /* makes each object */
            a[i].init(rand.Random(10) - 5, rand.Random(10) - 5, rand.Random(10));
        }
    }

    public void paint(Graphics g)
    {
        int     i, j;

            /* move each object one at a time */
        for (i = 0; i < 1000; i++)
        {
            g.clearRect(0, 0, 640, 480); 

            for (j = 0; j < NUM_OF_OBJECTS; j++)
                a[j].paint(g);
        }
    }
}


/*--------------------------------------------------------------------------*/
/*  This class will deal with all aspects of moving a square on the screen  */
/*  bouncing it off the four sides                                          */
/*--------------------------------------------------------------------------*/
class Bounce
{
    int     x;
    int     y;
    int     xSpeed, ySpeed, side;
    int     count = 0;

    /*
     *  void    init()
     *
     *  Initializes the object and sets things up
     */
    void init(int xs, int ys, int s)
    {
        Randomizer  rand = new Randomizer();

        xSpeed = xs;
        ySpeed = ys;
        side = s;

        x = rand.Random(640);
        y = rand.Random(480);
    }

    /*
     *  void    paint()
     *
     *  Deals with the logic of moving, bouncing and drawing the object
     */
    void paint(Graphics g)
    {
            /* draw the square only if it is on the screen */
            /* if it is 'true' that x is to the right of */
            /* the left AND is at least the square's size */
            /* away from the right edge */ 

        if (x < 0 || x > 639 - side)
            xSpeed = -xSpeed;               /* reverse direction, without drawing yet */ 

        if (y < 0 || y > 479 - side)      /* same as above but now for y */
            ySpeed = -ySpeed;

        g.fillRect(x, y, side, side);

        x = x + xSpeed;      /* move the square */ 
        y = y + ySpeed;      /* move the square */ 
    }
}


/*--------------------------------------------------------------------------*/
/*  This class will deal random number generation.                          */
/*--------------------------------------------------------------------------*/
class   Randomizer
{
    /*
     *  int Random()
     *
     *  Gives us back random numbers
     */
    int Random(int range)
    {
        return ((int) (Math.random() * range));
    }
}

BounceClass.htm

<html>
<head>
<title>BounceClass</title>
</head>
<body>
    <hr>
    <applet code=BounceClass width=640 height=480></applet>
    <hr>
</body>
</html>

Back to the top of this page. Back to main Index.