MouseListener mouseClicked Invoked when a mouse is
clicked on a component
mousePressed Invoked when a mouse is
pressed
mouseReleased Invoked when a mouse is
released
mouseEntered Invoked when a mouse
enters a component’s bounds
mouseExited Invoked when a mouse exits
a component’s bounds
MouseMotionListener mouseDragged Invoked when a mouse
button is pressed on a component and then dragged
mouseMoved Invoked when a mouse is
moved around a component
MouseWheelListener mouseWheelMoved Invoked when the mouse
Figure 10.1 BadRightMouseButton on Windows (top) and Mac OS X (bottom).
A common problem is an application that needs to process clicks from a right mouse button across platforms. For example, say we had an application that captured right mouse clicks to both display a context-sensitive popup menu and change the mode of a tool from select, on the left mouse click, to select and execute for a right mouse click. Figure 10.1 displays the user interface of a simple application to capture these two activities of a right mouse click. Figure 10.1 shows the application run on both Win- dows NT and Mac OSX, since our Java application supports both operating systems.
Listing 10.1 displays the source code for BadRightMouseButton.java.
01: /* BadRightMouseButton.java */ 02: import java.awt.event.*; 03: import java.awt.*; 04: import javax.swing.*; 05:
06: public class BadRightMouseButton extends JFrame implements MouseListener
07: {
08: public BadRightMouseButton() 09: {
10: super(“Bad Right Mouse Button”); 11:
12: JLabel l = new JLabel(“Right Mouse Click here.”); 13: getContentPane().add(“Center”, l); 14: 15: addMouseListener(this); 16: 17: setSize(400,200); 18: setLocation(100,100); 19: setVisible(true); 20: addWindowListener(new WindowAdapter() 21: {
22: public void windowClosing(WindowEvent evt)
23: { 24: System.exit(1); 25: } 26: }); 27: 28: } 29:
30: public static void main(String [] args) 31: {
32: try 33: {
34: BadRightMouseButton win = new BadRightMouseButton(); 35: 36: } catch (Throwable t) 37: { 38: t.printStackTrace(); 39: } 40: } 41:
42: public void mouseClicked(MouseEvent e) 43: {
44: int modifiers = e.getModifiers();
45: if ((modifiers & InputEvent.BUTTON1_MASK) == Æ
InputEvent.BUTTON1_MASK)
46: System.out.println(“Button 1 clicked.”); 47:
48: if ((modifiers & InputEvent.BUTTON2_MASK) == Æ
InputEvent.BUTTON2_MASK)
49: System.out.println(“Button 2 clicked.”); 50:
51: if ((modifiers & InputEvent.BUTTON3_MASK) == Æ
InputEvent.BUTTON3_MASK) ) 52: System.out.println(“Button 3 clicked.”); 53: 54: // modifier keys 55: System.out.println(“isControlDown? “ + e.isControlDown()); 56: System.out.println(“isMetaDown? “ + e.isMetaDown()); 57: System.out.println(“isAltDown? “ + e.isAltDown()); 58: System.out.println(“isShiftDown? “ + e.isShiftDown()); 59: System.out.println(“isAltGraphDown? “ + e.isAltGraphDown()); 60: 61: /* 1.4 methods
62: int buttonNumber = e.getButton();
63: System.out.println(“Button # is : “ + buttonNumber); 64:
65: int mods = e.getModifiersEx();
66: System.out.println(“Modifiers: “ + Æ InputEvent.getModifiersExText(mods));
67: */
68:
69: // is this a Popup Trigger?
70: System.out.println(“In mouseClicked(), isPopupTrigger? “ + Æ
e.isPopupTrigger());
71: } 72:
73: public void mousePressed(MouseEvent e) 74: { }
75: public void mouseReleased(MouseEvent e) 76: { }
77: public void mouseEntered(MouseEvent e) 78: { }
79: public void mouseExited(MouseEvent e) 80: { }
81: }
Listing 10.1 (continued)
JDK 1.4 has added some new methods as demonstrated (but commented out) in lines 62 and 65. These are additional convenience methods that enable you to eliminate the need for ANDing the modifier integer with the constant flags (lines 45, 48, and 51). Here is a run of BadRightMouseButton on Windows with a two-button mouse with a mouse wheel. When the program was executed, the right mouse button was clicked, followed by the left mouse button and then the mouse wheel. This produced the fol- lowing printlnstatements:
>>>java BadRightMouseButton (on Windows NT with 2 button mouse with mousewheel) Button 3 clicked. isControlDown? false isMetaDown? true isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false
Button 1 clicked. isControlDown? false isMetaDown? false isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false
Button 2 clicked.
isControlDown? false isMetaDown? false isAltDown? true
isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false
Here is a run of BadRightMouseButton.java on Mac OSX with a single-button mouse. When the program was executed, the single mouse button was clicked (which maps to button 1), then the Ctrl key was held and the mouse button clicked, then the special “apple” key was held and the mouse button clicked.
>>>java BadRightMouseButton (on MacOSX with a single mouse button)
Button 1 clicked. isControlDown? false isMetaDown? false isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false
Button 2 clicked. isControlDown? true isMetaDown? false isAltDown? true isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false
Button 3 clicked. isControlDown? false isMetaDown? true isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false
There are two problems you should notice when examining the results from both operating systems besides the fact that they are not consistent. First, there is no clear indication of a right mouse button click even though we know that the Windows mouse clearly has a right and left mouse button. Instead of “sides” of the mouse, we have the ability in the InputEventclass (which is the parent class of MouseEvent) to check which button was clicked: button 1, 2, or 3. Unfortunately, there is no way to cor- relate a button with a side for a cross-platform application. The second problem is that the call to isPopupTrigger()has always returned false when we know that a right- button mouse click is the trigger on Windows for a popup and the Ctrl-mouse click combination is the trigger on the Mac. Listing 10.2, GoodRightMouseButton.java, solves both of these problems.
01: /* GoodRightMouseButton.java */ 02: import java.awt.event.*; 03: import java.awt.*; 04: import javax.swing.*; 05:
06: public class GoodRightMouseButton extends JFrame implements Æ MouseListener
07: {
08: public GoodRightMouseButton() 09: {
// ... constructor identical to Listing #10.1 28: }
29:
30: public static void main(String [] args) 31: {
32: try 33: {
34: GoodRightMouseButton win = new GoodRightMouseButton(); 35: 36: } catch (Throwable t) 37: { 38: t.printStackTrace(); 39: } 40: } 41:
42: public void mouseClicked(MouseEvent e) 43: {
// ... getModifiers() code Identical to listing 10.1 ... 68:
69: // is this a Popup Trigger?
70: System.out.println(“In mouseClicked(), isPopupTrigger? “ + Æ e.isPopupTrigger());
71:
72: // Use SwingUtilities to disambiguate
73: boolean lb = SwingUtilities.isLeftMouseButton(e); 74: boolean mb = SwingUtilities.isMiddleMouseButton(e); 75: boolean rb = SwingUtilities.isRightMouseButton(e); 76: 77: System.out.println(“Left button? “ + lb); 78: System.out.println(“Middle button? “ + mb); 79: System.out.println(“Right button? “ + rb); 80: } 81:
82: public void mousePressed(MouseEvent e)
83: {
84: // is this a Popup Trigger?
85: System.out.println(“In mousePressed(), isPopupTrigger? “ + Æ
e.isPopupTrigger());
86: }
87: public void mouseReleased(MouseEvent e) 88: {
89: // is this a Popup Trigger?
90: System.out.println(“In mouseReleased(), isPopupTrigger? “ + Æ
e.isPopupTrigger());
91: } 92:
93: public void mouseEntered(MouseEvent e) 94: { }
95: public void mouseExited(MouseEvent e) 96: { }
97: } 98:
Listing 10.2 (continued)
Here is a run of GoodRightMouseButton on Windows. When executing the pro- gram, the right mouse button was clicked, followed by the left mouse button and then the mouse wheel. This produced the following printlnstatements:
>>>java GoodRightMouseButton (on Windows NT with 2 button mouse with mousewheel)
In mousePressed(), isPopupTrigger? false In mouseReleased(), isPopupTrigger? true
Button 3 clicked. isControlDown? false isMetaDown? true isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false Left button? false
Middle button? false Right button? true
In mousePressed(), isPopupTrigger? false In mouseReleased(), isPopupTrigger? false
Button 1 clicked. isControlDown? false isMetaDown? false isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false Left button? true
Middle button? false Right button? false
In mousePressed(), isPopupTrigger? false In mouseReleased(), isPopupTrigger? false
Button 2 clicked. isControlDown? false isMetaDown? false isAltDown? true isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false Left button? false
Middle button? true Right button? false
Here is a run of GoodRightMouseButton.java on Mac OSX. When the program was executed, the single mouse button was clicked, then the Ctrl key was held and the mouse button clicked, then the special “apple” key was held and the mouse button clicked.
>>>java GoodRightMouseButton (on MacOSX with a single mouse button) In mousePressed(), isPopupTrigger? false
In mouseReleased(), isPopupTrigger? false
Button 1 clicked. isControlDown? false isMetaDown? false isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false Left button? true
Middle button? false Right button? false
In mousePressed(), isPopupTrigger? true In mouseReleased(), isPopupTrigger? false
Button 2 clicked. isControlDown? true isMetaDown? false isAltDown? true isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false Left button? false
Middle button? true Right button? false
In mousePressed(), isPopupTrigger? false In mouseReleased(), isPopupTrigger? false
Button 3 clicked. isControlDown? false isMetaDown? true isAltDown? false isShiftDown? false isAltGraphDown? false
In mouseClicked(), isPopupTrigger? false Left button? false
Middle button? false Right button? true
The new results show that we can determine which mouse button (left, right, or middle) was clicked and whether that click is the popup trigger event. The solution has two parts: first, the SwingUtilitiesclass contains a set of methods that allow you to test a mouse event to determine which side of the mouse was clicked. It is slightly nonintuitive to have these separated from the other test methods in InputEventor
MouseEvent; however, that could change in a future release. Second, you should notice how you have to test for the popupTrigger in the mousePressed() and
mouseReleased()to accurately determine the trigger event. It is interesting to note that the Ctrl-mouse combination on the Macintosh is considered the middle mouse button and not the right mouse button. It would be better if the popup trigger was con- sistent on Windows and the Mac (both being considered a “right click”).
In conclusion, using the SwingUtilitiesclass and understanding when to call
isPopupTrigger()allows us to better process mouse events in cross-platform appli- cations.