简体   繁体   中英

Mouse Listener Event for different JPanels

Is is possible to have a global mouse motion listener that has different effects depending on what JPanel is clicked (with only using one mouse motion listener)?

For example: I have a JFrame with two added JPanels and a mouse motion listener added to the JFrame. I want the screen to resize when I click on one JPanel, but I want the JFrame to be dragged around when I click the other. I think this can be done using JLabels using the text of the JLabel to check against, same with a JButton.

EDIT: yes this is definitly not the proper way to do things but just wondering if it is possible, if so, how?

EDIT: Just to make things a bit more clearer, I have one class that extends ActionListener, MouseMotionListener, MouseListener. is it possible to have this one class handle all events of a JFrame that has lots of different JPanels attached to it and do something different based off of which JPanel was pressed? (such as having an ID attached to JPanels that I can compare the event.getSource() with)

First of all, a "global" listener, that does different things for different components, is a bad idea, it places too much logic into a single, couples the code and becomes a maintenance nightmare.

Having said that, you could use a single MouseListener add to each component, for example...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JPanel left = new TestPane();
                JPanel right = new TestPane();

                left.setBackground(Color.RED);
                right.setBackground(Color.BLUE);

                left.setName("left");
                right.setName("right");

                MouseListener listener = new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        System.out.println(((JPanel)e.getSource()).getName());
                    }
                };

                left.addMouseListener(listener);
                right.addMouseListener(listener);

                JFrame frame = new JFrame("Testing");
                frame.setLayout(new GridLayout(0, 2));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(left);
                frame.add(right);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}

Then you could simple use MouseEvent#getSource to determine which component triggered the event. For simplicity, I've supplied a name for each panel and displayed that, I would use some other way to identify the component before making a decision about what to do.

The better solution would be to provide a specific MouseListener which did a specific job to the each panel as required, this becomes much easier to manage, isolates responsibility, decouples the code and becomes easier to maintain and manage

I'm not sure if this is the best way to do it, but I just tested it and it does work, at least as far as my code tests it. Find which box the mouse is over when it's pressed and do stuff accordingly.

public static void main(String[] args) {
    JFrame main = new JFrame("test");
    JPanel first = new JPanel();
    JPanel second = new JPanel();
    first.setSize(400, 500);
    first.setBackground(Color.BLUE);
    second.setBackground(Color.RED);
    second.setSize(400,500);
    main.setSize(800, 500);
    main.add(first);
    first.setLocation(0,0);
    second.setLocation(400, 500);
    main.add(second);
    main.pack();
    main.setVisible(true);
    main.setSize(800, 500);
    main.addMouseListener(new MouseListener() {

        @Override
        public void mousePressed(MouseEvent e) {
            if(first.getBounds().contains(new Point(e.getX(), e.getY())))
            {
                System.out.println("first box");
            }else if(second.getBounds().contains(new Point(e.getX(), e.getY())))
            {
                System.out.println("Second box");
            }
        }
    });
}

EDIT 2

This should be your answer, I noticed on debugging that when I click on empty area on the frame I get a component with the name "null.contentPane" so I put it in the condition and it worked!, I hope I helped.

public class PanelsListener extends JFrame {

public static void main(String[] args) {
    PanelsListener pl = new PanelsListener();
    pl.setSize(700, 700);
    pl.setLayout(new FlowLayout());
    JPanel fp = new JPanel();

    fp.setName("First");
    fp.setSize(200, 200);
    fp.setBorder(new LineBorder(Color.red));
    JPanel sp = new JPanel();
    sp.setName("Second");
    sp.setSize(200, 200);
    sp.setBorder(new LineBorder(Color.blue));
    pl.add(fp);
    pl.add(sp);

    pl.addMouseListener(new MouseListener() {
        @Override
        public void mouseClicked(MouseEvent e) {
            JPanel pnl = (JPanel) javax.swing.SwingUtilities
                    .getDeepestComponentAt((PanelsListener) e.getSource(),
                            e.getX(), e.getY());
            if (pnl != null && (!pnl.getName().equals("null.contentPane"))) {
                String name = pnl.getName();
                if (name != null) {
                    if (name.equals("First")) {
                        pl.setSize(500, 500);
                    } else if (name.equals("Second")) {
                        pl.setSize(800, 800);
                    }
                    pl.repaint();
                }
            }

        }

        @Override
        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseExited(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mousePressed(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub

        }
    });

    pl.setVisible(true);
}

}

EDIT 1

As I understand from your comment, try instead the following:

public class PanelsListener extends JFrame{

public static int  panel_identifier=0;

public static void main(String[] args) {
    PanelsListener pl = new PanelsListener();
    pl.setSize(700, 700);
    pl.setLayout(new FlowLayout());
    JPanel fp=new JPanel();
    fp.setSize(200,200);
    fp.setBorder(new LineBorder(Color.red));
    JPanel sp=new JPanel();
    sp.setSize(200,200);
    sp.setBorder(new LineBorder(Color.blue));

    pl.add(fp);
    pl.add(sp);

    //panel_identifier is used to specify which panel has been clicked.

    fp.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent me) {
           pl.panel_identifier=1;
           pl.mouseClicked(me);
        }
    });
    sp.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent me) {
            pl.panel_identifier=2;
             pl.mouseClicked(me);
        }
    });

    pl.setVisible(true);
}
protected void mouseClicked(MouseEvent me) {
    if(panel_identifier==1)
    {
        this.setSize(500, 500);
        panel_identifier=0;
    }
    else if(panel_identifier==2)
    {
        this.setSize(800, 800);
        panel_identifier=0;
    }

}
}

Normal Solution

public class PanelsListener extends JFrame {

public static void main(String[] args) {
    PanelsListener pl = new PanelsListener();
    pl.setSize(700, 700);
    pl.setLayout(new FlowLayout());
    pl.add(new FirstPanel(pl));
    pl.add(new SecondPanel(pl));
    pl.setVisible(true);
}
}

class FirstPanel extends JPanel {

public FirstPanel(Frame frm) {
    setBorder(new LineBorder(Color.red));
    setSize(200, 200);
    addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            frm.setSize(500, 500);
            frm.repaint();
        }
    });
    addMouseMotionListener(new MouseAdapter() {
        @Override
        public void mouseDragged(MouseEvent e) {
            // do some action when mouse dragged over this panel
        }
    });
 }
 }

 class SecondPanel extends JPanel {

 public SecondPanel(Frame frm) {
    setBorder(new LineBorder(Color.blue));
    setSize(200, 200);
     addMouseListener(new MouseAdapter() {
     @Override
     public void mouseClicked(MouseEvent e) {
     frm.setSize(800,800);
     frm.repaint();
     }
     });

    addMouseMotionListener(new MouseAdapter() {
        @Override
        public void mouseDragged(MouseEvent e) {
            // do some action when mouse dragged over this panel
        }
    });
 }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM