Harry
Harry

Reputation: 782

Adding multiple MouseListeners dynamically JPanel

I am trying to add shapes onto a window using JPanel and then be able to click and drag them around the window. This works if I only have one shape; but when I add more shapes, the click and drag is very funky. It does drag but not with the mouse, it isn't proportional and doesn't drag with the mouse.

Any help is appreciated. Thanks!

public class SimpleDraw {

    public static void main(String[] args) {

        JFrame frame = new UMLWindow();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(30, 30, 1000, 700);
        frame.getContentPane().setBackground(Color.white);
        frame.setVisible(true);
        frame.setLocationRelativeTo(null);

        // Display the window.
        frame.setVisible(true);

    }
}

class UMLWindow extends JFrame {
    Squares squares = new Squares();

    private static final long serialVersionUID = 1L;

    public UMLWindow() {
        addMenus();
    }

    public void addMenus() {

        getContentPane().add(squares);

        JMenuBar menubar = new JMenuBar();

        JMenu shapes = new JMenu("Shapes");

        JMenuItem rectangleMenuItem = new JMenuItem("New Rectangle");
        rectangleMenuItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                squares.addSquare(10, 10, 100, 100);
            }
        });

        shapes.add(rectangleMenuItem);

        menubar.add(shapes);

        setJMenuBar(menubar);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

}

class Squares extends JPanel {
    private static final long serialVersionUID = 1L;

    private List<Path2D> squares = new ArrayList<Path2D>();
    // private Path2D rect = new Path2D.Double();
    int currentIndex;

    public void addSquare(int x, int y, int width, int height) {
        Path2D rect2 = new Path2D.Double();
        rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
                - height / 2, width, height), true);

        squares.add(rect2);
        // rect = rect2;
        MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
        addMouseListener(myMouseAdapter);
        addMouseMotionListener(myMouseAdapter);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        this.setOpaque(true);
        this.setBackground(Color.WHITE);
        Graphics2D g2 = (Graphics2D) g;
        for (Path2D rect : squares) {
            g2.draw(rect);
        }
        repaint();
    }

    class MyMouseAdapter extends MouseAdapter {
        private boolean pressed = false;
        private Point point;

        @Override
        public void mousePressed(MouseEvent e) {
            if (e.getButton() != MouseEvent.BUTTON1) {
                return;
            }
            for (int i = 0; i < squares.size(); i++) {
                if (squares.get(i) != null
                        && squares.get(i).contains(e.getPoint())) {
                    currentIndex = i;
                    pressed = true;
                    this.point = e.getPoint();
                }
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (pressed) {
                int deltaX = e.getX() - point.x;
                int deltaY = e.getY() - point.y;
                squares.get(currentIndex).transform(
                        AffineTransform.getTranslateInstance(deltaX, deltaY));
                point = e.getPoint();
                repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            pressed = false;
        }
    }

}

Upvotes: 1

Views: 84

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Lot of problems...

  • Most important, no you don't want to add a bunch of MouseListeners/MouseMotionListeners to your JPanel. You only want to add one, and have it control any and all squares that the JPanel holds.
  • Don't put a repaint() in your paintComponent method as that's a poor way to try to create an animation loop, a loop that you have absolutely no control over. Plus there's no need. The MouseAdapter should drive all the animation by itself.

class Squares extends JPanel {
   private static final long serialVersionUID = 1L;

   public Squares() {
      MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
      addMouseListener(myMouseAdapter);
      addMouseMotionListener(myMouseAdapter);
   }

   private List<Path2D> squares = new ArrayList<Path2D>();
   // private Path2D rect = new Path2D.Double();
   int currentIndex;

   public void addSquare(int x, int y, int width, int height) {
      Path2D rect2 = new Path2D.Double();
      rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
            - height / 2, width, height), true);

      squares.add(rect2);
      repaint(); // !!
      // rect = rect2;
      // !! MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
      // addMouseListener(myMouseAdapter);
      // addMouseMotionListener(myMouseAdapter);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      this.setOpaque(true);
      this.setBackground(Color.WHITE);
      Graphics2D g2 = (Graphics2D) g;
      for (Path2D rect : squares) {
         g2.draw(rect);
      }
      // !! repaint();

}

Upvotes: 2

Related Questions