Как оставить MouseListener на ChildComponent, но правильно отслеживать вход и выход мыши на родительском? - PullRequest
0 голосов
/ 11 января 2020

У меня есть JPanel с 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);
    }
});

Проблема в том, что если MouseEvent отлавливается дочерним компонентом, он не обрабатывается родительским объектом как чтение во многих SO-вопросах, связанных с этой топикой * 1016. *. Я пробовал разные вещи, такие как повторная отправка события или просто игнорирование события выхода, если событие, если координаты события все еще находятся на панели.

Первое решение вообще не работает, второе и с тех пор событие ввода мышью больше не происходит.

Как я могу решить эту проблему?

Единственное решение, которое я вижу сейчас, - полностью удалить слушателя из дочернего компонента и самостоятельно выполнить обработку столкновений и событий в родителях. мышь слушатель мыши, но это было бы беспорядок, а не предполагаемый способ сделать это, я думаю.

Любая помощь или идеи приветствуются.

РЕДАКТИРОВАТЬ: вот полный короткий компилируемый пример:

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

Ответы [ 2 ]

1 голос
/ 11 января 2020

Я немного изменил ваш пример и заставил его работать. Ключ (по крайней мере, в этом примере) должен был обеспечить общий доступ к кнопке mouseListener с cardLayoutPanel. Я не знаю, является ли это универсальным решением, но оно работает здесь. Я также внес следующие изменения:

  1. добавлен собственный класс innner для 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 голосов
/ 11 января 2020

Не очень хорошее решение, но мне удалось добиться того, что я хочу, вызвав событие flip, когда ввод родительского компонента . Это работает, так как у меня достаточно места между моими панели с этим свойством.

Однако мне не удалось добиться этого эффекта с помощью стеклянных панелей, как это было предложено в комментарии. Возможно, я делал это неправильно, но события не поступали к компонентам должным образом, даже некоторые экземпляры проверок никуда не делись.

Если кто-то знает, как это сделать правильно, я был бы рад видеть.

...