Having two objects move in an SwingBot

2020-02-07 04:56发布

问题:

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();
        }            
    }
}

回答1:

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.


UPDATE

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

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);
            }
        });
    }
}


回答2:

As @peeskillet has already pointed out...in your paintComponent method, you were re-creating the poly object each time it was called...meaning it never moved, and in fact was potential NullPointerException waiting to happen...

public void paintComponent(Graphics g)
{
    //...
    // This is a bad idea...        
    poly = new Polygon(xPoly, yPoly, xPoly.length);            
    //...
}

Instead, create the poloygon in the constructor to your Robot panel.

This example also demonstrates Initial Threads and key bindings and Stroking and Filling Graphics Primitives

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Original {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(400, 400);
                frame.setTitle("SwingBot");
                Robot r = new Robot();
                frame.add(r);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class Robot extends JComponent {

        private Rectangle rect = new Rectangle(20, 60);
        private Polygon poly = new Polygon();

        public Robot() {

            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);

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Down");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "Right");

            ActionMap am = getActionMap();

            am.put("Up", new MoveAction(0, -10));
            am.put("Down", new MoveAction(0, 10));
            am.put("Left", new MoveAction(-10, 0));
            am.put("Right", new MoveAction(10, 0));

        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g.create();

            // set the color
            g2.setColor(Color.ORANGE);

            // draw the shape`
            g2.fill(rect);

            g2.setColor(Color.BLUE);
            g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g2.drawPolygon(poly);
            g2.dispose();

        }

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

        public class MoveAction extends AbstractAction {

            private int xDelta;
            private int yDelta;

            public MoveAction(int xDelta, int yDelta) {
                this.xDelta = xDelta;
                this.yDelta = yDelta;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                moveBot(xDelta, yDelta);
            }
        }

    }
}

Please, make sure you give all credit to @peeskillet, I just wanted to highlight some problem areas and solutions you might consider