Обнаружение событий входа / выхода мыши в любом месте на JPanel - PullRequest
13 голосов
/ 15 марта 2010

В основном есть JPanel, на котором я хочу знать, когда мышь входит в область JPanel и выходит из области JPanel. Поэтому я добавил слушателя мыши, но если на JPanel есть компоненты, и мышь наводит курсор на один из них, это определяется как выход на JPanel, даже если компонент находится на JPanel. Мне было интересно, знает ли кто-нибудь какой-либо способ решения этой проблемы, не добавляя при этом слушателей ко всем компонентам на JPanel?

Ответы [ 5 ]

9 голосов
/ 15 мая 2013

Существует очень простое решение этой проблемы, которое может работать:

public class MyJPanel implements MouseListener {

    public void mouseExited(MouseEvent e) {
        java.awt.Point p = new java.awt.Point(e.getLocationOnScreen());
        SwingUtilities.convertPointFromScreen(p, e.getComponent());
        if(e.getComponent().contains(p)) {return;}
        ...//the rest of your code
    }

    ...
}

Таким образом, вы просто игнорируете событие mouseExited, которое происходит в дочернем элементе.

8 голосов
/ 15 марта 2010

Вот один из способов сделать это для компонента, который может содержать другие компоненты:

  1. Добавление глобального прослушивателя событий AWT для получения всех событий мыши. Например:

    Toolkit.getDefaultToolkit().addAWTEventListener( 
       new TargetedMouseHandler( panel ), AWTEvent.MOUSE_EVENT_MASK );
    
  2. Реализуйте TargetedMouseHandler, чтобы игнорировать события, которые не получены ни панелью, ни одним из дочерних элементов панели (вы можете использовать SwingUtilities.isDescendingFrom для проверки этого).

  3. Отслеживайте, находится ли мышь уже в пределах вашей панели. Когда вы получаете событие MouseEvent.MOUSE_ENTERED на своей панели или в одном из его дочерних элементов, установите для флага значение true.

  4. Когда вы получаете событие MouseEvent.MOUSE_EXITED, сбрасывайте флаг, только если точка в MouseEvent находится за пределами вашей целевой панели. SwingUtilities.convertPoint и Component.getBounds().contains() пригодятся здесь.

4 голосов
/ 26 августа 2010

Это пример кода, реализующего решение Эша. Для меня JFrame не обнаружил все события выхода должным образом, но внутренний JPanel сделал, поэтому я передал два компонента - один для тестирования потомков и один для тестирования границы.

Toolkit.getDefaultToolkit().addAWTEventListener(
        new TargetedMouseHandler(this, this.jPanel), 
        AWTEvent.MOUSE_EVENT_MASK);
}

public class TargetedMouseHandler implements AWTEventListener
{

    private Component parent;
    private Component innerBound;
    private boolean hasExited = true;

    public TargetedMouseHandler(Component p, Component p2)
    {
        parent = p;
        innerBound = p2;
    }

    @Override
    public void eventDispatched(AWTEvent e)
    {
        if (e instanceof MouseEvent)
        {
            if (SwingUtilities.isDescendingFrom(
                (Component) e.getSource(), parent))
            {
                MouseEvent m = (MouseEvent) e;
                if (m.getID() == MouseEvent.MOUSE_ENTERED)
                {
                    if (hasExited)
                    {
                        System.out.println("Entered");
                        hasExited = false;
                    }
                } else if (m.getID() == MouseEvent.MOUSE_EXITED)
                {
                    Point p = SwingUtilities.convertPoint(
                        (Component) e.getSource(),
                        m.getPoint(),
                        innerBound);
                    if (!innerBound.getBounds().contains(p))
                    {
                        System.out.println("Exited");
                        hasExited = true;
                    }
                }
            }
        }
    }
}
0 голосов
/ 25 июля 2018

Простое решение с Java 1.8 +

public class MyJPanel implements MouseListener {

    public void mouseExited(MouseEvent e) {        
        if(!this.contains(e.getPoint())) {
            ... //the rest of your code
        }
    }

    ...
}
0 голосов
/ 15 марта 2010

Если вы хотите, чтобы все события отправлялись в окно верхнего уровня, вы можете добавить слушателя на стеклянную панель JFrame. Смотри: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/RootPaneContainer.html#getGlassPane%28%29

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...