Swing Hack 4: The universal right click

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!

: (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);
    }

}
Talk to me about it on Twitter

Posted October 3rd, 2003

Tagged: java swing-hacks java.net