6

我有一个摆动组件,它有几个子组件。如果鼠标位于这些组件中的任何一个上,我想要更改一些标签,然后如果鼠标移出所有组件,则将其更改为其他标签。我正在尝试找到一种更有效的方法来做到这一点。

目前,我在所有看起来像这样的子组件上都有鼠标侦听器:

class AMouseListener extends MouseAdapter {
    private boolean mouseOver;
    mouseEntered(MouseEvent e) { mouseOver = true; updateLabel(); }
    mouseExited(MouseEvent e) { mouseOver = false; updateLabel(); }

    void updateLabel() {
       String text = "not-over-any-components";
       // listeners are each of the listeners added to the child components
       for ( AMouseListener listener :listeners ) {
          if ( listener.mouseOver ) {
             text = "over-a-component";
             break;
          }
       }
    }
}

这可行,但我觉得应该有更好的方法来处理这个问题,只处理父容器上的 mouseEntered 和 mouseExited 事件,但由于子组件拦截这些事件,我不知道如何去做(我不一定可以控制子组件,因此如果我愿意,我无法将鼠标事件转发给父事件)。

4

4 回答 4

7

例如

在此处输入图像描述

在此处输入图像描述

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;

public class TestMouseListener {

    public static void main(String[] args) {
        final JComboBox combo = new JComboBox();
        combo.setEditable(true);
        for (int i = 0; i < 10; i++) {
            combo.addItem(i);
        }
        final JLabel tip = new JLabel();
        tip.setPreferredSize(new Dimension(300, 20));
        JPanel panel = new JPanel();
        panel.add(combo);
        panel.add(tip);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
        panel.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseEntered(MouseEvent e) {
                tip.setText("Outside combobox");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                Component c = SwingUtilities.getDeepestComponentAt(
                   e.getComponent(), e.getX(), e.getY());
                // doesn't work if you move your mouse into the combobox popup
                tip.setText(c != null && SwingUtilities.isDescendingFrom(
                   c, combo) ? "Inside combo box" : "Outside combobox");
            }
        });
    }

    private TestMouseListener() {
    }
}
于 2012-06-18T22:22:35.623 回答
2

查看“玻璃窗格”的文档和示例。
这应该给你你需要的东西:玻璃窗格

于 2012-06-18T21:54:51.417 回答
1

您可以启动侦听器的单个实例并将该实例添加到每个组件。像这样:

AMouseListener aMouseListener=new  AMouseListener();

for each(Component c:components) {
caddMouseListener(aMouseListener);
}
于 2012-06-18T22:05:54.390 回答
1

我知道这已经很老了,但这是一个简单的解决方案,您可以使用它为组件及其边界内的所有组件创建鼠标侦听器(无需单独将侦听器添加到所有组件):

/**
 * Creates an {@link AWTEventListener} that will call the given listener if
 * the {@link MouseEvent} occurred inside the given component, one of its
 * children or the children's children etc. (recursive).
 * 
 * @param component
 *            the component the {@link MouseEvent} has to occur inside
 * @param listener
 *            the listener to be called if that is the case
 */
public static void addRecursiveMouseListener(final Component component, final MouseListener listener) {
    Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

        @Override
        public void eventDispatched(AWTEvent event) {
            if(event instanceof MouseEvent) {
                MouseEvent mouseEvent = (MouseEvent) event;
                if(mouseEvent.getComponent().isShowing() && component.isShowing()){
                    if (containsScreenLocation(component, mouseEvent.getLocationOnScreen())) {
                        if(event.getID() == MouseEvent.MOUSE_PRESSED) {
                            listener.mousePressed(mouseEvent);
                        }
                        if(event.getID() == MouseEvent.MOUSE_RELEASED) {
                            listener.mouseReleased(mouseEvent);
                        }
                        if(event.getID() == MouseEvent.MOUSE_ENTERED) {
                            listener.mouseEntered(mouseEvent);
                        }
                        if(event.getID() == MouseEvent.MOUSE_EXITED) {
                            listener.mouseExited(mouseEvent);
                        }
                        if(event.getID() == MouseEvent.MOUSE_CLICKED){
                            listener.mouseClicked(mouseEvent);
                        }
                    }
                }
            }
        }
    }, AWTEvent.MOUSE_EVENT_MASK);
}

/**
 * Checks if the given location (relative to the screen) is inside the given component
 * @param component the component to check with
 * @param screenLocation the location, relative to the screen
 * @return true if it is inside the component, false otherwise
 */
public static boolean containsScreenLocation(Component component, Point screenLocation){
    Point compLocation = component.getLocationOnScreen();
    Dimension compSize = component.getSize();
    int relativeX = screenLocation.x - compLocation.x;
    int relativeY = screenLocation.y - compLocation.y;
    return (relativeX >= 0 && relativeX < compSize.width && relativeY >= 0 && relativeY < compSize.height);
}

注意:一旦鼠标退出此侦听器的根组件,mouseExited(mouseEvent)可能不会触发,但是您可以将鼠标侦听器添加到根组件本身,它应该会触发。
mouseExited(mouseEvent)虽然一般来说是不可靠的。

于 2019-08-08T16:58:12.713 回答