Title: Spots
Course: CPS 161: An Intro to Programming with Java - DL MM MASTER

User Interfaces: Mouse and Key

Spots Programs

In this set of notes, we are going to try to provide some insight into the paint routine. To do so, we need to introduce you to the Interfaces associated with Mouse Activity. We will look at Listener interfaces in more detail in a later set of notes. We are going to create a series of simple programs that allow you to click and see spots drawn in the spot where you clicked.

MouseListener Interface -

Think back to how we did the ActionListener Interface and many of the steps are similar:

1. First we need a class which implements the desired Interface which is MouseListener for now. The easiest class to work with is our top level Spots class that is derived from Applet. So we add the claim in defining Spots:
implements MouseListener
2. Now that our class implements an interface, we are obligated to add all of the methods that go with this interface. This interface has 5 methods, which we add even though we only want to work with one of them.
3. We actually put some code into MousePressed. The other 4 routines are empty.
4. We need to tell someone to give us MouseListener calls. We end up telling the Component class that is underneath our Spots derived Applet class. We do this with the call
addMouseListener(this); // pass point to this class
5. In the MousePressed routine we receive an instance of MouseEvent. This class has all of the information available about the mouse activity. What we want to know is the location where the Mouse was pressed. To get this information call the getX, and getY methods on the MouseEvent.
6. We store the location of the mouse press in a global Point variable called clickPoint. This class mostly just stores and x and a y location.
7. Now how do we get the paint routine called. We can't just call paint. To do that we would have to create a Graphics class and we don't have enough system information to do this. Note that the Graphics class is abstract, which means that something in the system needs to fill in some holes.
8. The proper way to do it is to call the repaint() method. This tells the system that we want the system to generate a paint call.
9. It is quite instructive to convert this to JApplet to see what happens. Make the conversion without adding the "Clear the screen" code.

Spots.java

Click in the following applet

Spots Applet


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

