javaswingglasspanemouse-listeners

How to click through JGlassPane With MouseListener to UI behind it


I have a JFrame and a bunch of JComponents on top of the JFrame. I need to make use of the JGlassPane and I used this implementation to set it up.

   JPanel glass = new JPanel();
   frame.setGlassPane(glass);
   glass.setVisible(true);
   glass.setOpaque(false);

After doing so I can't select any JButtons or other JComponents under the JGlassPane.

Is there a way to have only the components on the GlassPane selectable while still having the ability to select components under the GlassPane?

Edit I forgot to mention (not knowing this would be relevant) that I did attach both a MouseListener and a MouseMotionListener to the glass pane. Is there a way to pass the Mouse Events to other components and only use them when needed?


Solution

  • Make your mouseListener dispatch the events it doesn't want to handle.

    The example code below is mixed, using the nice SSCCE by @whiskeyspider and the tutorial (BTW: looking into the tutorial is a good starter for solving problems :-)

    ml = new MouseListener() {
        @Override
        public void mousePressed(MouseEvent e) {
            dispatchEvent(e);
        }
        // same for all methods
        // ....
    
        private void dispatchEvent(MouseEvent e) {
            if (isBlocked)
                return;
            Point glassPanePoint = e.getPoint();
            Container container = frame.getContentPane();
            Point containerPoint = SwingUtilities.convertPoint(glass,
                    glassPanePoint, container);
    
            if (containerPoint.y < 0) { // we're not in the content pane
                // Could have special code to handle mouse events over
                // the menu bar or non-system window decorations, such as
                // the ones provided by the Java look and feel.
            } else {
                // The mouse event is probably over the content pane.
                // Find out exactly which component it's over.
                Component component = SwingUtilities.getDeepestComponentAt(
                        container, containerPoint.x, containerPoint.y);
    
                if (component != null) {
                    // Forward events to component below
                    Point componentPoint = SwingUtilities.convertPoint(
                            glass, glassPanePoint, component);
                    component.dispatchEvent(new MouseEvent(component, e
                            .getID(), e.getWhen(), e.getModifiers(),
                            componentPoint.x, componentPoint.y, e
                                    .getClickCount(), e.isPopupTrigger()));
                }
            }
        }
    };
    
    glass.addMouseListener(ml);
    glassButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
            if (isBlocked) {
                // glass.removeMouseListener(ml);
                glassButton.setText("Block");
            } else {
                // ml = new MouseAdapter() { };
                // glass.addMouseListener(ml);
                glassButton.setText("Unblock");
            }
    
            isBlocked = !isBlocked;
        }
    });