Search code examples
javauser-interfacemouselistenerjcomponent

Create a line between ellipses when the user drags from point a to point b


I have 6 vertices and the user should be able to create a line if the user drags the mouse for example, from vertex 1 to vertex 2. If the user released the mouse and the mouse didn't end up in one of the vertex, it won't create a line.

How do i do it?

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import javax.swing.JFrame;

public class DijkstraUI extends JComponent implements MouseListener {
    String zero = "0";
    String one = "1";
    String two = "2";
    String three = "3";
    String four = "4";
    String five = "5";

    Ellipse2D zeroOval = new Ellipse2D.Double(50,120,50,50);
    Ellipse2D oneOval = new Ellipse2D.Double(150,45,50,50);
    Ellipse2D twoOval = new Ellipse2D.Double(150,150,50,50);
    Ellipse2D threeOval = new Ellipse2D.Double(260,120,50,50);
    Ellipse2D fourOval = new Ellipse2D.Double(100,240,50,50);
    Ellipse2D fiveOval = new Ellipse2D.Double(200,250,50,50);

    Point pointStart = null;
    Point pointEnd = null;

    public DijkstraUI(){
    }

    public static void main(String args[]) {
        JFrame frame = new JFrame("Dijkstra: Finding the shortest path");
        DijkstraUI dj = new DijkstraUI();
        frame.getContentPane().add(dj);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setVisible(true);
        frame.setResizable(false);
    }

    @Override
    public void paint(Graphics g){
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(Color.WHITE);
        g2d.fill(zeroOval);
        g2d.fill(oneOval);
        g2d.fill(twoOval);
        g2d.fill(threeOval);
        g2d.fill(fourOval);
        g2d.fill(fiveOval);
        g2d.setPaint(Color.BLACK);
        g2d.drawString(zero,70,150);
        g2d.drawString(one,170,75);
        g2d.drawString(two,170,180);
        g2d.drawString(three,280,150);
        g2d.drawString(four,120,270);
        g2d.drawString(five,220,280);

        super.paint(g);
        if(pointStart != null)
            g2d.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if((e.getButton() == 1) || zeroOval.contains(e.getX(), e.getY())){
            System.out.print("test");
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
        pointStart = e.getPoint();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        pointStart = null;
    }

    public void mouseMoved(MouseEvent e) {
        pointEnd = e.getPoint();
    }

    public void mouseDragged(MouseEvent e) {
        pointEnd = e.getPoint();
        repaint();
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void mouseExited(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

Solution

  • It took a while, but I drew your lines.

    Shortest Path

    I made the following major changes to your code.

    1. I put the JFrame creation code in a Runnable, and called the SwingUtilities invokeLater method with the Runnable to put the creation and use of the Swing components on the Event Dispatch thread. Oracle and I insist that all Swing applications start on the Event Dispatch thread.

    2. I created a GUI model class, DijkstraModel. The DijkstraModel class contains a List of the ellipses and a list of the lines.

    3. I created a ellipse class, MyEllipse, to hold the Ellipse2D information and the ellipse label. Whenever you see yourself trying to keep two lists in sync, consider creating a Java getter / setter class to hold the fields.

    4. I created a line class, MyLine to hold the line end points.

    5. The paintComponent method was simplified because of the GUI model. I added a call to the super paintComponent method.

    6. I created a separate MouseListener class, MyMouseListener, because it was easier to deal with the listener in a static context when it's separate.

    Here's the modified code.

    package com.ggl.testing;
    
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.geom.Ellipse2D;
    import java.awt.geom.Point2D;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    public class DijkstraUI extends JComponent {
        private static final long serialVersionUID = 8838700175925828779L;
    
        private static MyMouseListener listener;
    
        private DijkstraModel model;
    
        public DijkstraUI() {
            this.model = new DijkstraModel();
            listener = new MyMouseListener(this, model);
        }
    
        public static void main(String args[]) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame("Dijkstra: Finding the shortest path");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    DijkstraUI dj = new DijkstraUI();
                    dj.addMouseListener(listener);
                    frame.getContentPane().add(dj);
    
                    frame.setSize(400, 400);
                    frame.setResizable(false);
                    frame.setVisible(true);
                }
            };
    
            SwingUtilities.invokeLater(runnable);
        }
    
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
    
            Graphics2D g2d = (Graphics2D) g;
    
            for (MyEllipse ellipse : model.getEllipseList()) {
                g2d.setPaint(Color.WHITE);
                Ellipse2D ellipse2d = ellipse.getEllipse();
                g2d.fill(ellipse2d);
                g2d.setPaint(Color.BLACK);
                g2d.drawString(ellipse.getLabel(),
                        (int) ellipse2d.getCenterX() - 5,
                        (int) ellipse2d.getCenterY() + 6);
            }
    
            for (MyLine myLine : model.getLineList()) {
                g2d.setPaint(Color.BLUE);
                g2d.drawLine(myLine.getFromPoint().x, myLine.getFromPoint().y,
                        myLine.getToPoint().x, myLine.getToPoint().y);
            }
        }
    
