Search code examples
javaswingawtmouselistenermousemotionlistener

How to have a MotionListener called on a JPanel that is covered


This question is to help me solve my other question. I have a JPanel that is completely covered by JLabels. I have added a MotionListener to the panel but it is never called since the labels are in the way. If I remove the labels my MotionnListener is called properly.

Is there a way I can have the covered panel see the motion events?

public class ChangesAttempt extends JPanel {
    private static final long serialVersionUID = -8031881678612431401L;

    static JFrame frame;
    static JPanel grid;
    static JLabel[][] squares;
    static boolean[][] litSquares;
    static int size, boardSize;
    MouseEvent listener = new MouseEvent();
    MotionListener mListerner = new MotionListener();
    Color backGround = Color.BLUE;
    Color selected = Color.PINK;

    public ChangesAttempt(int size) {
        ChangesAttempt.size = size;
        squares = new JLabel[size][size];
        litSquares = new boolean[size][size];
        grid = new JPanel(new GridLayout(size, size));
        grid.addMouseMotionListener(mListerner);
        /*Coment out setBoard(); below to see the mousedDragged method actually being called
        since the JLabels will not be in the way.*/
        setBoard();

        frame = new JFrame();
        frame.setLayout(new BorderLayout());
        frame.add(grid, BorderLayout.CENTER);
        frame.setTitle("ChangedLife");
        if (25 * size < 525)
            boardSize = 525;
        else
            boardSize = 25 * size;
        frame.setSize(boardSize, boardSize);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    class MouseEvent implements MouseListener {

        @Override
        public void mousePressed(java.awt.event.MouseEvent e) {
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    if (e.getSource() == squares[i][j]) {
                        if (litSquares[i][j] == false) {
                            squares[i][j].setBackground(selected);
                            litSquares[i][j] = true;
                        } else {
                            squares[i][j].setBackground(backGround);
                            litSquares[i][j] = false;
                        }
                    }
                }
            }
        }

        @Override
        public void mouseClicked(java.awt.event.MouseEvent e) {
        }

        @Override
        public void mouseEntered(java.awt.event.MouseEvent e) {
        }

        @Override
        public void mouseExited(java.awt.event.MouseEvent e) {
        }

        @Override
        public void mouseReleased(java.awt.event.MouseEvent e) {
        }
    }

    class MotionListener implements MouseMotionListener {
        @Override
        public void mouseDragged(java.awt.event.MouseEvent e) {
            Point p = e.getPoint();
            System.out.println("mouse Dragged to " + p);
        }

        @Override
        public void mouseMoved(java.awt.event.MouseEvent e) {
            // TODO Auto-generated method stub

        }
    }

    public void setBoard() {
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                squares[i][j] = new JLabel();
                squares[i][j].addMouseListener(listener);
                squares[i][j].setOpaque(true);
                squares[i][j].setBackground(backGround);
                grid.add(squares[i][j]);
            }
        }
    }

    class MyLabel extends JLabel {
        private static final long serialVersionUID = -1414933339546989142L;

    }

    public static void main(String args[]) {
        new ChangesAttempt(20);
    }
}

Solution

  • There's no "easy" way to achieve this, it might be better to move all you mouse listeners to the panel instead.

    This would require you to look up the component (that's within the parent component) at the specified click point, for example...

    @Override
    public void mousePressed(java.awt.event.MouseEvent e) {
        Component component = e.getComponent();
        Component source = component.getComponentAt(e.getPoint());
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (source == squares[i][j]) {
                    if (litSquares[i][j] == false) {
                        squares[i][j].setBackground(selected);
                        litSquares[i][j] = true;
                    } else {
                        squares[i][j].setBackground(backGround);
                        litSquares[i][j] = false;
                    }
                }
            }
        }
    }
    

    This will work, if you remove the MouseListener from the labels and instead, add it to the grid, allowing with your MouseMotionListener