Search code examples
javaswingawtpaintcomponentmouselistener

Move an Oval in java


I made a mini code that draw oval and link each other , now i try to move the oval(Circle) but I have a problem (in coding)

// Panneau.java
public class Panneau extends JPanel {
    private int R = 20;
    private boolean isDrag = false;
    String text = "stack";
    int x = 250, y = 200;
    int height = 50, width = 50;
    Random Rnd = new Random();
    int rand=Rnd.nextInt();
    int r=Math.abs(rand%250);
    int r2=Math.abs(rand%250);
    public Panneau() {
        addMouseListener(new MouseAdapter() {
            @Override
           public void mousePressed(MouseEvent e) {
                if ((x<=e.getX() && x+R>=e.getX()) && ( y<=e.getY() && y+R>=e.getY())) {
                    moveVertex(e.getX(),e.getY());
                    isDrag = true;
                }
            }

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

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (isDrag) moveVertex(e.getX(),e.getY());
            }
        });
    }

    private void moveVertex(int x1, int y1) {
        if ((x!=x1) || (y!=y1)) {
            x=x1-10;
            y=y1-10;
            repaint();
        }
    }

    @Override
    protected void paintComponent(Graphics g){
        // declaration
        super.paintComponent(g);
        g.setColor(Color.black);
        g.drawLine(x,y,x+r,y+r2);
        g.setColor(Color.yellow);
        g.fillOval(x-height/2, y-width/2,width, height);
        g.fillOval((x-height/2)+r, (y-width/2)+r2,width, height);
        FontMetrics fm = g.getFontMetrics();
        double textWidth = fm.getStringBounds(text, g).getWidth();
        g.setColor(Color.blue);
        g.drawString(text, (int) (x - textWidth/2),(int) (y + fm.getMaxAscent() / 2));
        g.drawString(text, (int) (x - textWidth/2)+r,(int) (y + fm.getMaxAscent() / 2)+r2);
    }


}

enter image description here I must move the two circles and the line must not move(Graph node) please help me and thanks :) After the update ( thanks to MadProgrammer) now I can move all the figure ( but if I clicked in the red circle only) , I want to move just circles thanks :)


Solution

  • Basically, because instead of using reapint(int, int) you could use repaint()

    private void moveVertex(int x1, int y1) {
        int OFFSET = 1;
        if ((x != x1) || (y != y1)) {
            x = x1 - 10;
            y = y1 - 10;
            repaint();
        }
    }
    

    This will ensure that the entire component is repainted.

    While I wouldn't discount the use of repaint(int, int), because your painting process is relatively simple, it's not going to provide you with a great deal of benefit at this stage

    Updated with additional example

    IF I understand, you want to be able to move a single node and have the line remain joined.

    While it might be possible to implement within the code you have available, a simpler soltution would be to take advantage of the 2D Graphics Shape API, this provides a number of really useful functions, including determining of points fall within a given shape.

    It also means you don't need to keep track of a large number of parameters, but instead, get a self contained object that just knows how it should be painted...

    enter image description here

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.geom.Ellipse2D;
    import java.awt.geom.Line2D;
    import java.awt.geom.Rectangle2D;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TestGraphNode {
    
        public static void main(String[] args) {
            new TestGraphNode();
        }
    
        public TestGraphNode() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new Panneau());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class Panneau extends JPanel {
    
            private int radius = 50;
            private String text = "stack";
    
            private List<Ellipse2D> nodes;
    
            private Ellipse2D dragged;
            private Point offset;
    
            public Panneau() {
                nodes = new ArrayList<>(25);
    
                nodes.add(new Ellipse2D.Float(50 - (radius / 2), 100 - (radius / 2), radius, radius));
                nodes.add(new Ellipse2D.Float(350 - (radius / 2), 100 - (radius / 2), radius, radius));
    
                addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
    
                        for (Ellipse2D node : nodes) {
    
                            if (node.contains(e.getPoint())) {
    
                                System.out.println("Clicked...");
                                dragged = node;
                                // Adjust for the different between the top/left corner of the
                                // node and the point it was clicked...
                                offset = new Point(node.getBounds().x - e.getX(), node.getBounds().y - e.getY());
                                // Highlight the clicked node
                                repaint();
                                break;
    
                            }
    
                        }
    
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        // Erase the "click" highlight
                        if (dragged != null) {
                            repaint();
                        }
                        dragged = null;
                        offset = null;
                    }
                });
    
                addMouseMotionListener(new MouseAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        if (dragged != null && offset != null) {
                            // Adjust the position of the drag point to allow for the
                            // click point offset
                            Point to = e.getPoint();
                            to.x += offset.x;
                            to.y += offset.y;
    
                            // Modify the position of the node...
                            Rectangle bounds = dragged.getBounds();
                            bounds.setLocation(to);
                            dragged.setFrame(bounds);
    
                            // repaint...
                            repaint();
                        }
    
                    }
                });
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 400);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                // declaration
                super.paintComponent(g);
    
                Graphics2D g2d = (Graphics2D) g.create();
                // Draw the connecting lines first
                // This ensures that the lines are under the nodes...
                Point p = null;
                for (Ellipse2D node : nodes) {
    
                    g2d.setColor(Color.BLACK);
                    Point to = node.getBounds().getLocation();
                    to.x += radius / 2;
                    to.y += radius / 2;
                    if (p != null) {
                        g2d.draw(new Line2D.Float(p, to));
                    }
                    p = to;
    
                }
                // Draw the nodes...
                for (Ellipse2D node : nodes) {
    
                    g2d.setColor(Color.yellow);
                    g2d.fill(node);
                    if (node == dragged) {
                        g2d.setColor(Color.BLUE);
                        g2d.draw(node);
                    }
                    g2d.setColor(Color.BLUE);
    
                    FontMetrics fm = g.getFontMetrics();
                    int textWidth = fm.stringWidth(text);
                    int x = node.getBounds().x;
                    int y = node.getBounds().y;
                    int width = node.getBounds().width;
                    int height = node.getBounds().height;
                    g.drawString(text,
                                    x + ((width - textWidth)) / 2,
                                    y + ((height - fm.getHeight()) / 2) + fm.getAscent());
    
                }
    
                g2d.dispose();
    
            }
    
        }
    }