13.5 Mouse Events

Mouse events are handled in ways similar to those used with button events. Mouse events, however, are slightly more complex because there are many things that we can do with a mouse while the only thing that we can do with a button is press it.

To use a mouse, we again register a class as a listener. In order to make efficient use of system resources, there are two kinds of listener interfaces associated with mouse events: MouseListener and MouseMotionListener. Registration of a class as a listener takes a form similar to that used with button events. Implementation of the MouseListener interface requires the implementation of all of the following five methods.

Implementation of the MouseMotionListener interface requires only two methods.

The MouseEvent object e that appears as a parameter of each of these methods is supplied automatically by Java. It can be used to get a great deal of useful information about the event. We will only be using two instance methods in the MouseEvent class:

In both cases, the coordinates are given relative to the component involved in the event. Thus, clicking the mouse at the upper left hand corner of a component will produce an event with coordinates (0, 0) no matter where the component is located on the screen.

Other methods are available in the MouseEvent class to indicate which mouse button was involved in the event, to give the identifier of the component that was clicked, to indicate whether or not a double click had occurred, and so on. These are all beyond the scope of this book.

To show how mouse events work in a program, let us create a very simple drawing program that paints a small black circle at any point at which we click the mouse within a window.

Example 1

The following program will draw a filled circular region of radius 10 pixels at any point at which the mouse is clicked (within the window created by the program).
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseCircles implements MouseListener
{
   int x = -1;
   int y;
   static final int RADIUS = 10;
   Drawing draw = new Drawing();
   
   public MouseCircles()
   {
      JFrame frame = new JFrame("Mouse Droppings");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      draw.addMouseListener(this);
      frame.add(draw);
      frame.setSize(300,100);
      frame.setVisible(true);
   }
   
   public void mouseClicked (MouseEvent e)
   {
      x = e.getX();
      y = e.getY();
      draw.repaint();
   }

   public void mousePressed (MouseEvent e)
   {
   }

   public void mouseReleased (MouseEvent e)
   {
   }

   public void mouseEntered (MouseEvent e)
   {
   }

   public void mouseExited (MouseEvent e)
   {
   }
   
   class Drawing extends JComponent
   {
      public void paint(Graphics g)
      {
         if (x != -1)
            g.fillOval(x - RADIUS, y - RADIUS, 2 * RADIUS, 2 * RADIUS);
      }
   }
   
   public static void main(String[] args)
   {
      new MouseCircles();
   }
}  

Here is a typical image produced by the program. Each click of the mouse within the window produces a new circle centred at the point of the click.

There are a number of points that should be noted in this program.

  1. public class MouseCircles implements MouseListener
    The implements clause promises that the CircleFrame class contains all the methods of the MouseListener interface.
  2. int x;
    int y;

    These fields are the coordinates of the centres of the circular regions that the program draws.
  3. draw.addMouseListener(this);
    The draw object should be added to the list of objects that act as listeners to mouse clicks.
  4. public void mouseClicked (MouseEvent e)
    The mouseClicked method obtains the coordinates of the location of any mouse click (within the current component’s area) from the MouseEvent object e and then asks Java to schedule the component for painting.

    Note: to qualify as a click the mouse must not move between pressing the mouse button and releasing it. For that reason, especially if programming a game with many mouse clicks it may be preferable to use mouseReleased instead of mouseClicked

  5. mousePressed, mouseReleased, mouseEntered, mouseExited
    Although we do not want to take any action for mouse pressing, releasing, and so on, we must include all of these methods in order to implement the interface. To satisfy these requirements here, we have supplied methods (sometimes called stub methods) whose bodies contain no statements.
  6. public void paint (Graphics g)
    The paint method simply draws a filled circular region with radius given by RADIUS and centre at the most recent mouse click.

To save a lot of writing when dealing with listeners that have more than one method, Java has a number of adapter classes that implement listener interfaces in a trivial way, with stub methods. We can then create a listener by extending the adapter class with our own handler class that overrides the methods that we need with something useful and leaves the other methods alone.

To illustrate, consider the mouse listener in Example 1. Java has a class called MouseAdapter that contains trivial versions of all five methods needed by a mouse listener. The form of each of the methods in MouseAdapter is the same as four of our methods — a header with an empty body. If we extend this class and provide a useful mouseClicked method, we will have everything that we need.

As you might have expected, there are some small difficulties that we must overcome to use this idea. We create a new class as our handler and let that class extend MouseAdapter.

Creating a separate class, however, creates a new problem. We want the mouseClicked method to be able to refer to the x and y fields of the MouseCircles class and to be able to use repaint to activate the paint method that is in the Drawing class. To overcome this problem, we can create our handler class as an inner class of the MouseCircles class. As we saw in Chapter 12, inner classes have exactly the properties that we want here. The next example incorporates these ideas.

Example 2

The following code shows how we could change the program in Example 1 to avoid the need for writing stub methods in a class acting as a listener.

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

public class MouseCircles2
{
   int x = -1;
   int y;
   static final int RADIUS = 10;
   Drawing draw = new Drawing();
   
   public MouseCircles2()
   {
      JFrame frame = new JFrame("Mouse Droppings");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      draw.addMouseListener(new ClickHandler());
      frame.add(draw);
      frame.setSize(300,100);
      frame.setVisible(true);
   }
   
   class ClickHandler extends MouseAdapter
   {
      public void mouseClicked (MouseEvent e)
      {
         x = e.getX();
         y = e.getY();
         draw.repaint();
      }
   }
      
   class Drawing extends JComponent
   {
      public void paint(Graphics g)
      {
         if (x != -1)
            g.fillOval(x - RADIUS, y - RADIUS, 2 * RADIUS, 2 * RADIUS);
      }
   }
   
   public static void main(String[] args)
   {
      new MouseCircles2();
   }
} 
Now, we no longer have the clause implements MouseListener in the header of our main class. This is because the implementation of MouseListener is done in the MouseAdapter class. The constructor of the MouseCircles2 class has also been changed; it now calls the constructor of the ClickHandler class to create a new ClickHandler object and then puts that object on the mouse listener’s list of objects to be informed of mouse events.

Exercise 13.5

  1. Explain the difference between the terms.
    1. mousePressed and mouseClicked
    2. MouseListener and MouseMotionListener
    3. MouseListener and MouseAdapter
  2. Although the designers of Java created adapter classes for MouseListener and MouseMotionListener, they did not do so for ActionListener. Do you think that this was an oversight, sheer laziness, or something else? Justify your answer.
  3. Write a program that first allows the user to press the mouse at one point on the screen, move the mouse (keeping the button pressed) to another point, and then release the mouse. Once the user has done this, the program should draw the line segment that connects the two points.
  4. Write a program that allows the user to click on two points and then draws the circle that has its centre at the first point and passes through the second point.