在JPanel上的任何位置检测鼠标进入/退出事件

时间:2010-03-15 05:32:11

标签: java

基本上,当鼠标进入JPanel区域并退出JPanel区域时,我想知道一个JPanel。所以我添加了一个鼠标监听器,但是如果JPanel上有组件并且鼠标经过其中一个组件,则它被检测为JPanel上的一个出口,即使该组件位于JPanel上。我想知道是否有人知道如何解决这个问题,而不需要像在JPanel上的所有组件上添加监听器那样?

5 个答案:

答案 0 :(得分:9)

有一个非常简单的解决方案可以解决这个问题:

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事件,就会忽略它。

答案 1 :(得分:8)

以下是为可能包含其他组件的组件执行此操作的一种方法:

  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.convertPointComponent.getBounds().contains()会派上用场。

答案 2 :(得分:4)

这是实施Ash解决方案的示例代码。对我来说,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;
                    }
                }
            }
        }
    }
}

答案 3 :(得分:0)

如果要将所有事件发送到顶级窗口,可以将侦听器添加到JFrame的玻璃窗格。请参阅:http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/RootPaneContainer.html#getGlassPane%28%29

答案 4 :(得分:0)

使用Java 1.8+的simpeler解决方案

public class MyJPanel implements MouseListener {

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

    ...
}