public class Spots extends Applet
        implements MouseListener{
    Point clickPoint=new Point(-1,-1);
    int radius = 7;

    public void init()
    {
    // Our Applet is a Component.  We want to register it to
    // fire MouseEvents according to the MouseListener interface
    // The class which will handle this interface in the Applet itself.
    // This implies our applet must implement the MouseListener interface.

       addMouseListener(this);
    }

    public void paint(Graphics g)
    {
       // find out how big our drawing area is
       int w = getSize().width;
       int h = getSize().height;
       // Make a red spot
       Color color = new Color(1.0f, 0.0f, 0.0f);

       g.drawRect(0,0,w -1, h -1); // draw boundary

       if (clickPoint.x >= 0)
       {
          g.setColor(color);
          g.fillOval(clickPoint.x - radius,    clickPoint.y - radius,
                    2*radius, 2*radius);
       }
    }
    public void mousePressed(MouseEvent e)
    {
       clickPoint.x = e.getX();
       clickPoint.y = e.getY();
       // Note that nothing happens unless I tell java to repaint my screen
       repaint();
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
}


Spots2.java

Cover artwork and then uncover artwork

Spots2 Applet

This example is almost the same as Spots except for:

1. For fun, I decided to create random colors for the spots --- Red spots are just too boring.
2. The most significant change however, is overriding the update method of the Component class. Note that we keep drawing new spots.
3. I lied a little bit above. It turns out that repaint is actually a request to the system to call the update method. The normal update method in the Component class clears the whole screen and then calls paint.
4. By overriding update, we avoided clearing the screen --- we just had update call paint only.
5. Create a bunch of spots and then cover your window with any other window (like a PAD window). Then uncover your spots and you will see that Spots2.java should only remember one spot(last one) out of your collection.


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

public class Spots2 extends Applet
    implements MouseListener{
Point clickPoint=new Point(-1,-1);
int radius = 7;

public void init()
    {
       addMouseListener(this);
    }


public void paint(Graphics g)
{
    int w = getSize().width;
    int h = getSize().height;

    // For fun, let's use a random color for each new spot
    Color color = new Color(
        (float)Math.random(), (float)Math.random(), (float)Math.random());

    g.drawRect(0,0,w -1, h -1);

    if (clickPoint.x >= 0)
    {
        g.setColor(color);
        g.fillOval(clickPoint.x - radius,    clickPoint.y - radius,
                    2*radius, 2*radius);
    }
}

// We will override the normal update routine which would clear the
// screen on each repaint operation before calling paint.

    public void update(Graphics g)
    {
       paint(g);
    }

    public void mousePressed(MouseEvent e)
    {
       clickPoint.x = e.getX();
       clickPoint.y = e.getY();
       // Note that nothing happens unless I tell java to repaint my screen
       repaint();
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
}



Spots3.java

Click and Drag

Spots3 Applet

More for fun than anything else, we want to add another Interface. We want to be able to drag our mouse and get a brush effect. Note that we have removed the Vector class that stored our Data, so we won't be able to redraw our screen after it is covered.

Adding the MouseMotionListener interface gives us the Mouse Drag information. We add it the same way as MouseListener. See if you can pick out the steps.

Note that we only change colors on a click, on a drag we just note a new location and keep redrawing points.


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


public class Spots3 extends Applet
       implements MouseListener, MouseMotionListener{
Point clickPoint=new Point(-1,-1);
int radius = 7;
Color color;

public void init()
{
    // MouseMotionListener interface gives us the Drag capability

    addMouseListener(this);
    addMouseMotionListener(this);
}
public void paint(Graphics g)
{
    int w = getSize().width;
    int h = getSize().height;


    g.drawRect(0,0,w -1, h -1);

    if (clickPoint.x >= 0)
    {
        g.setColor(color);
        g.fillOval(clickPoint.x - radius,    clickPoint.y - radius,
                    2*radius, 2*radius);
    }
}

// We will override the normal update routine which would clear the
// screen on each repaint operation before calling paint.

public void update(Graphics g)
{
    paint(g);
}

// ---------------------------
// Routines needed for the MouseListener Interface
// ---------------------------
public void mousePressed(MouseEvent e)
{
    clickPoint.x = e.getX();
    clickPoint.y = e.getY();
    color = new Color(
        (float)Math.random(), (float)Math.random(), (float)Math.random());
    System.out.println("Color = " + color);

    // Note that nothing happens unless I tell java to repaint my screen
    repaint();
}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
// ---------------------------
// Routines needed for the MouseMotionListener Interface
// ---------------------------
public void mouseDragged(MouseEvent e)
{
    clickPoint.x = e.getX();
    clickPoint.y = e.getY();
    // Note that nothing happens unless I tell java to repaint my screen
    repaint();
}
public void mouseMoved(MouseEvent e){} // part of MouseMotionListener

}



Preview to Data Structures work

The ArrayList class gives you the equivalent of an array of objects which can expand dynamically on a need basis. You don't need to know how large your array is going to need to be.


import java.util.*;

class List1
{
    public static void main(String[] args)
    {
        ArrayList list = new ArrayList();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        // ....
        for (int i=0; i < list.size(); i++)
        {
            String str = (String)list.get(i);
            System.out.println(str);
        }
    }
}


Generics Version of the above example


import java.util.*;

class List2
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        // ....
        for (int i=0; i < list.size(); i++)
        {
            // Note no need for Caste (String)
            String str = list.get(i);
            System.out.println(str);
        }
    }
}


Spots2save.java

Note we are going to use JApplet for the rest of the applets on this page:

Click to make points in the following applet, Cover artwork and then uncover artwork

Spots2save Applet

If we really care about spots being repainted after our window is covered, we need to remember the spots in some collection class.

We create a Helper Data class to store the location of the point and the Color of the spot. Everytime we click, we just store another Data class into our Vector class.

We still call repaint and in our paint method we redraw all spots stored in the Vector class.

The should work in all browsers if this window is the active one page in the browser. In otherwords, you are covering the applet with some other window and then uncover the applet.


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

// Class to save Spot Data
class Data
{
    Point p;
    Color c;

    Data(Point p1, Color c1)
    {
        p=p1;
        c=c1;
    }
}

