Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1720
  • Last Modified:

JFrame + mouseListener

Hi,

I have a java applet which loads a JFrame
now this JFrame has many components

When I press a button , it loads a JWindow

if this JWindow is visible then I want to hide it
if the user presses either the escape key anywhere in the frame or if he clicks a mouse anywhere in the frame

This is the code

 /**add key listener to the root pane**/
    protected JRootPane createRootPane()
    {

        MouseListener mouseListener = new MouseAdapter()
        {
            public void mouseClicked(MouseEvent event)
            {
                setVisible(false);
            }
        };

        /**add the keyboard listener*/
        ActionListener actionListener = new ActionListener()
        {
            public void actionPerformed(ActionEvent actionEvent)
            {
                setVisible(false);
            }
        };
        JRootPane rootPane = new JRootPane();
        KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
        rootPane.registerKeyboardAction(actionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);

        rootPane.addMouseListener(mouseListener);
        return rootPane;
    }


I am able to intercept the "Escape" key anywhere in the frame

But I am not able to trace mouse click events

What should I do to get the mouseClicked event
when evr user clicks the mouse anywhere in the JFrame

maybe I have to add MouseListener recursively as componets get added to the JFrame

but is there a better approcah

please help
0
sanjay_thakur
Asked:
sanjay_thakur
  • 4
  • 3
1 Solution
 
sanjay_thakurAuthor Commented:
I guess I will have to add mouseListener
for all the child components of the JFrame

but is there a better approcah?
0
 
Jim CakalicSenior Developer/ArchitectCommented:
I'm not sure whether there is a _better_ way than what I am about to suggest. But as I recall, this way works. Basically, you have to use the GlassPane of the JFrame set to visible so that it will intercept all the mouse events occurring in the frame and redispatch (or not) to the appropriate components if desired. Here is the sample code (slightly modified) from the Java Tutorial for GlassPaneDemo that does this. The original can be found here:
    http://java.sun.com/docs/books/tutorial/uiswing/components/example-swing/index.html#GlassPaneDemo
with the relevant part of the tutorial here:
    http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html

---------- GlassPaneDemo.java ----------
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.*;

public class GlassPaneDemo {
    static private MyGlassPane myGlassPane;

    public static void main(String[] args) {
        JFrame frame = new JFrame("GlassPaneDemo");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        JCheckBox changeButton = new JCheckBox("Glass pane \"visible\"");
        changeButton.setSelected(false);
        changeButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                myGlassPane.setVisible(e.getStateChange()
                    == ItemEvent.SELECTED);
            }
        });

        JButton button1 = new JButton("Button 1");
        button1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Pressed Button 1");
            }
        });
        JButton button2 = new JButton("Button 2");
        button2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Pressed Button 2");
            }
        });

        //Set up the content pane, where the "main GUI" lives.
        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new FlowLayout());
        contentPane.add(changeButton);
        contentPane.add(button1);
        contentPane.add(button2);

        //Set up the menu bar, which appears above the content pane.
        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Menu");
        menu.add(new JMenuItem("Do nothing"));
        menuBar.add(menu);
        frame.setJMenuBar(menuBar);

        //Set up the glass pane, which appears over both menu bar
        //and content pane.
        myGlassPane = new MyGlassPane(changeButton, menuBar, frame.getContentPane());
        frame.setGlassPane(myGlassPane);

        frame.pack();
        frame.setVisible(true);
    }
}

/**
 * We have to provide our own glass pane so that it can paint.
 */
class MyGlassPane extends JComponent {
    Point point;

    public void paint(Graphics g) {
        if (point != null) {
            g.setColor(Color.red);
            g.fillOval(point.x - 10, point.y - 10, 20, 20);
        }
    }

    public void setPoint(Point p) {
        point = p;
    }

    public MyGlassPane(AbstractButton aButton,
        JMenuBar menuBar,
        Container contentPane) {
        CBListener listener = new CBListener(aButton, menuBar, this, contentPane);
        addMouseListener(listener);
        addMouseMotionListener(listener);
    }
}

/**
 * Listen for all events that our check box is likely to be
 * interested in.  Redispatch them to the check box.
 */
class CBListener extends MouseInputAdapter {
    Toolkit toolkit;
    Component liveButton;
    JMenuBar menuBar;
    MyGlassPane glassPane;
    Container contentPane;
    boolean inDrag = false;

