Java 如何在ChildComponent上保留MouseListener,但正确跟踪父组件上的鼠标进出?

Java 如何在ChildComponent上保留MouseListener,但正确跟踪父组件上的鼠标进出?,java,swing,layout,components,cardlayout,Java,Swing,Layout,Components,Cardlayout,我有一个带有卡片布局和两张卡片的JPanel。我希望布局在每次鼠标进入或退出面板时翻转卡片。 除非其中一张卡是侦听鼠标事件的组件,否则这种方法可以正常工作。考虑下面的例子: JPanel cardLayoutPanel = new JPanel(layout); JButton button = new JButton("listening!"); JLabel label = new JLabel("not listening."); cardLayoutPanel.add(button);

我有一个带有卡片布局和两张卡片的JPanel。我希望布局在每次鼠标进入或退出面板时翻转卡片。 除非其中一张卡是侦听鼠标事件的组件,否则这种方法可以正常工作。考虑下面的例子:

JPanel cardLayoutPanel = new JPanel(layout);
JButton button = new JButton("listening!");
JLabel label = new JLabel("not listening.");
cardLayoutPanel.add(button);
cardLayoutPanel.add(label);
layout.last(cardLayoutPanel);
cardLayoutPanel.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseEntered(MouseEvent e) {
        System.out.println("entered!");
        layout.next(cardLayoutPanel);
    }

    @Override
    public void mouseExited(MouseEvent e) {
        System.out.println("exited!");
        layout.next(cardLayoutPanel);
    }
});
问题是,如果MouseEvent被子组件捕获,那么在许多与此主题相关的问题中,父组件不会将其作为read处理。 我尝试了不同的方法,比如重新修补事件,或者如果事件坐标仍在面板中,则忽略退出事件

第一个解决方案根本不起作用,第二个解决方案也不起作用。此后,鼠标输入的事件不再发生

我怎样才能解决这个问题

我现在看到的唯一解决方案是从子组件中完全删除侦听器,并在父鼠标侦听器中自己执行冲突和事件处理,但我想这将是一个混乱,不是预期的方法

感谢您的任何帮助或想法

编辑:下面是一个完整的简短可编译示例:

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class CardLayoutTest {

    public static void main(String[] args) {
        JFrame frame = new JFrame();

        JPanel content = new JPanel();
        content.setBorder(new EmptyBorder(new Insets(50, 50, 50, 50)));

        CardLayout layout = new CardLayout();
        JPanel cardLayoutPanel = new JPanel(layout);
        JButton button = new JButton("listening!");
        JLabel label = new JLabel("not listening.");
        cardLayoutPanel.add(button);
        cardLayoutPanel.add(label);
        layout.last(cardLayoutPanel);
        cardLayoutPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("entered!");
                layout.next(cardLayoutPanel);
            }


            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("exited!");
                layout.next(cardLayoutPanel);
            }
        });

        content.add(cardLayoutPanel);
        frame.add(content);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

这不是一个好的解决方案,但我通过在进入父组件时调用flip事件实现了我想要的。这是因为我的面板之间有足够的空间

然而,我并没有像评论中所说的那样,用玻璃窗来达到这种效果。也许我做错了,但是事件没有正确地到达组件,甚至一些瞬间的检查不知从哪里失败了


如果有人知道如何正确地做到这一点,我将很高兴看到

我稍微修改了你的示例,并使其生效。关键(至少在本例中)是让按钮与
cardLayoutPanel
共享相同的
mouseListener
。我不知道这是否是一个普遍的解决方案,但它确实在这里起作用。我还做了以下修改:

  • 为mouseListener添加了一个私有Inner类
  • 增加了cardLayoutPanel的大小
  • 为标签和按钮添加颜色边框

  • 鼠标事件是一种痛苦。只需添加一个鼠标侦听器就可以防止事件沿组件树向下传播!有损益表的地方,你无法确定发生了什么。重新修补为“玻璃窗格”应该会起作用。我知道,这正是这里的问题所在。损益表和财务报表是什么意思?你所说的“作为‘玻璃窗格’的redispatch”是什么意思?PL&F可插拔外观-使GUI看起来像一个特定平台的代码,无论是Windows、Metal、Gtk还是其他平台。应该有很多关于玻璃窗格的例子,玻璃窗格是容器顶部的一个组件,可以在鼠标事件通过时拦截鼠标事件。好的,谢谢你,我会看看是否可以用这种方法运行。非常感谢你的努力!我会看看a是否能让你的解决方案明天运行。好的。一项观察。我使用主程序中的
    按钮
    实例来
    单击按钮。更好的方法是从
    MouseEvent
    获取源代码并将其转换为JButton,然后使用它执行
    doClick
    。这样他们就可以共享相同的
    mouseListener
    事实上,我只是尝试了一下,以确保语法正确,所以我会修改我的答案。
    
        import java.awt.CardLayout;
        import java.awt.Color;
        import java.awt.Dimension;
        import java.awt.Insets;
        import java.awt.event.MouseAdapter;
        import java.awt.event.MouseEvent;
    
        import javax.swing.JButton;
        import javax.swing.JFrame;
        import javax.swing.JLabel;
        import javax.swing.JPanel;
        import javax.swing.border.EmptyBorder;
        import javax.swing.border.LineBorder;
    
        public class CardLayoutTest {
    
            JButton button = new JButton("listening!");
            JPanel cardLayoutPanel = new JPanel();
            CardLayout layout = new CardLayout();
    
            public static void main(String[] args) {
                new CardLayoutTest().start();
            }
    
            public void start() {
                JFrame frame = new JFrame();
    
                JPanel content = new JPanel();
                content.setBorder(new EmptyBorder(
                        new Insets(50, 50, 50, 50)));
    
                cardLayoutPanel.setLayout(layout);
                cardLayoutPanel
                        .setPreferredSize(new Dimension(200, 200));
                button.addActionListener(
                        ae -> System.out.println("IT WORKS!"));
                button.removeMouseMotionListener(
                        button.getMouseMotionListeners()[0]);
                button.removeMouseListener(
                        button.getMouseListeners()[0]);
    
                MyMouseListener ml = new MyMouseListener();
                button.addMouseListener(ml);
                button.setBorder(new LineBorder(Color.red, 2));
                JLabel label = new JLabel("not listening.");
                label.setBorder(new LineBorder(Color.blue, 2));
                cardLayoutPanel.add(button);
                cardLayoutPanel.add(label);
                layout.last(cardLayoutPanel);
                cardLayoutPanel.addMouseListener(ml);
    
                content.add(cardLayoutPanel);
                frame.add(content);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setDefaultCloseOperation(
                        JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
    
            private class MyMouseListener extends MouseAdapter {
    
                @Override
                public void mouseEntered(MouseEvent e) {
                        System.out.println("entered!");
                        layout.next(cardLayoutPanel);
    
                }
                public void mouseClicked(MouseEvent e) {
                    if (e.getSource() instanceof JButton) {
                        JButton b = (JButton)(e.getSource());
                        b.doClick();
                    }
                }
    
                @Override
                public void mouseExited(MouseEvent e) {
                        System.out.println("exited!");
                        layout.next(cardLayoutPanel);
                }
            }
        }