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

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

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

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. 添加全局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()将在这里派上用场。

这是实施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; } } } } } } 

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

使用java 1.8+的simpeler解决方案

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