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

时间:2015-02-25 20:13:18

标签: java swing

我创建了一个包含不同组件的JPanel的JFrame,例如,当鼠标位于JPanel的边界内时,我希望JPanel具有可见边框和可见图像。我的问题是,只要鼠标悬停在"可互动的"在JPanel内部的组件,它会在鼠标退出JPanel时注册。我希望只要它在JPanel的范围内绘制这些东西,当鼠标退出JPanel的界限时,边框和图像就会消失。#34; 。有没有办法实现这个目标?

这是一个小小的演示:

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);
        }

    }

}

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

3 个答案:

答案 0 :(得分:4)

这实际上听起来要困难得多。您需要能够监视容器的子组件的所有鼠标事件。不幸的是,你要么得到一个全有或全无的解决方案。也就是说,你要么得到你现在遇到的问题,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);

(父母是你的主要容器)

这基本上将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);

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

答案 1 :(得分:2)

一种解决方案是为JPanel中的每个子组件添加一个鼠标监听器。

使用您的代码,这是一种方式:

package com.ggl.testing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class HoverTest {

    /**
     * @param args
     *            the command line arguments
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                HoverTest hoverTest = new HoverTest();
                hoverTest.new TestFrame();
            }
        });
    }

    public class TestFrame extends JFrame {
        private static final long serialVersionUID = 6304847277329579360L;

        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);

            ButtonListener listener = new ButtonListener(appearingButton);

            panel.add(hoverButton);
            panel.add(appearingButton);
            panel.addMouseListener(listener);

            hoverButton.addMouseListener(listener);
            appearingButton.addMouseListener(listener);

            add(panel);

            setSize(new Dimension(200, 200));
            setVisible(true);
        }

    }

    private class ButtonListener extends MouseAdapter {

        private JButton appearingButton;

        public ButtonListener(JButton appearingButton) {
            this.appearingButton = appearingButton;
        }

        @Override
        public void mouseEntered(java.awt.event.MouseEvent evt) {
            System.out.println("Entered!");
            appearingButton.setVisible(true);
        }

        @Override
        public void mouseExited(java.awt.event.MouseEvent evt) {
            System.out.println("Exited!");
            appearingButton.setVisible(false);
        }
    }

}

答案 2 :(得分:0)

这实际上比你想象的容易得多:

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) {
           if( ! panel.contains( evt.getPoint() ) ){
                System.out.println("Exited!");
                appearingButton.setVisible(false);
           }
      }
});

if 语句将过滤掉鼠标仍位于面板内时发生的所有 mouseExited 事件。

结果是,您最终会收到多个 mouseEntered 事件,但这些事件之间没有 mouseExited ,但由此引起的任何问题都可以轻松避免。