swing mouse listeners being intercepted by child components

后端 未结 4 1148
说谎
说谎 2020-12-20 22:05

I have a swing component that has several sub components. What I want to do change some label if the mouse is over any of those components, and then change it to something e

相关标签:
4条回答
  • 2020-12-20 22:26

    I know this is very old, but here's a simple solution with which you can create a mouse listener for a component and all components inside it's bounds (without adding the listener to all components individually):

    /**
     * Creates an {@link AWTEventListener} that will call the given listener if
     * the {@link MouseEvent} occurred inside the given component, one of its
     * children or the children's children etc. (recursive).
     * 
     * @param component
     *            the component the {@link MouseEvent} has to occur inside
     * @param listener
     *            the listener to be called if that is the case
     */
    public static void addRecursiveMouseListener(final Component component, final MouseListener listener) {
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
    
            @Override
            public void eventDispatched(AWTEvent event) {
                if(event instanceof MouseEvent) {
                    MouseEvent mouseEvent = (MouseEvent) event;
                    if(mouseEvent.getComponent().isShowing() && component.isShowing()){
                        if (containsScreenLocation(component, mouseEvent.getLocationOnScreen())) {
                            if(event.getID() == MouseEvent.MOUSE_PRESSED) {
                                listener.mousePressed(mouseEvent);
                            }
                            if(event.getID() == MouseEvent.MOUSE_RELEASED) {
                                listener.mouseReleased(mouseEvent);
                            }
                            if(event.getID() == MouseEvent.MOUSE_ENTERED) {
                                listener.mouseEntered(mouseEvent);
                            }
                            if(event.getID() == MouseEvent.MOUSE_EXITED) {
                                listener.mouseExited(mouseEvent);
                            }
                            if(event.getID() == MouseEvent.MOUSE_CLICKED){
                                listener.mouseClicked(mouseEvent);
                            }
                        }
                    }
                }
            }
        }, AWTEvent.MOUSE_EVENT_MASK);
    }
    
    /**
     * Checks if the given location (relative to the screen) is inside the given component
     * @param component the component to check with
     * @param screenLocation the location, relative to the screen
     * @return true if it is inside the component, false otherwise
     */
    public static boolean containsScreenLocation(Component component, Point screenLocation){
        Point compLocation = component.getLocationOnScreen();
        Dimension compSize = component.getSize();
        int relativeX = screenLocation.x - compLocation.x;
        int relativeY = screenLocation.y - compLocation.y;
        return (relativeX >= 0 && relativeX < compSize.width && relativeY >= 0 && relativeY < compSize.height);
    }
    

    Note: Once the mouse exits the root component of this listener the mouseExited(mouseEvent) will probably not fire, however you can just add the mouse listener to the root component itself and it should fire.
    mouseExited(mouseEvent) is unreliable in general though.

    0 讨论(0)
  • 2020-12-20 22:37

    You could initiate a single instance of the listener and add that instance to each component. Like this:

    AMouseListener aMouseListener=new  AMouseListener();
    
    for each(Component c:components) {
    caddMouseListener(aMouseListener);
    }
    
    0 讨论(0)
  • For example

    enter image description here

    enter image description here

    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.*;
    
    public class TestMouseListener {
    
        public static void main(String[] args) {
            final JComboBox combo = new JComboBox();
            combo.setEditable(true);
            for (int i = 0; i < 10; i++) {
                combo.addItem(i);
            }
            final JLabel tip = new JLabel();
            tip.setPreferredSize(new Dimension(300, 20));
            JPanel panel = new JPanel();
            panel.add(combo);
            panel.add(tip);
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(panel);
            frame.pack();
            frame.setVisible(true);
            panel.addMouseListener(new MouseAdapter() {
    
                @Override
                public void mouseEntered(MouseEvent e) {
                    tip.setText("Outside combobox");
                }
    
                @Override
                public void mouseExited(MouseEvent e) {
                    Component c = SwingUtilities.getDeepestComponentAt(
                       e.getComponent(), e.getX(), e.getY());
                    // doesn't work if you move your mouse into the combobox popup
                    tip.setText(c != null && SwingUtilities.isDescendingFrom(
                       c, combo) ? "Inside combo box" : "Outside combobox");
                }
            });
        }
    
        private TestMouseListener() {
        }
    }
    
    0 讨论(0)
  • 2020-12-20 22:45

    Check out the docs and examples for the "glass pane".
    This should give you what you need: The Glass Pane

    0 讨论(0)
提交回复
热议问题