JaVa
   

Reading Mouse Input

The mouse is probably the most important input device for PC games, especially for real-time games where reaction times are important. With Java, mouse events are easy to detect using the same methods already used to detect keyboard events earlier. The example SimpleMouse is a simple app program similar to the ones we created at the beginning of . This example implements all of the important mouse events that can occur in your program, such as the position of the mouse and button clicking information. The example shows mouse event information and also allows you to move a square shape about the window by clicking the left mouse button. The structure of this example is a little different from the SimpleKeyboard example. For starters, this example is an app, whereas SimpleKeyboard was an applet. In this example, we also create our own custom drawing class MouseMat, adding this to the main JFrame object's content pane. We also add the mouse listener to the MouseMat component instead of the main frame to illustrate how a listener can be applied to any component. This example contains two source files: SimpleMouse.java and MouseMat.java. Here is the source code for the classes SimpleMouse and MouseMat.

Code Listing 10-1: SimpleMouse.java
import java.awt.*;
import javax.swing.*;
public class SimpleMouse extends JFrame
{
 public SimpleMouse()
 {
 super("Simple Mouse Example");
 getContentPane().setLayout(null);
 setDefaultCloseOperation(EXIT_ON_CLOSE);
 setResizable(false);
 MouseMat mouseMat = new MouseMat(new Rectangle(10, 10, 380, 380));
 getContentPane().add(mouseMat);
 showToInternalSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
 validate();
 }
 public Insets showToInternalSize(int internalWidth, int
 internalHeight)
 {
 setVisible(true);
 Insets insets = getInsets();
 final int newWidth = internalWidth + insets.left +
 insets.right;
 final int newHeight = internalHeight + insets.top +
 insets.bottom;
 try
 {
 EventQueue.invokeAndWait(new Runnable()
 {
 public void run()
 {
 setSize(newWidth, newHeight);
 }
 });
 }
 catch(Exception e)
 {
 System.out.println(e);
 }
 return insets;
 }
 public static void main(String[] args)
 {
 new SimpleMouse();
 }
 private static final int DISPLAY_WIDTH = 400;
 private static final int DISPLAY_HEIGHT = 400;
}


Java End example

SimpleMouse is a basic class extending the JFrame class to create a windowed app. Here we create a window with an internal graphics component of resolution 400x400. We then create a MouseMat object with the following line of code:

MouseMat mouseMat = new MouseMat(new Rectangle(10, 10, 380, 380));