public class Spots2save extends JApplet
    implements MouseListener{
  int radius = 7;

  // Storage to save our Spot Data
  ArrayList arrsave=new ArrayList();

  public void init()
    {
       addMouseListener(this);
    }

  public void paint(Graphics g)
  {
    int w = getSize().width;
    int h = getSize().height;
    Data d;

    g.setColor(Color.white);
    g.fillRect(0,0,w-1,h-1); // clear screen
    g.setColor(Color.black);
    g.drawRect(0,0,w -1, h -1);

    // Paint all spots
    for (int i=0; i < arrsave.size(); i++)
    {
        //d = (Data)arrsave.get(i);  // Not supported in I.E.
        d = (Data)arrsave.get(i);
        g.setColor(d.c);
        g.fillOval(d.p.x - radius,    d.p.y - radius,
                    2*radius, 2*radius);
    }
  }

  public void mousePressed(MouseEvent e)
    {
       int x = e.getX();
       int y = e.getY();
       Point p = new Point(x,y);

       Color color = new Color(
            (float)Math.random(), (float)Math.random(), (float)Math.random());
       Data d = new Data(p, color);

       // Add a new Spot to the Data collection
       arrsave.add(d);

       // Note that nothing happens unless I tell java to repaint my screen
       repaint();
    }

   public void mouseClicked(MouseEvent e) {}
   public void mouseEntered(MouseEvent e) {}
   public void mouseExited(MouseEvent e) {}
   public void mouseReleased(MouseEvent e) {}
}




Keys.java

Click and type keys (including backspace)

Keys Applet


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Keys extends JApplet
        implements KeyListener{

    String keysEntered="";

    public void keyPressed(KeyEvent e)
    {
    }
    public void keyReleased(KeyEvent e)
    {
    }
    public void keyTyped(KeyEvent e)
    {
        if(e.getKeyChar() ==  KeyEvent.VK_BACK_SPACE)
        {
           // Ensure it's not empty:
           if( keysEntered.length() > 0)
           {
               keysEntered = keysEntered.substring(0, keysEntered.length() - 1);
           }
        }
        else
        {
            keysEntered += e.getKeyChar();
        }
        repaint();
    }

    public void init()
    {
       addKeyListener(this);
    }

    public void paint(Graphics g)
    {
       Dimension d = getSize();
       g.setColor(Color.yellow);
       g.fillRect(0,0,d.width, d.height);

       g.setColor(Color.black);
       g.drawString(keysEntered, 10,50);
    }


}




Inner Classes, Adapter classes and Anonymous classes

Some standard Java features are easily demonstrated with the simple Spots program.

Inner Classes

One Java feature that that fits well with the JDK event model is the notion of Inner Classes. An Inner Class is a class that is defined inside of an existing class. The inner class is only accessable to the class containing the inner class. Also the inner class has access to all of the member variables in its containing class. We will redo the Spots program again using an inner class.

SpotsInner


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SpotsInner extends JApplet
{
    Point clickPoint=new Point(-1,-1);
    int radius = 7;

// ****************************************************
//   INNER CLASS

    class MouseStuff implements MouseListener
    {
        public void mouseClicked(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e) {}
        public void mouseReleased(MouseEvent e){}

        // Finally the one routine we really use in this Interface
        public void mousePressed(MouseEvent e)
        {
// Note how this Inner class has access to all of the characteristics of
// the outer class which contains this inner class
            clickPoint.x = e.getX();
            clickPoint.y = e.getY();
            // Note that nothing happens unless I tell java to repaint my screen
            repaint();
        }
    }
 // ****************************************************


    MouseStuff mouse_stuff=new MouseStuff();


    public void init()
    {
        addMouseListener(mouse_stuff);
    }

    public void paint(Graphics g)
    {
        int w = getSize().width;
        int h = getSize().height;
        g.setColor(Color.yellow);
        g.fillRect(0,0, w-1, h-1);
        g.setColor(Color.black);

        g.drawRect(0,0,w -1, h -1);

        Color color = new Color(1.0f, 0.0f, 0.0f);

        if (clickPoint.x >= 0)
        {
            g.setColor(color);
            g.fillOval(clickPoint.x - radius,    clickPoint.y - radius,
                    2*radius, 2*radius);
        }
    }
}


Note that instead of having the Applet class implement the MouseListener class, we create another class called MouseStuff inside the Applet. Note that now we have to create an instance of this class and pass the instance to the addMouseListener routine. Also note that when you compile this source file you will see 2 class files. If you put this on your web site, you would need to put both class files on your web site.

Adapter Classes

Suppose that when you are interested in dealing with the MouseListener interface, you don't like the fact that you have to add 5 routines to your class, when you really only care about one of the routines. In this case you might be interested in the Adapter classes that are associated with all of the Listener interfaces with more than one routine.

Take another look at the AWT Listeners Information table. Note that all of the listener interfaces that have more than one routine also have Adaper routines. An Adapter class is a class that implements a given interface and has all of the required routines implemented as do nothing type routines. This means that if we create an Inner class derived from an Adapter class and override only the routine we want, we won't have to look at all of the other routines that we want to ignore.

