Search code examples
javaswingpaintcomponentmouselistener

Java Graphics: connect dots through a 2D line


I am new to Java and I would like to create a very simple draw-GUI, in which the user draws simple forms clicking on the panel and connecting different spots with a line when mouse is pressed in a position and released in another (drag-and-drop). Spots and lines should be stored in two ArrayLists. I managed to get the spots on the panel when clicked but the line is changing coordinates every time the mouse is dropped and a further point is created. I tried many times but I don´t know how to make the lines remain on the panel and "trace" the drag-and-drop-activity.

Thank you in advance for every tip!


import java.util.ArrayList;
import java.util.Arrays;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Line2D;
import java.awt.geom.Line2D.Double;

import javax.swing.JPanel;

public class PaintPanel extends JPanel {

    private ArrayList<Point> pointList;
    private ArrayList<Line2D.Double> lineList;
    private Point point1, point2;
    private Line2D line;
    public PaintPanel() {

        pointList = new ArrayList<Point>();
        lineList = new ArrayList<Line2D.Double>();
        addMouseListener(new PaintListener());

    }

    //takes as parameter objekt of Class Graphics
    public void paintComponent(Graphics g) {
        // calls constructor of SuperClass 
        super.paintComponent(g);

        this.setBackground(Color.white);
        // color to draw
        g.setColor(Color.black);

        for(Point spot : pointList) {
            g.fillOval(spot.x,spot.y, 10, 10);
            if(point1 != null & point2 !=null) {
                Graphics2D g2 =(Graphics2D) g;
                line = new Line2D.Double(point1.getX(), point1.getY(), point2.getX(), point2.getY());
                lineList.add((Double) line);
                g2.draw(line);
            }


        }

    }


    private class PaintListener implements MouseListener{

        @Override
        public void mouseClicked(MouseEvent e) {
        }

        @Override
        public void mousePressed(MouseEvent e) {
            point1 = e.getPoint();
            pointList.add(point1);
            repaint();

        }
        public void mouseDragged(MouseEvent e) {

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            point2 = e.getPoint();
            pointList.add(point2);
            repaint();
        }

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

        }

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

        }



    }

}

Solution

  • I have recreated what you are trying to do, I've added code comments to help you through the process.

    The program starts with a set of points that you can join with lines and also you can add more points by right clicking.

    You would need to implement MouseMotionListener along with MouseListener (as seen below) as this would allow you to track all of the mouse's actions.

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import java.util.ArrayList;
    import javax.swing.*;
        
    public class PaintPanel extends JPanel implements MouseListener, MouseMotionListener {
    
    //ARRAYLIST OF ALL POINTS
    public ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();
    
    //ARRAYLIST OF ALL LINES
    public ArrayList<Line2D.Double> lines = new ArrayList<Line2D.Double>();
    
    //START POINT OF A NEW LINE
    public Point2D.Double startPoint;
    
    //CURRENT MOUSE LOCATION
    public Point2D.Double mouse = null;
    
    //TRUE IF USER IS DRAGGING
    public boolean dragging = false;
    
    //THE SIZE OF THE POINTS
    public int pointSize = 20;
    
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        PaintPanel stage = new PaintPanel();
        stage.setBackground(new Color(47, 47, 47));
        stage.setPreferredSize(new Dimension(1000, 1000));
        stage.addMouseListener(stage);
        stage.addMouseMotionListener(stage);
        frame.setContentPane(stage);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    public PaintPanel() {
    
        //ADDING POINTS TO THE CANVAS
        for (int i = 1; i < 10; i++)
            for (int j = 1; j < 10; j++)
                points.add(new Point2D.Double(100 * i, j * 100));
    
    }
    
    public void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        Graphics2D g2 = (Graphics2D) graphics;
        
        //MAKING IT LOOK NICER
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setStroke(new BasicStroke(2));
    
        //DRAWING CURRENTLY DRAGGING LINE
        if (dragging && startPoint != null) {
            g2.setColor(Color.WHITE);
            g2.drawLine((int) startPoint.x, (int) startPoint.y, (int) mouse.x, (int) mouse.y);
        }
        
        //DRAWING ALL THE LINES
        for (int i = 0; i < lines.size(); i++) {
            g2.setColor(Color.WHITE);
            Line2D l = lines.get(i);
            g2.drawLine((int) l.getX1(), (int) l.getY1(), (int) l.getX2(), (int) l.getY2());
        }
        
        //DRAWING ALL THE POINTS
        for (int i = 0; i < points.size(); i++) {
            Point2D.Double p = points.get(i);
            g2.setColor(Color.WHITE);
            g2.fillRoundRect((int) (p.x - (pointSize / 2)), (int) (p.y - (pointSize / 2)), pointSize, pointSize, pointSize, pointSize);
        }
    }
    
    @Override
    public void mousePressed(MouseEvent e) {
        
        //ADD POINTS WITH RIGHT CLICK
        if (SwingUtilities.isRightMouseButton(e)) {
            mouse = new Point2D.Double(e.getX(), e.getY());
            points.add(new Point2D.Double(e.getX(), e.getY()));
        }
        repaint();
    }
    
    @Override
    public void mouseReleased(MouseEvent e) {
        if (SwingUtilities.isLeftMouseButton(e)) {
            mouse = new Point2D.Double(e.getX(), e.getY());
            
            //IF THE USER HAS BEEN DRAGGING WHEN MOUSE RELEASED...
            if (dragging) {
                for (int i = 0; i < points.size(); i++) {
                    Point2D.Double p = points.get(i);
                    //IF THE USER FINISHED DRAGGING AT A POINT...
                    if (p.distance(mouse) < pointSize / 2) {
                        lines.add(new Line2D.Double(startPoint, p));
                    }
                }
            }
            startPoint = null;
            dragging = false;
        }
        repaint();
    }
    
    @Override
    public void mouseDragged(MouseEvent e) {
        if (SwingUtilities.isLeftMouseButton(e)) {
            mouse = new Point2D.Double(e.getX(), e.getY());
            dragging = true;
            for (int i = 0; i < points.size(); i++) {
                Point2D.Double p = points.get(i);
                //IF THE USER STARTED DRAGGING ON A POINT...
                if (p.distance(mouse) < pointSize / 2 && startPoint == null) {
                    startPoint = p;
                }
            }
        }
        repaint();
    }
    
    //UNUSED METHODS
    @Override
    public void mouseMoved(MouseEvent e) {}
    @Override
    public void mouseClicked(MouseEvent e) {}
    @Override
    public void mouseEntered(MouseEvent e) {}
    @Override
    public void mouseExited(MouseEvent e) {}
    

    }