鼠标在内部组件悬停时退出

Rac*_*416 2 java swing

我创建了一个带有包含不同组件的 JPanel 的 JFrame,例如,当鼠标位于 JPanel 的边界内时,我希望 JPanel 有可见的边框和可见的图像。我的问题是,一旦鼠标悬停在 JPanel 内的“可交互”组件上,它就会在鼠标退出 JPanel 时注册。我希望它能够绘制这些东西,只要它在 JPanel 的边界内,并且当鼠标退出 JPanel 的边界时,边框和图像“消失”。有什么办法可以实现这一点吗?

这是一个小演示:

public class Test {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new TestFrame();
    }

    static class TestFrame extends JFrame{
        JPanel panel;
        JButton hoverButton;
        JButton appearingButton;
        public TestFrame() {
            super();
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);
            panel = new JPanel();
            panel.setBackground(Color.red);
            hoverButton = new JButton("Hover me!");
            appearingButton = new JButton("I appeared!");
            appearingButton.setVisible(false);
            panel.add(hoverButton);
            panel.add(appearingButton);
            panel.addMouseListener(new java.awt.event.MouseAdapter() {
                public void mouseEntered(java.awt.event.MouseEvent evt) {
                    System.out.println("Entered!");
                    appearingButton.setVisible(true);
                }
                public void mouseExited(java.awt.event.MouseEvent evt) {
                    System.out.println("Exited!");
                    appearingButton.setVisible(false);
                }
            });
            add(panel);
            setSize(new Dimension(200, 200));
            setVisible(true);
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

当鼠标位于 JPanel 内(覆盖整个 JFrame)时,将出现第二个按钮。然而,将鼠标悬停在第一个按钮上将使第二个按钮消失。我希望只要您位于 JPanel 的范围内,就会显示第二个按钮。

Mad*_*mer 5

这实际上比听起来要困难得多。您需要能够监视容器子组件的所有鼠标事件。不幸的是,你要么得到全有,要么全无的解决方案。也就是说,您要么遇到现在遇到的问题,一旦MouseListener另一个组件开始捕获鼠标事件(这就是鼠标侦听器 API 的工作原理),鼠标事件就会停止报告,或者您可以看到系统正在处理的所有鼠标事件。

这使您需要提供某种过滤过程,以便您可以过滤掉那些您不感兴趣的事件,例如......

    Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
        @Override
        public void eventDispatched(AWTEvent event) {
            Object source = event.getSource();
            if (source instanceof JComponent) {
                JComponent comp = (JComponent) source;
                if (SwingUtilities.isDescendingFrom(parent, comp)) {
                    // The mouse is in the house...
                }
            }
        }
    }, AWTEvent.MOUSE_MOTION_EVENT_MASK);
Run Code Online (Sandbox Code Playgroud)

(父级是你的主容器)

这基本上将一个附加AWTEventListener到主事件处理框架中,它将告诉您已处理的特定类型的所有事件。然后,在采取适当的行动之前,您需要检查相关事件是否确实发生在您感兴趣的环境(您自己或其中一个孩子)内......

Java 10(~ 8+?)/2018

自从我写了最初的答案以来,事件机制的工作方式似乎发生了一些变化(而且我也犯了一些小错误)

为了AWTListener生成事件,所有“感兴趣”的组件都需要注册鼠标事件

我做了一个非常基本的测试,创建一个普通的旧JPanel(和一个按钮)并将它们添加到父容器中并使用......

panel.addMouseListener(new MouseAdapter() {});
panel.addMouseMotionListener(new MouseAdapter() {});
add(panel);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
    @Override
    public void eventDispatched(AWTEvent event) {
        Object source = event.getSource();
        if (source instanceof JComponent) {
            JComponent comp = (JComponent) source;
            System.out.println(comp);
            if (SwingUtilities.isDescendingFrom(comp, TestPane.this)) {
                // The mouse is in the house...
                System.out.println("Mouse in the house");
            }
        }
    }
}, AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
Run Code Online (Sandbox Code Playgroud)

这为按钮和面板生成了事件