SpotsAdapter


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SpotsAdapter extends JApplet
{
    Point clickPoint=new Point(-1,-1);
    int radius = 7;

// ****************************************************
//   INNER CLASS

    class MouseStuff extends MouseAdapter
    {
       // Note that we don't need don't need to specify any of the methods that
       // we don't care about.  The MouseAdapter has already implemented all
       // methods in the Interface as dummy routines.

       // We just override the methods we really care about.

        public void mousePressed(MouseEvent e)
        {
            clickPoint.x = e.getX();
            clickPoint.y = e.getY();
            // Note that nothing happens unless I tell java to repaint my screen
            repaint();
        }
    }
 // ****************************************************


    MouseStuff mouse_stuff=new MouseStuff();


    public void init()
    {
        addMouseListener(mouse_stuff);
    }

    public void paint(Graphics g)
    {
        int w = getSize().width;
        int h = getSize().height;

        g.setColor(Color.yellow);
        g.fillRect(0,0, w-1, h-1);
        g.setColor(Color.black);

        Color color = new Color(1.0f, 0.0f, 0.0f);

        g.drawRect(0,0,w -1, h -1);

        if (clickPoint.x >= 0)
        {
            g.setColor(color);
            g.fillOval(clickPoint.x - radius,    clickPoint.y - radius,
                    2*radius, 2*radius);
        }
    }
}




Note that MouseStuff is now an inner class derived from MouseAdapter. MouseAdapter takes care of all of the routines that we have no interest in. In MouseStuff we override only the routines we care about.

Anonymous Classes

Another variation on the Inner Class theme is to create a class that is defined in place and never really given any name. I personally think that Anonymous Classes are a little hard to read, but you may encounter this technique in some other book, so it's good to be aware of it.

SpotsAnonymous


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SpotsAnonymous extends JApplet
{
    Point clickPoint=new Point(-1,-1);
    int radius = 7;

    public void init()
    {
    // Anonymous class created here
        addMouseListener(
            new MouseAdapter()
            {
                public void mousePressed(MouseEvent e)
                {
                    clickPoint.x = e.getX();
                    clickPoint.y = e.getY();
                    repaint();
                }  //end of mousePressed routine
            } // end of Anonymous Class definition
        ); // end of addMouseListener call
    }

    public void paint(Graphics g)
    {
        int w = getSize().width;
        int h = getSize().height;

        g.setColor(Color.yellow);
        g.fillRect(0,0, w-1, h-1);
        g.setColor(Color.black);

        Color color = new Color(1.0f, 0.0f, 0.0f);

        g.drawRect(0,0,w -1, h -1);

        if (clickPoint.x >= 0)
        {
            g.setColor(color);
            g.fillOval(clickPoint.x - radius,    clickPoint.y - radius,
                    2*radius, 2*radius);
        }
    }
}


Exercises:

1. Create the following program:
SpotLines.java
2. Update your Hangman program to use a GUI
3. Update your Tic Tac Toe game to use a GUI
4. Simple Click and Draw Exercise
In this exercise, put together a simple applet that draws a new line with each mouse click. On the first click , you just need to save the clicked location. For the second, third, fourth, etc. clicks you should draw the following lines:
* line connecting first click to the second click
* line connecting second click to the third click
* line connecting third click to the fourth click
* etc.
Your program should save it's points so that if you navigate to another page and come back, your drawing is still in place. Take a look at the Spots examples for clues. If you want to have more of a challenge, add colors to your line drawing program. Create some colored boxes that allow you to select your desired drawing color.
5. Create a drawing program. Use the MouseMotionListener, MouseListener, and KeyListener interface. When the user enters the key "o", "r", "l" we will draw ovals, rectangles, lines respectively.
6. Take the 2D button created in the previous section and make it respond to Mouse clicks. Make the button respond like a toggle. When you click on it it toggles between raised and depressed.
7. Create a Check box class that draws a check box and responds to mouse clicks.
8. Create a Radio box class that draws a radio button and responds to mouse clicks.
9. Create a text field box that allows you to enter in text in it.
10. Remember the dot game that you played when you were young. See if you can create a small subset of it that draws lines between an array of dots. If you are ambitious consider completing the dot game program.
11. Have you ever played battleship. Create a small part of battleship which detects which square you clicked in from a grid. If you are ambitious consider writing a complete battleship game.

Last Updated: April 2, 2008 10:52 AM