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