Skip to main content

Swing Hack 4: The universal right click

Posted by joshy on October 3, 2003 at 9:13 AM PDT

I received an email today asking about my use of the glass
pane. It seems this fellow wants to handle right clicks on
any component in each screen. A logical request. In most cases
your right clicks are not limited to a single component, yet to
receive the events required to show popups you have to add a
listener to each component! Not enjoyable.

To get around this we can use a glass pane. Remember from last time
that a glass pane is an invisible component covering the entire frame.
We could catch the events there and handle right clicks on any component. The problem, of course, is that now none of your components
can get any of the events.

To get around this issue we can test for the right click and then
redispatch the event to make sure the correct component gets it. Not
trivial but not too hard either. The tricky part is rebroadcasting
the event. First you have to figure out which component was supposed
to be hit. To find this we must convert the click point from
being relative to the glass pane to being relative to the content
pane:

// get the mouse click point relative to the content pane
Point containerPoint = SwingUtilities.convertPoint(this, e.getPoint(),contentPane);

Then we can search for the child component which was hit

// find the component that under this point
Component component = SwingUtilities.getDeepestComponentAt(
            contentPane,
            containerPoint.x,
            containerPoint.y);

Once that's done we convert the point to be relative to the target
component:

// convert point relative to the target component
Point componentPoint = SwingUtilities.convertPoint(
    this,
    e.getPoint(),
    component);

And now we redispatch the event:

// redispatch the event
component.dispatchEvent(new MouseEvent(component,
    e.getID(),
    e.getWhen(),
    e.getModifiers(),
    componentPoint.x,
    componentPoint.y,
    e.getClickCount(),
    e.isPopupTrigger()));

Here's the complete code. Parts of it were
adapted from the Java Tutorial sections on
glasspanes and popup menus.
The code makes a frame with a button and a textfield.
Then it creates a right click handler to grab the
events, check for right clicks, and redispatch the
others.

for more on glass panes and popup menus you can read
here
and
here
.

Enjoy!

- joshua

: (hmm. maybe I should make this a link).

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

/**
    Written by Joshua Marinacci (joshy@joshy.org)
    Adapted from Sun tutorial code at
        http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html... class RightClick extends JComponent implements MouseListener, MouseMotionListener {

    JPopupMenu popup;
    Container contentPane;

    public RightClick(Container contentPane) {
        addMouseListener(this);
        addMouseMotionListener(this);
        this.contentPane = contentPane;

        popup = new JPopupMenu();
        popup.add(new JMenuItem("Dogs"));
        popup.add(new JMenuItem("Cats"));
        popup.add(new JMenuItem("Mass Hysteria"));
    }

    // draw some text just so we know the glass pane
    // is installed and visible
    public void paint(Graphics g) {
        g.drawString("I'm a glass pane",50,50);
    }


    // catch all mouse events and redispatch them
    public void mouseMoved(MouseEvent e) {
        redispatchMouseEvent(e, false);
    }
    public void mouseDragged(MouseEvent e) {
        redispatchMouseEvent(e, false);
    }
    public void mouseClicked(MouseEvent e) {
        p("mouse clicked");
        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);
    }


    private void redispatchMouseEvent(MouseEvent e,
        boolean repaint) {

        // if it's a popup
        if(e.isPopupTrigger()) {
            p("it's a popup");
            // show the popup and return
            popup.show(e.getComponent(), e.getX(), e.getY());

        } else {
            // since it's not a popup we need to redispatch it.

            // get the mouse click point relative to the content pane
            Point containerPoint = SwingUtilities.convertPoint(this,
                e.getPoint(),contentPane);

            // find the component that under this point
            Component component = SwingUtilities.getDeepestComponentAt(
                        contentPane,
                        containerPoint.x,
                        containerPoint.y);

            // return if nothing was found
            if (component == null) {
                return;
            }

            // convert point relative to the target component
            Point componentPoint = SwingUtilities.convertPoint(
                this,
                e.getPoint(),
                component);

            // redispatch the event
            component.dispatchEvent(new MouseEvent(component,
                e.getID(),
                e.getWhen(),
                e.getModifiers(),
                componentPoint.x,
                componentPoint.y,
                e.getClickCount(),
                e.isPopupTrigger()));
        }
    }



    public static void main(String[] args) {
        // create a frame with some components in it
        JFrame frame = new JFrame("Right Click Test");
        JButton button = new JButton("this is a button");
        JTextField tf = new JTextField("this is a textfield");
        JPanel panel = new JPanel();
        panel.add(button);
        panel.add(tf);
        frame.getContentPane().add(panel);


        // create the right click glass pane.
        RightClick rc = new RightClick(frame.getContentPane());
        // set as glasspane and make it visible
        frame.setGlassPane(rc);
        rc.setVisible(true);

        // pack and show the frame
        frame.pack();
        frame.setSize(400,200);
        frame.show();
    }

    // utiltity function
    public static void p(String str) {
        System.out.println(str);
    }

}
Related Topics >>