        public class MyMouseListener implements MouseListener {
    
            private JComponent component;
    
            private DijkstraModel model;
    
            private Point fromPoint;
    
            public MyMouseListener(JComponent component, DijkstraModel model) {
                this.component = component;
                this.model = model;
            }
    
            @Override
            public void mouseClicked(MouseEvent e) {
    
            }
    
            @Override
            public void mousePressed(MouseEvent e) {
                Point p = e.getPoint();
                Point2D p2d = new Point2D.Double((double) p.x, (double) p.y);
                p = getCenterPoint(p2d);
                if (p.x >= 0) {
                    fromPoint = p;
                }
            }
    
            @Override
            public void mouseReleased(MouseEvent e) {
                Point p = e.getPoint();
                Point2D p2d = new Point2D.Double((double) p.x, (double) p.y);
                p = getCenterPoint(p2d);
                if (p.x >= 0) {
                    model.addMyLine(new MyLine(fromPoint, p));
                    component.repaint();
                }
            }
    
            @Override
            public void mouseEntered(MouseEvent e) {
    
            }
    
            @Override
            public void mouseExited(MouseEvent e) {
    
            }
    
            private Point getCenterPoint(Point2D mousePoint) {
                for (MyEllipse ellipse : model.getEllipseList()) {
                    Ellipse2D ellipse2d = ellipse.getEllipse();
                    if (ellipse2d.contains(mousePoint)) {
                        Point p = new Point((int) ellipse2d.getCenterX(),
                                (int) ellipse2d.getCenterY());
                        return p;
                    }
                }
    
                return new Point(-1, -1);
            }
    
        }
    
        public class DijkstraModel {
            private List<MyEllipse> ellipseList;
            private List<MyLine> lineList;
    
            public DijkstraModel() {
                this.ellipseList = new ArrayList<>();
    
                this.ellipseList.add(new MyEllipse("0", new Ellipse2D.Double(50,
                        120, 50, 50)));
                this.ellipseList.add(new MyEllipse("1", new Ellipse2D.Double(150,
                        45, 50, 50)));
                this.ellipseList.add(new MyEllipse("2", new Ellipse2D.Double(150,
                        150, 50, 50)));
                this.ellipseList.add(new MyEllipse("3", new Ellipse2D.Double(260,
                        120, 50, 50)));
                this.ellipseList.add(new MyEllipse("4", new Ellipse2D.Double(100,
                        240, 50, 50)));
                this.ellipseList.add(new MyEllipse("5", new Ellipse2D.Double(200,
                        250, 50, 50)));
    
                this.lineList = new ArrayList<>();
            }
    
            public List<MyEllipse> getEllipseList() {
                return Collections.unmodifiableList(ellipseList);
            }
    
            public void addMyLine(MyLine myLine) {
                this.lineList.add(myLine);
            }
    
            public List<MyLine> getLineList() {
                return Collections.unmodifiableList(lineList);
            }
    
        }
    
        public class MyEllipse {
            private final String label;
            private final Ellipse2D ellipse;
    
            public MyEllipse(String label, Ellipse2D ellipse) {
                this.label = label;
                this.ellipse = ellipse;
            }
    
            public String getLabel() {
                return label;
            }
    
            public Ellipse2D getEllipse() {
                return ellipse;
            }
    
        }
    
        public class MyLine {
            private final Point fromPoint;
            private final Point toPoint;
    
            public MyLine(Point fromPoint, Point toPoint) {
                this.fromPoint = fromPoint;
                this.toPoint = toPoint;
            }
    
            public Point getFromPoint() {
                return fromPoint;
            }
    
            public Point getToPoint() {
                return toPoint;
            }
    
        }
    }