Search code examples
javaswingtimerpaintcomponent

Having two objects move in an SwingBot


I'm trying to make it so that both shapes move when the commands are pressed. My question is: How do I get the blue polygon to move along with the yellow rectangle? I can't seem to figure it out, no matter what I do. Any help is appreciated! thanks!

EDIT: Removed Timer Code (it is for something different)

import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.Color;
import java.awt.Polygon;
import java.util.Scanner;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;

public class Original {

    public static void main(String[] args) {    
        // contruction of new JFrame object
        JFrame frame = new JFrame();    
        // mutators
        frame.setSize(400,400);
        frame.setTitle("SwingBot");    
        // program ends when window closes
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
        Robot r = new Robot();
        frame.add(r);
        // voila!
        frame.setVisible(true);
        // your Scanner-based command loop goes here        
        int noend = 0;
        System.out.println("Type a Command:");
        while(noend == 0)
        {
             Scanner input = new Scanner(System.in);
             String command = input.next(); 
             if(command.equals("left"))
                 r.moveBot(-10,0);

             if(command.equals("right"))
                 r.moveBot(10,0);

             if(command.equals("down"))
                 r.moveBot(0,10);

             if(command.equals("up"))
                 r.moveBot(0,-10);
        }            
        // call methods on the Robot instance like w.moveBot(10,10) in response to
        // user input
    }    

    public static class Robot extends JComponent
    {
        private Rectangle rect = new Rectangle(20,60);
        private Polygon poly = new Polygon();

        public void paintComponent(Graphics g)
        {
            Graphics2D g2 = (Graphics2D) g;               
            // set the color
            g2.setColor(Color.ORANGE);                
            // draw the shape`
            g2.fill(rect);                
            int xPoly[] = {75, 125, 170, 170, 200, 105, 60};
            int yPoly[] = {75, 50, 88, 111, 125, 180, 150};    
            poly = new Polygon(xPoly, yPoly, xPoly.length); 
                super.paintComponent(g);
                g.setColor(Color.BLUE);
                g.drawPolygon(poly);                
        }

        public void moveBot(int x, int y)
        {
            // move the rectangle 
            rect.translate(x,y);
            poly.translate(x,y);
            // redraw the window
            repaint();
        }            
    }
}

Solution

  • Suggestions:

    • Don't create the shapes in the paintComponent method.
    • When creating them give them variables that can be changed
    • In the Timer or key press, or where ever you are trying to move them, change those variable and call repaint()
    • For multiple objects you can have a an interface like Shape where each Shape has a move() method that can be called.
    • Loop through an data structure of those objects and call their move() methods, then repaint()`
    • A Shape can have a drawShape(Graphics g) method, and you can loop through the data structure of Shape inside the paintComponent method and call drawShape(g)

    You can see this answer for an example.

    enter image description here


    UPDATE

    Here's an example of all the points I mention above.

    enter image description here

    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.AbstractAction;
    import javax.swing.ActionMap;
    import javax.swing.InputMap;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    import javax.swing.SwingUtilities;
    
    public class MoveShape extends JPanel {
    
        List<Shape> shapes;
    
        public MoveShape() {
            shapes = createShapeList();
    
            InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke("RIGHT"), "moveRight");
            ActionMap am = getActionMap();
            am.put("moveRight", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (Shape sh : shapes) {
                        sh.moveRight();
                        repaint();
                    }
                }
            });
        }
    
        private List<Shape> createShapeList() {
            List<Shape> list = new ArrayList<>();
            int xPoly[] = {75, 125, 170, 170, 200, 105, 60};
            int yPoly[] = {75, 50, 88, 111, 125, 180, 150};
            list.add(new MyPolygon(xPoly, yPoly, 6));
            list.add(new MyRectangle(75, 250, 150, 150));
            return list;
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Shape sh : shapes) {
                sh.drawShape(g);
            }
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(450, 450);
        }
    
        public class MyRectangle implements Shape {
    
            int x, y, width, height;
    
            public MyRectangle(int x, int y, int width, int height) {
                this.x = x;
                this.y = y;
                this.width = width;
                this.height = height;
            }
    
            @Override
            public void drawShape(Graphics g) {
                g.fillRect(x, y, width, height);
            }
    
            @Override
            public void moveRight() {
                x += INCREMENT;
            }
    
        }
    
        public class MyPolygon implements Shape {
    
            int[] xPoints;
            int[] yPoints;
            int numPoints;
    
            public MyPolygon(int[] xPoints, int[] yPoints, int numPoints) {
                this.xPoints = xPoints;
                this.yPoints = yPoints;
                this.numPoints = numPoints;
            }
    
            @Override
            public void drawShape(Graphics g) {
                g.fillPolygon(xPoints, yPoints, numPoints);
            }
    
            @Override
            public void moveRight() {
                for (int i = 0; i < xPoints.length; i++) {
    
                    xPoints[i] += INCREMENT;
    
                }  
            }
        }
    
        public interface Shape {
    
            public static final int INCREMENT = 5;
    
            public void drawShape(Graphics g);
    
            public void moveRight();
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JFrame frame = new JFrame("Move Shapes");
                    frame.add(new MoveShape());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setVisible(true);
                }
            });
        }
    }