    public CBListener(Component liveButton, JMenuBar menuBar,
        MyGlassPane glassPane, Container contentPane) {
        toolkit = Toolkit.getDefaultToolkit();
        this.liveButton = liveButton;
        this.menuBar = menuBar;
        this.glassPane = glassPane;
        this.contentPane = contentPane;
    }

    public void mouseMoved(MouseEvent e) {
        redispatchMouseEvent(e, false);
    }

    /*
     * We must forward at least the mouse drags that started
     * with mouse presses over the check box.  Otherwise,
     * when the user presses the check box then drags off,
     * the check box isn't disarmed -- it keeps its dark
     * gray background or whatever its L&F uses to indicate
     * that the button is currently being pressed.
     */
    public void mouseDragged(MouseEvent e) {
        redispatchMouseEvent(e, false);
    }

    public void mouseClicked(MouseEvent e) {
        System.out.println("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, true);
        inDrag = false;
    }

    private void redispatchMouseEvent(MouseEvent e, boolean repaint) {
        boolean inButton = false;
        boolean inMenuBar = false;
        Point glassPanePoint = e.getPoint();
        Component component = null;
        Container container = contentPane;
        Point containerPoint = SwingUtilities.convertPoint(
            glassPane,
            glassPanePoint,
            contentPane);
        int eventID = e.getID();

        if (containerPoint.y < 0) {
            inMenuBar = true;
            container = menuBar;
            containerPoint = SwingUtilities.convertPoint(
                glassPane,
                glassPanePoint,
                menuBar);
            testForDrag(eventID);
        }

        //XXX: If the event is from a component in a popped-up menu,
        //XXX: then the container should probably be the menu's
        //XXX: JPopupMenu, and containerPoint should be adjusted
        //XXX: accordingly.
        component = SwingUtilities.getDeepestComponentAt(
            container,
            containerPoint.x,
            containerPoint.y);

        if (component == null) {
            return;
        }

        if (component.equals(liveButton)) {
            inButton = true;
            testForDrag(eventID);
        }

//        if (inMenuBar || inButton || inDrag) {
            Point componentPoint = SwingUtilities.convertPoint(
                glassPane,
                glassPanePoint,
                component);
            component.dispatchEvent(new MouseEvent(component,
                eventID,
                e.getWhen(),
                e.getModifiers(),
                componentPoint.x,
                componentPoint.y,
                e.getClickCount(),
                e.isPopupTrigger()));
//        }

        if (repaint) {
            toolkit.beep();
            glassPane.setPoint(glassPanePoint);
            glassPane.repaint();
        }
    }

    private void testForDrag(int eventID) {
        if (eventID == MouseEvent.MOUSE_PRESSED) {
            inDrag = true;
        }
    }
}
---------- end ----------

Best regards,
Jim Cakalic
0
 
sanjay_thakurAuthor Commented:
Hi Jim,

Is there any thing simpler

I am using jdk1.4
any new feature to handle this which I am not aware of?


0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
Jim CakalicSenior Developer/ArchitectCommented:
Nothing that I can find. Seems use of glass pane is still the way to globally intercept mouse events. I use the word "intercept" here because in AWT, a mouse action is considered to occur in a particular component if and only if the mouse cursor is over the unobscured part of the component's bounds when the action happens. Component bounds can be obscured by the visible component's children or by a menu or by a top-level window. In the case of JFrame, all the components you create and add to the content pane obscure the JFrame itself. Therefore, the JFrame, while it can be a mouse listener, will only receive mouse events when the mouse cursor is in an area not occupied by one of its child components. The glass pane is an "overlay" that, when visible, obscures everything else although it itself is by default transparent. But events cannot pass through it to the underlying components unless you choose to redispatch them directly.

Jim
0
 
sanjay_thakurAuthor Commented:
Hi Jim,
I guess you are correct this is the only option
I will try out the code.

Please give me a couple of days.

Thanks for all the help.
0
 
Jim CakalicSenior Developer/ArchitectCommented:
OK. Post back if you need anything more.
0
 
sanjay_thakurAuthor Commented:
My apologies for the delay.

Thanks a ton for all your help.
0

Featured Post

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now