如何将MouseListener留在ChildComponent上,但正确跟踪鼠标在父组件上的进入和退出?

问题描述 投票:0回答:2

我有一个带有CardLayout和两张卡的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被子组件捕获,则父组件不会将它作为与该主题相关的许多SO问题中的读取对象进行处理。我尝试了不同的操作,例如重新分发事件,或者如果事件坐标仍在面板中,则忽略退出事件。

第一个解决方案根本不起作用,第二个解决方案都没有,因为从那以后不再发生鼠标输入事件。

我该如何解决?

我现在看到的唯一解决方案是将侦听器从子组件中完全删除,并在父级鼠标侦听器中自行执行碰撞和事件处理,但这将是一团糟,而不是预期的方式。我想这样做。

任何帮助或想法得到赞赏。

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

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);
    }
}
java swing layout components cardlayout
2个回答
1
投票

我稍微修改了您的示例,并使其生效。按键(至少在此示例中)是使按钮与mouseListener共享相同的cardLayoutPanel。我不知道这是否是通用解决方案,但它确实在这里起作用。我还进行了以下更改:

  1. 为mouseListener添加了一个私有内部类。
  2. 增加cardLayoutPanel的大小。
  3. 为标签和按钮添加了彩色边框。

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

0
投票

这不是一个好的解决方案,但是我通过entering parent component。时调用flip事件设法达到了我想要的目的。这是可行的,因为我的面板之间有足够的空间来使用此属性。

但是,我没有按照评论所建议的那样用玻璃板实现这种效果。也许我做错了,但是事件没有正确到达组件,甚至某些检查实例都失败了。

[如果有人知道如何正确执行此操作,我将很高兴见到。

© www.soinside.com 2019 - 2024. All rights reserved.