The Rectangle object parameter to the MouseMat constructor defines the location and size of the MouseMat component. The reason we create the MouseMat of this size and not at (0, 0, 400, 400) is to illustrate how the mouse listener works relative to the component to which it is added. You will understand this fact when you run the example code, and we will touch on this a little later. Before we go any further, let's take a look at the code for MouseMat.java. The code for this class is quite bulky but is designed to illustrate all of the important features of the MouseEvent object received.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MouseMat extends JComponent implements MouseListener,
 MouseMotionListener
{
 public MouseMat(Rectangle bounds)
 {
 setBounds(bounds);
 setLayout(null);
 rect = new Rectangle(getWidth()/4, getHeight()/4,
 getWidth()/2, getHeight()/2);
 addMouseListener(this);
 addMouseMotionListener(this);
 }
 public void paintComponent(Graphics g)
 {
 Graphics2D g2D = (Graphics2D)g;
 g2D.setColor(Color.cyan);
 g2D.fillRect(0, 0, getWidth(), getHeight());
 if(mouseOver) g2D.setColor(Color.red);
 else g2D.setColor(Color.blue);
 g2D.fill(rect);
 g2D.setColor(Color.black);
 g2D.drawString("You can't lose me!!!!!",rect.x+40,rect.y+100);
 g2D.drawString("Example: Simple Mouse",120,20);
 g2D.drawString("Last recorded mouse position:
 ("+mousePoint.x+","+mousePoint.y+")",80,300);
 g2D.drawString("Last click count: "+clickCount,80,315);
 String lmStr = "Last mouse press event: ";
 if(lastMouseEvent!=null)
 {
 switch(lastMouseEvent.getID())
 {
 case MouseEvent.MOUSE_PRESSED:
 lmStr+="Mouse Pressed";
 break;
 case MouseEvent.MOUSE_RELEASED:
 lmStr+="Mouse Released";
 break;
 case MouseEvent.MOUSE_CLICKED:
 lmStr+="Mouse Clicked";
 break;
 }
 }
 g2D.drawString(lmStr,80,330);
 String lmmStr = "Last mouse motion event: ";
 if(lastMouseMotionEvent!=null)
 {
 switch(lastMouseMotionEvent.getID())
 {
 case MouseEvent.MOUSE_MOVED:
 lmmStr+="Mouse Moved";
 break;
 case MouseEvent.MOUSE_DRAGGED:
 lmmStr+="Mouse Dragged";
 break;
 }
 }
 g2D.drawString(lmmStr,80,345);
 }
 public void mousePressed(MouseEvent e)
 {
 if((e.getModifiers() & MouseEvent.BUTTON1_MASK)!=0)
 {
 rect.setLocation(e.getX()-(rect.width/2),e.getY()-
 (rect.height/2));
 lastMouseEvent = e;
 repaint();
 }
 }
 public void mouseReleased(MouseEvent e)
 {
 if((e.getModifiers() & MouseEvent.BUTTON1_MASK)!=0)
 {
 lastMouseEvent = e;
 repaint();
 }
 }
 public void mouseClicked(MouseEvent e)
 {
 if((e.getModifiers() & MouseEvent.BUTTON1_MASK)!=0)
 {
 clickCount = e.getClickCount();
 lastMouseEvent = e;
 repaint();
 }
 }
 public void mouseEntered(MouseEvent e)
 {
 mouseOver = true;
 repaint();
 }
 public void mouseExited(MouseEvent e)
 {
 mouseOver = false;
 repaint();
 }
 public void mouseMoved(MouseEvent e)
 {
 mousePoint.setLocation(e.getX(), e.getY());
 lastMouseMotionEvent = e;
 repaint();
 }
 public void mouseDragged(MouseEvent e)
 {
 mousePoint.setLocation(e.getX(), e.getY());
 lastMouseMotionEvent = e;
 repaint();
 }
 private int clickCount;
 private Rectangle rect;
 private Point mousePoint = new Point(0, 0);
 private MouseEvent lastMouseEvent;
 private MouseEvent lastMouseMotionEvent;
 private boolean mouseOver;
}


When you compile and run this example, your output should be similar to the following figure. This screen shot is an illustration of when the mouse is not currently over the component, resulting in the square shape being colored blue. The mouse was clicked near the top-left corner of the component area, moving the square shape centered to that position.

Java Click To expand
Screenshot-2:

In the SimpleKeyboard example, the key listener is added to the main applet object. In this example, the mouse and mouse motion listeners are added to the MouseMat component itself. This is implemented in the constructor of MouseMat with the following code:

addMouseListener(this);
addMouseMotionListener(this);


As you can see, the MouseMat class implements the listener interfaces MouseListener and MouseMotionListener and therefore implements their respective methods. We use the MouseMat class as a canvas for displaying mouse event information. It contains a constructor, a paint method, and the mouse listener methods. The constructor first of all uses the method setBounds to set its x and y position (and also its width and height) relative to its parent SimpleMouse. The size of the component MouseMat is 380x380 pixels starting at position (10, 10), to illustrate how the mouse listeners have been added to the MouseMat component and not to the main frame SimpleMouse. When you run this example, you will see a 10-pixel gray border around the light blue MouseMat component. Try moving the mouse over this gray area, and you will see that mouse events are not registered by your program, as we are not "listening" to that area; we are listening to the MouseMat component area defined by the light blue area in the window. Note that mouse drag events continue to register with your program when the mouse is dragged out of the component area. The MouseMat class contains the rect variable, which stores the location and size for the shape that you can move around the screen by pressing the left mouse button somewhere on the MouseMat component. The rectangle's coordinates are changed when the listener method mousePressed is invoked. Here we retrieve the mouse coordinates relative to the MouseMat component from the MouseEvent e parameter (passed to mousePressed) with the methods getX and getY. Alternatively, the method getPoint returns a Point object with the coordinates. In each of the three mouse button-related methods, mousePressed, mouseReleased, and mouseClicked, we check to make sure that the button causing the event was the left mouse button with the following code:

if((e.getModifiers() & MouseEvent.BUTTON1_MASK)!=0)
{
 // Event caused by left button/button 1
}


If you want actions from any of the mouse buttons to affect the program, simply remove the if statement and its brackets, as the methods are invoked regardless of the type of button causing the event. We perform a bitwise operation on the event modifier's value with the left button mask value BUTTON1_MASK to test if the left mouse button caused the event. The field BUTTON3_MASK is the mask for the right mouse button and the field BUTTON2_MASK is the mask for the middle mouse button. We use the methods mouseEntered and mouseExited to determine when the MouseMat component has lost the mouse focus, hence the mouse is no longer pointing at the component. When this occurs, we alter the Boolean variable mouseOver accordingly, which is then used to determine the color of the moveable shape. The position of the mouse is updated when either of the mouse motion events, mouseMoved or mouseDragged, is invoked. This is because only one of these events is invoked for a particular mouse motion event and not both (e.g., when the mouse is dragged, the mouseMoved method is not invoked, just the mouseDragged method). The mouse-clicking count of the left mouse button is stored in the integer variable clickCount in the class MouseMat object, set using the method setClickCount. The click count is the amount of consecutive mouse clicks on the mouse button and is assigned its value when the method mouseClicked is invoked in the mouse listener in MouseMat. Notice that the click count is not updated when the mouse is dragged; a click count increments when the mouse is clicked within a small time frame from the occurrence of the last mouse click and without the mouse moving in that time. Also in the paint method is the use of the method getID. This is used because we have an instance of MouseEvent from which we need to extract the type of event. The return value of getID can be compared with one of the static members in MouseEvent (e.g., MOUSE_PRESSED, MOUSE_DRAGGED, etc.). If you were to add a number of components and provide one mouse listener for them all, you would need some way to determine on which component the event occurred. You can check this using the getSource method of the MouseEvent event object passed to your listener method as follows:

public void mousePressed(MouseEvent e)
{
 if(e.getSource() == myMouseMat)
 {
 }
}


We will now look at integrating mouse events with the main game loop.

JaVa
   
Comments