O'Reilly logo

Swing Hacks by Chris Adamson, Joshua Marinacci

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Create a Global Right-Click #57
Chapter 8, Rendering
|
293
HACK
H A C K
#57
Create a Global Right-Click
Hack #57
Give your application a right-click context menu without having to add a
listener to every component.
Oftentimes, an application needs to have a pop-up menu that is accessible
from more than one component. Sometimes the entire window should be
right-clickable. Unfortunately, doing this the normal way in Swing would
require adding a mouse listener to every component in the window, which
isn’t a very appealing solution, especially if your UI code is spread across
many classes. It would be much nicer if there were a single place to add the
context menu. This hack shows how to use a single glass pane to provide a
right-clickable menu to the entire application.
A glass pane is an invisible
JComponent that covers an entire JFrame. The glass
pane can be used to catch events or draw on top of the rest of the applica-
tion. For this hack, we will use a glass pane to capture right-click events and
trigger a pop up, alleviating the need to register a mouse listener with every
component in the frame. The basic idea is for the glass pane to intercept all
mouse events and forward them on to the application, except for the right-
click. Right-clicks will trigger the pop-up menu instead. This way there is
only one listener per frame, instead of potentially hundreds.
To start off, you need a component that has a reference to the content pane
of the frame and a pre-built pop-up menu. This is the beginning of just such
a class:
public class RightClickGlassPane extends JComponent
implements MouseListener, MouseMotionListener {
private JPopupMenu popup;
private Container contentPane;
public RightClickGlassPane(Container contentPane, JPopupMenu menu) {
addMouseListener(this);
addMouseMotionListener(this);
this.contentPane = contentPane;
popup = menu;
}
public void paint(Graphics g) {
}
// catch all mouse events and redispatch them
public void mouseMoved(MouseEvent e) {
redispatchMouseEvent(e, false);
}
294
|
Chapter 8, Rendering
#57 Create a Global Right-Click
HACK
public void mouseDragged(MouseEvent e) {
redispatchMouseEvent(e, false);
}
public void mouseClicked(MouseEvent e) {
redispatchMouseEvent(e, false);
}
public void mouseEntered(MouseEvent e) {
redispatchMouseEvent(e, false);
}
public void mouseExited(MouseEvent e) {
redispatchMouseEvent(e, false);
}
public void mousePressed(MouseEvent e) {
redispatchMouseEvent(e, false);
}
public void mouseReleased(MouseEvent e) {
redispatchMouseEvent(e, false);
}
In the RightClickGlassPane constructor, the code saves a reference to the
content pane and pop-up menu that were passed into it. Then it registers
itself as both a
MouseListener and MouseMotionListener so that it can cap-
ture all mouse events and send them to the
redispatchMouseEvent( ) method.
The
RightClickGlassPane also overrides the paint( ) method to do nothing,
ensuring that the glass pane is invisible.
The
redispatchMouseEvent( ) method is the key to the right-click glass pane.
It must first check for a right-click (actually the pop-up trigger, which will
also handle Control-click on the Mac), and then either show the pop up at
the mouse location or forward the event to the correct component. Event
forwarding is the hard part.
Each mouse event contains the current mouse coordinates, along with the
state of the mouse buttons and any modifier keys (such as Control or Shift).
Mouse coordinates are always relative to the component being clicked. This
means that a 10,10 position relative to a
JButton in the middle of the screen
wouldn’t be the same location as 10,10 relative to another
JButton lower
down on the screen. In order to account for coordinate differences,
redispatchMouseEvent( ) needs to convert between coordinate systems using
the
SwingUtilities.convertPoint( ) method:
private void redispatchMouseEvent(MouseEvent e, boolean repaint) {
// if it's a pop up
if(e.isPopupTrigger( )) {
// show the pop up and return
popup.show(e.getComponent(), e.getX(), e.getY( ));
} else {
// since it's not a pop up we need to redispatch it.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required