基本上,我有一个JPanel,在这个面板上我想知道鼠标何时进入并离开JPanel的区域。因此,我添加了一个鼠标监听器,但是如果在JPanel上有组件,并且鼠标经过其中一个组件时,即使该组件位于JPanel上,它也被检测为从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事件时,你只需要忽略它即可。
mouseEntered
也不会调用mouseExited
。 - Marcono1234以下是一种处理可能包含其他组件的组件的方法:
Add a global AWT event listener to get all mouse events. For example:
Toolkit.getDefaultToolkit().addAWTEventListener(
new TargetedMouseHandler( panel ), AWTEvent.MOUSE_EVENT_MASK );
Implement the TargetedMouseHandler
to ignore events that aren't sourced by the panel or by one of the panel's children (you can use SwingUtilities.isDescendingFrom
to test for this).
Keep track of whether or not the mouse is already within the bounds of your panel. When you get a MouseEvent.MOUSE_ENTERED
event in your panel or one of its children, set a flag to true.
When you get a MouseEvent.MOUSE_EXITED
event, only reset the flag if the point in the MouseEvent
is outside the bounds of your target panel. SwingUtilities.convertPoint
and Component.getBounds().contains()
will come in handy here.
这是实现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;
}
}
}
}
}
}
使用Java 1.8+的更简单解决方案
public class MyJPanel implements MouseListener {
public void mouseExited(MouseEvent e) {
if(!this.contains(e.getPoint())) {
... //the rest of your code
}
}
...
}
如果您想获取发送到顶层窗口的所有事件,可以向JFrame的玻璃窗格添加侦听器。请参见getGlassPane。