Mouse Interfaces
Java supports a very rich set of methods to handle mouse events, and these are divided into two different interfaces. The MouseListener interface specifies 5 methods that deal with mouse button clicks and keeping track of when the mouse enters or exits a component. The MouseMotionListener interface specifies 2 methods that focus on mouse movement.
Here is a summary of the abstract methods in each interface class:
Because these are interface classes, once you agree to implement them in your code you must provide code for all of the methods that they each provide, even if that means you are only providing empty curly braces { .. }.
Time for an example! The code below demonstrates all 7 of the mouse handling methods specified by the MouseMotionListener and MouseListener interfaces. To implement more than one interface class you simply separate them with a comma (,) as shown on line 33.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
import java.awt.Color; import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseEvent; public class MouseTrackerFrame extends JFrame { private JPanel mousePanel; private JLabel statusBar; public MouseTrackerFrame() { super( "Demo of ALL Mouse Events" ); // We'll update the statusBar JLabel as mouse events occur statusBar = new JLabel( "Mouse Outside JPanel" ); add( statusBar, BorderLayout.SOUTH ); // We will track mouse events on a JPanel mousePanel = new JPanel(); mousePanel.setBackground( Color.WHITE ); add( mousePanel, BorderLayout.CENTER ); // Create and register listener for mouse and mouse motion events MouseEventListener mousePanelListener = new MouseEventListener(); mousePanel.addMouseListener( mousePanelListener ); mousePanel.addMouseMotionListener( mousePanelListener ); } // Inner class to handle 7 possible mouse events class MouseEventListener implements MouseListener, MouseMotionListener { // These 5 methods override those in MouseListener interface // handle event when mouse released immediately after press @Override public void mouseClicked( MouseEvent event ) { statusBar.setText( String.format( "Clicked at [%d, %d]", event.getX(), event.getY() ) ); } // handle event when mouse pressed @Override public void mousePressed( MouseEvent event ) { statusBar.setText( String.format( "Pressed at [%d, %d]", event.getX(), event.getY() ) ); } // handle event when mouse released after dragging @Override public void mouseReleased( MouseEvent event ) { statusBar.setText( String.format( "Released at [%d, %d]", event.getX(), event.getY() ) ); } // handle event when mouse enters JPanel @Override public void mouseEntered( MouseEvent event ) { statusBar.setText( String.format( "Mouse entered at [%d, %d]", event.getX(), event.getY() ) ); mousePanel.setBackground( Color.GREEN ); } // handle event when mouse exits JPanel @Override public void mouseExited( MouseEvent event ) { statusBar.setText( "Mouse outside JPanel" ); mousePanel.setBackground( Color.WHITE ); } // These 2 methods override those in MouseMotionListener interface // handle event when user drags mouse with button pressed @Override public void mouseDragged( MouseEvent event ) { statusBar.setText( String.format( "Dragged at [%d, %d]", event.getX(), event.getY() ) ); } // handle event when user moves mouse @Override public void mouseMoved( MouseEvent event ) { statusBar.setText( String.format( "Moved at [%d, %d]", event.getX(), event.getY() ) ); } } } |
In this example we are using the JFrame default BorderLayout manager, and placing a JPanel widget in the center region, and a status JLabel in the south.
Our inner class for event handling starts on line 33. Because the MouseEventListener class that we are defining implements both MouseListener and MouseMotion listener we’ll need to implement 7 methods in total. Those methods follow in the body of the class.
In each case, they update the message in the south statusBar to reflect the event. Notice also the use of getX() and getY() from the MouseEvent object passed into each method when that event occurs. Finally, in the case of mouseEntered() and mouseExited() we are also changing the background colour of the JPanel.
Here is a test class:
1 2 3 4 5 6 7 8 9 10 11 |
import javax.swing.JFrame; public class MouseTrackerTest { public static void main( String[] args ) { MouseTrackerFrame appWindow = new MouseTrackerFrame(); appWindow.setSize( 300, 200 ); appWindow.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); appWindow.setVisible( true ); } } |
For convenience, Java 1.5 (and later) include a Swing interface class called MouseInputListener which includes all of the same MouseListener and MouseMotionListener abstract methods (in package javax.swing.event), so you can implement one interface class instead of two if you like. You would still need to provide code for 7 methods though.
MouseAdapter Class
Let’s say in the example above that we only care about MouseClicked() events. Even if we only implemented the MouseListener interface this still means we need to define 5 methods, 4 of which will have empty method bodies { .. }. All of these empty method bodies reduce program readability, and are generally a nuisance to type out all the time! If only there was a better way…
There is! For many event listener interfaces that have multiple methods, the Java API provides what are called adapter classes to simplify code. What an adapter class does is it implements all of the methods of an interface class, each with an empty method body { .. }. An adapter class is not an interface class, it’s a regular class, so instead of implementing an adapter class you inherit from it.
Think about what this means. Since we are inheriting from the adapter class (which has already implemented all of an interface class’s methods, providing empty bodies) we only need to override the method(s) that we really need for our event handling. Very clever!
Let’s see how this works in the case of tracking MouseClicked() events only.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
import java.awt.Color; import java.awt.Graphics; import java.awt.BorderLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; public class MouseDetailsFrame extends JFrame { private JLabel statusBar; private JPanel mousePanel; public MouseDetailsFrame() { super( "Demo of ONLY mouseClicked Event" ); // We'll update the statusBar JLabel as mouse events occur statusBar = new JLabel( "Mouse Outside JPanel" ); add( statusBar, BorderLayout.SOUTH ); // We will track mouse events on a JPanel mousePanel = new JPanel(); mousePanel.setBackground( Color.WHITE ); add( mousePanel, BorderLayout.CENTER ); // Create and register listener for mouse and mouse motion events mousePanel.addMouseListener( new MouseEventListener() ); } // Inner class that extends MouseAdapter and only overrides the mouseClicked() method class MouseEventListener extends MouseAdapter { // handle mouse click event and determine which button was pressed public void mouseClicked( MouseEvent event ) { int xPos = event.getX(); int yPos = event.getY(); String details = String.format( "Clicked %d time(s)", event.getClickCount() ); if ( event.isMetaDown() ) // right mouse button details += " with right mouse button"; else if ( event.isAltDown() ) // middle mouse button details += " with center mouse button"; else // left mouse button details += " with left mouse button"; statusBar.setText( details ); } } } |
Our inner MouseEventListener class, inherits (extends) MouseAdapter (which has implemented all of the required methods from the MouseListener and MouseMotionListener interface classes). All we need to do is override the inherited MouseClicked() method with our custom code. I’m sure you can appreciate how much shorter (and less cluttered) the code is using this technique.
A Java application may be run on a system with a one-, two-, or three-button mouse. Java provides two methods to distinguish between mouse buttons:
Finally, here’s the test class:
1 2 3 4 5 6 7 8 9 10 11 |
import javax.swing.JFrame; public class MouseDetailsTest { public static void main( String[] args ) { MouseDetailsFrame appWindow = new MouseDetailsFrame(); appWindow.setSize( 300, 200 ); appWindow.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); appWindow.setVisible( true ); } } |
You Try!
- Create a GUI that tracks the location of the mouse within a JPanel. Imagine that the window is divided into 4 quadrants. As the mouse moves between quadrants, change the background color. Use a different colour for each quadrant. Your code should work even if the window is resized. Solve this by implementing the MouseMotionListener interface.
- Modify your code so that you inherit from MouseAdapter instead.