java 检测 JPanel 上任意位置的鼠标进入/退出事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2445297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detecting mouse enter/exit events anywhere on JPanel
提问by Mano
Basically there is a JPanel on which I want to know when the mouse enters the area of the JPanel and exits the area of the JPanel. So I added a mouse listener, but if there are components on the JPanel and the mouse goes over one of them it is detected as an exit on the JPanel, even though the component is on the JPanel. I was wondering whether anyone knows any way to solve this problem without doing something like adding listeners onto all components on the JPanel?
基本上有一个JPanel,我想知道鼠标何时进入JPanel区域并退出JPanel区域。因此,我添加了一个鼠标侦听器,但是如果 JPanel 上有组件并且鼠标经过其中一个组件,则即使组件位于 JPanel 上,也会将其检测为 JPanel 上的退出。我想知道是否有人知道解决这个问题的任何方法,而无需像在 JPanel 上的所有组件上添加侦听器这样的事情?
回答by Darksharcoux
There is a very easy solution for this problem that can work :
有一个非常简单的解决方案可以解决这个问题:
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
}
...
}
This way you just ignore the mouseExited event when it occurs on a child element.
这样,当它发生在子元素上时,您只需忽略 mouseExited 事件。
回答by Ash
Here is one way to do it for a component that may contain other components:
这是对可能包含其他组件的组件执行此操作的一种方法:
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
TargetedMouseHandlerto ignore events that aren't sourced by the panel or by one of the panel's children (you can useSwingUtilities.isDescendingFromto 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_ENTEREDevent in your panel or one of its children, set a flag to true.When you get a
MouseEvent.MOUSE_EXITEDevent, only reset the flag if the point in theMouseEventis outside the bounds of your target panel.SwingUtilities.convertPointandComponent.getBounds().contains()will come in handy here.
添加全局 AWT 事件侦听器以获取所有鼠标事件。例如:
Toolkit.getDefaultToolkit().addAWTEventListener( new TargetedMouseHandler( panel ), AWTEvent.MOUSE_EVENT_MASK );实现
TargetedMouseHandler忽略不是由面板或面板的其中一个子项(您可以SwingUtilities.isDescendingFrom用来测试)来源的事件。跟踪鼠标是否已经在面板的范围内。当您
MouseEvent.MOUSE_ENTERED在面板或其中一个子面板中收到事件时,请将标志设置为 true。当您收到
MouseEvent.MOUSE_EXITED事件时,仅当 中的点MouseEvent超出目标面板的边界时才重置标志。SwingUtilities.convertPoint并且Component.getBounds().contains()会在这里派上用场。
回答by brian_d
This is sample code implementing Ash's solution. For me, the JFrame did not detect all exit events properly, but an inner JPanel did, so I passed in two components - one for testing descendants and one for testing the boundary.
这是实现 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;
}
}
}
}
}
}
回答by Frank Dekker
A simpeler solution with java 1.8+
使用 java 1.8+ 的更简单的解决方案
public class MyJPanel implements MouseListener {
public void mouseExited(MouseEvent e) {
if(!this.contains(e.getPoint())) {
... //the rest of your code
}
}
...
}
回答by Itay Maman
If you want to get all event send to a top-level window you can add a listener to the glass pane of the JFrame. See: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/RootPaneContainer.html#getGlassPane%28%29
如果您想将所有事件发送到顶级窗口,您可以向 JFrame 的玻璃窗格添加一个侦听器。请参阅:http: //java.sun.com/j2se/1.4.2/docs/api/javax/swing/RootPaneContainer.html#getGlassPane%28%29

