My paintComponent draw something that I didn't code - java

I made a big aqua square, but somehow, a little gray square appeared in my JPanel, it looks like this.
Theres the little gray square there in the middle and I didn't draw it. How do I avoid it? Heres my code:
my Main:
package Main;
public class main {
public static void main(String[] args) {
createWindow window = new createWindow();
}
}
myFrame and myPanel:
package Main;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import Objects.Piece;
public class createWindow extends JFrame {
public myPanel panel;
public createWindow() {
super();
panel = new myPanel();
KeyListener key = new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
keyAction(e.getKeyCode());
}
public void keyAction(int keycode) {
switch (keycode) {
case KeyEvent.VK_UP:
System.out.println("Up");
break;
case KeyEvent.VK_RIGHT:
System.out.println("Right");
break;
case KeyEvent.VK_DOWN:
System.out.println("Down");
break;
case KeyEvent.VK_LEFT:
System.out.println("Left");
break;
}
}
};
pack();
add(panel);
addKeyListener(key);
setSize(800, 450);
setResizable(false);
setLocationRelativeTo(null);
setVisible(true);
}
}
class myPanel extends JPanel {
public Piece firstP = new Piece(100, 100, 100, 100, new Color(50, 255, 255), "self");
myPanel() {
super();
setBackground(Color.gray);
add(firstP);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(firstP.color);
g2d.fillRect(firstP.x,firstP.y, firstP.width, firstP.height);
}
}
myPiece:
package Objects;
import java.awt.*;
import javax.swing.*;
public class Piece extends JPanel {
public int x;
public int y;
public int width;
public int height;
public Color color;
public String type;
public Piece(int x, int y, int width, int height, Color color, String type) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.type = type;
}
}
Can someone fix my code? I am new to java paint and I can't see the bug here...

Related

My repaint() method is not calling the paintComponent() from another class

I made a box from another class that extends JPanel, the thing is, the paintComponent() is not getting called after I do repaint() from another class. I don't know how repaint works and I am trying to practice some work.
Here's my JFrame:
package Main;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
import KeyActions.keyActions;
import Objects.Piece;
public class createWindow extends JFrame {
public createWindow() {
super();
myPanel panel = new myPanel();
keyActions actions = new keyActions();
KeyListener key = new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
keyAction(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
}
public void keyAction(int keycode) {
switch (keycode) {
case KeyEvent.VK_UP:
actions.keyUP();
break;
case KeyEvent.VK_RIGHT:
break;
case KeyEvent.VK_DOWN:
break;
case KeyEvent.VK_LEFT:
break;
}
}
};
add(panel);
addKeyListener(key);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setResizable(false);
setLocationRelativeTo(null);
setVisible(true);
}
}
Here's my code from the JPanel:
package Main;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import Objects.Piece;
public class myPanel extends JPanel {
//main character
public Piece innerLayer = new Piece(25, 25, 50, 50, new Color(255, 255, 0), "self");
public myPanel() {
super();
setBackground(Color.gray);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(innerLayer.color);
g2d.setStroke(new BasicStroke(15));
g2d.drawRect(innerLayer.x, innerLayer.y, innerLayer.width, innerLayer.height);
System.out.println("I am get called");
}
}
And this is my keyAction:
package KeyActions;
import Main.myPanel;
public class keyActions {
myPanel panel = new myPanel();
public void keyUP() {
int x = panel.innerLayer.getX();
int y = panel.innerLayer.getY();
y--;
panel.innerLayer.addPosVal(x, y);
panel.repaint();
System.out.println("keyUp is called");
}
}
After the keyUP is called, the repaint() didn't call the paintComponent(), it should println "I am get called" but it did not.
Here's my code from the Piece object:
package Objects;
import java.awt.*;
import java.util.Arrays;
import javax.swing.*;
public class Piece {
public int x;
public int y;
public int width;
public int height;
public Color color;
public String type;
public Piece(int x, int y, int width, int height, Color color, String type) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.type = type;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void addPosVal(int x, int y) {
this.x += x;
this.y += y;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
}

Why is java copying instead of creating a new Instant When i use different variables?

I made a fairly simple code and i got into an error which confused me.
So I have a class that creates two totally different variables and creating them using the new keyword
Player playerLeft = new Player(5,150);
Player playerRight = new Player( 150,150);
Player class:
import javax.swing.*;
import java.awt.*;
public class Player extends JComponent {
private int posY;
private int posX;
public Player(int x, int y) {
posX = x;
posY = y;
//repaint();
}
public float getMovementY() {
return movementY;
}
public void setMovementY(int movementY) {
this.movementY = movementY;
}
int movementY = 0;
public void paintComponent(Graphics g) {
Graphics2D _g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(posX, posY, 20, 150);
_g2.fill(rect);
}
public void setLocation(int x, int y) {
posY = y;
posX = x;
repaint();
}
public void move() {
setLocation(posX, posY + movementY);
}
}
It's probably me not knowing something about Java but for me when I try to instantiate playerRight it just overwrites player left and drawsOut playerRight only.
Here is the complete code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;
public class mainJFrame extends JFrame implements KeyListener {
int relativeTimeMillsec = 0;
Player playerLeft = new Player(5, 150);
Player playerRight = new Player(150, 150);
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
relativeTimeMillsec++;
refreshTimeText(relativeTimeMillsec);
calcMovements();
}
};
//components
JLabel timeCounterLabel = new JLabel("Time: " + 0, SwingConstants.CENTER);
public mainJFrame() {
createComponents();
addKeyListener(this);
}
public void createComponents() {
this.setTitle("The title");
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
timer.scheduleAtFixedRate(task, 0, 10);
JButton testButton = new JButton("Label");
testButton.setSize(100, 25);
testButton.setLocation(this.getWidth() / 2 - testButton.getWidth() / 2, this.getHeight() / 2 - testButton.getHeight() / 2);
timeCounterLabel.setSize(200, 25);
timeCounterLabel.setLocation(this.getWidth() / 2 - timeCounterLabel.getWidth() / 2, 10);
//playerRight = new Player(this.getWidth()-45,this.getHeight()/2);
// this.add(testButton);
this.add(timeCounterLabel);
this.add(playerLeft);
this.add(playerRight);
}
public void paintComponent(Graphics g) {
{
super.repaint();
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_S) {
playerLeft.movementY = +2;
} else if (e.getKeyCode() == KeyEvent.VK_W) {
playerLeft.movementY = -2;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
playerRight.movementY = +2;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerRight.movementY = -2;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
private double calcRealRelativeTime(int _relTime) {
return relativeTimeMillsec / (double) 100;
}
private void refreshTimeText(int _relTime) {
timeCounterLabel.setText("Time: " + Math.round(calcRealRelativeTime(_relTime)));
}
private void calcMovements() {
playerLeft.move();
playerRight.move();
}
}
Understand that a JFrame's contentPane (the container that holds its components) uses BorderLayout by default, and this code:
this.add(timeCounterLabel);
this.add(playerLeft);
this.add(playerRight);
is adding all components to the same default BorderLayout.CENTER position, meaning any components added will replace components added previously.
But more importantly, yours is a common problem and stems from your having your Player class extend from a GUI component. Don't do this, as then you will have a great deal of difficulty drawing multiple Player objects and having them interact easily (as you're finding out). Instead have Player be a logical (non-component) class, and have only one class extend JPanel and do all the drawing. This class can hold Player objects, perhaps held in a collection such as an ArrayList<Player>, and then iterate through the collection within its paintComponent method.
Other issues:
Do not use java.util.Timer and java.util.TimerTask for Swing animations since these classes do not follow Swing threading rules. Use instead a javax.swing.Timer.
Learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others
If/when you do override a painting method such as paintComponent, be sure to call the super's method within your override, usually on the first line, so as not to break the painting chain. Also, use the #Override annotation before this method and any other methods that you think that you may be overriding so that the compiler catches possible errors with this.
For example (but not a complete example)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleAnimation extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 20;
private Player2 playerLeft = new Player2(5, 150, Color.RED);
private Player2 playerRight = new Player2(150, 150, Color.BLUE);
public SimpleAnimation() {
playerLeft.setySpeed(1);
playerRight.setySpeed(-1);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
playerLeft.draw(g);
playerRight.draw(g);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
playerRight.move();
playerLeft.move();
repaint();
}
}
private static void createAndShowGui() {
SimpleAnimation mainPanel = new SimpleAnimation();
JFrame frame = new JFrame("SimpleAnimation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Player2 {
private static final int RECT_WIDTH = 20;
private static final int RECT_HEIGHT = 50;
private int x;
private int y;
private int ySpeed;
private Color color;
public Player2(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setySpeed(int ySpeed) {
this.ySpeed = ySpeed;
}
public int getySpeed() {
return ySpeed;
}
public void setLocation(int x, int y) {
setX(x);
setY(y);
}
public void move() {
setLocation(x, y + ySpeed);
}
public void draw(Graphics g) {
g.setColor(color);
g.fillRect(x, y, RECT_WIDTH, RECT_HEIGHT);
}
}

Repaint() method calling in another class

I have a problem with repaint() method in my Java code. I want to call it in another class but I can't, something doesn't work at all. I've searched on forums, but nothing was able to help me out.
My Main class:
public class Main {
public static Main main;
public static JFrame f;
public Main(){
}
public static void main(String[] args) {
main = new Main();
f = new JFrame();
Ball b = new Ball();
f.getContentPane().setBackground(Color.GRAY);
f.add(b);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setTitle("Test");
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addMouseMotionListener(b);
f.addKeyListener(new Key());
}
}
Ball class where I created 2DGraphics for moving shapes:
public class Ball extends JLabel implements MouseMotionListener{
public Ball(){
}
public static double x = 10;
public static double y = 10;
public static double width = 40;
public static double height = 40;
String nick;
boolean isEllipse = true;
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if(isEllipse){
Ellipse2D e2d = new Ellipse2D.Double(x, y, width, height);
g2d.setColor(Color.RED);
g2d.fill(e2d);
}
else{
Rectangle2D r2d = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(Color.GREEN);
g2d.fill(r2d);
}
}
#Override
public void mouseDragged(MouseEvent e) {
isEllipse = false;
x = e.getX() - 30;
y = e.getY() - 40;
this.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX() - 30;
y = e.getY() - 40;
isEllipse = true;
this.repaint();
}
}
And Key class where I put KeyListener for move the shapes by key pressing:
public class Key extends Ball implements KeyListener {
public Key() {
}
#SuppressWarnings("static-access")
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
super.x += 10;
super.repaint();
System.out.println("x: " + super.x);
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
But something is wrong with this code: super method doesn't work for Key class. Everything in Ball class is working well. Where is the problem?
Super works fine, but your interpretation of what it does is wrong. Your problem is that you're trying to use inheritance to solve a problem that isn't solved with inheritance. You need to call repaint() on the actual visualized and used Ball instance, not on an instance of some completely different class, Key, that inappropriately extends from Ball. First off, make Key not extend Ball, pass in a true Ball reference into Key and the solution will fall from that.
Perhaps do something like this:
f.addKeyListener(new Key(b));
and
public class Key implements KeyListener {
private Ball ball;
public Key(Ball ball) {
this.ball = ball;
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
b.incrX(10); // give Ball a public method for this
b.repaint();
// System.out.println("x: " + super.x);
}
}
// .... etc...
Note, myself, I'd use Key Bindings for this, not a KeyListener, since then I wouldn't have to futz with keyboard focus.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
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 MoveBall {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static void createAndShowGui() {
BallPanel ballPanel = new BallPanel(PREF_W, PREF_H);
MyMouse myMouse = new MyMouse(ballPanel);
ballPanel.addMouseListener(myMouse);
ballPanel.addMouseMotionListener(myMouse);
new CreateKeyBindings(ballPanel);
JFrame frame = new JFrame("MoveBall");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(ballPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
#SuppressWarnings("serial")
class BallPanel extends JPanel {
private static final Color ELLIPSE_COLOR = Color.RED;
private static final Color SQUARE_COLOR = Color.GREEN;
private static final int BALL_WIDTH = 40;
private int prefW;
private int prefH;
private boolean isEllipse = true;
private int ballX;
private int ballY;
public BallPanel(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
}
public boolean isEllipse() {
return isEllipse;
}
public void setEllipse(boolean isEllipse) {
this.isEllipse = isEllipse;
}
public int getBallX() {
return ballX;
}
public void setBallX(int ballX) {
this.ballX = ballX;
}
public void setXY(int x, int y) {
ballX = x;
ballY = y;
repaint();
}
public void setXYCenter(int x, int y) {
ballX = x - BALL_WIDTH / 2;
ballY = y - BALL_WIDTH / 2;
repaint();
}
public void setXYCenter(Point p) {
setXYCenter(p.x, p.y);
}
public int getBallY() {
return ballY;
}
public void setBallY(int ballY) {
this.ballY = ballY;
}
public void incrementBallX(int x) {
ballX += x;
repaint();
}
public void incrementBallY(int y) {
ballY += y;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (isEllipse) {
g2.setColor(ELLIPSE_COLOR);
g2.fillOval(ballX, ballY, BALL_WIDTH, BALL_WIDTH);
} else {
g2.setColor(SQUARE_COLOR);
g2.fillOval(ballX, ballY, BALL_WIDTH, BALL_WIDTH);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
class MyMouse extends MouseAdapter {
private BallPanel ballPanel;
public MyMouse(BallPanel ballPanel) {
this.ballPanel = ballPanel;
}
#Override
public void mousePressed(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
}
enum Direction {
UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT);
private int key;
private Direction(int key) {
this.key = key;
}
public int getKey() {
return key;
}
}
// Actions for the key binding
#SuppressWarnings("serial")
class MyKeyAction extends AbstractAction {
private static final int STEP_DISTANCE = 5;
private BallPanel ballPanel;
private Direction direction;
public MyKeyAction(BallPanel ballPanel, Direction direction) {
this.ballPanel = ballPanel;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (direction) {
case UP:
ballPanel.incrementBallY(-STEP_DISTANCE);
break;
case DOWN:
ballPanel.incrementBallY(STEP_DISTANCE);
break;
case LEFT:
ballPanel.incrementBallX(-STEP_DISTANCE);
break;
case RIGHT:
ballPanel.incrementBallX(STEP_DISTANCE);
break;
default:
break;
}
}
}
class CreateKeyBindings {
private BallPanel ballPanel;
public CreateKeyBindings(BallPanel ballPanel) {
this.ballPanel = ballPanel;
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = ballPanel.getInputMap(condition);
ActionMap actionMap = ballPanel.getActionMap();
for (Direction direction : Direction.values()) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(direction.getKey(), 0);
String keyString = keyStroke.toString();
inputMap.put(keyStroke, keyString);
actionMap.put(keyString, new MyKeyAction(ballPanel, direction));
}
}
}

I added a rectangle to a shape Arraylist but the shape will not show up on the panel

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
#SuppressWarnings("serial")
public class GUI extends JFrame implements ActionListener, MouseListener {
private boolean drawLine = false;
private boolean drawRec = false;
private boolean drawOval = false;
private final JButton line;
private final JButton oval;
private final JButton rectangle;
private final JPanel buttonPanel;
public DrawStuff drawPanel = new DrawStuff();
public int x1;
public int x2;
public int y1;
public int y2;
public int click;
public GUI() {
super("Graphics IO");
this.click = 1;
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 3));
line = new JButton("Line");
line.addActionListener(this);
buttonPanel.add(line);
oval = new JButton("Oval");
oval.addActionListener(this);
buttonPanel.add(oval);
rectangle = new JButton("Rectangle");
rectangle.addActionListener(this);
buttonPanel.add(rectangle);
Container contentPane = this.getContentPane();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
//add(drawPanel);
addMouseListener((MouseListener) this);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == line) {
drawLine = true;
repaint();
} else if (source == oval) {
drawOval = true;
repaint();
} else if (source == rectangle) {
drawRec = true;
repaint();
}
}
public static void main(String[] args) {
GUI guiIO = new GUI();
}
class DrawStuff extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLUE);
ArrayList<Shape> shapes = new ArrayList<>();
if (drawLine) {
drawLine = false;
} else if (drawOval) {
//no clue how to add an oval
drawOval = false;
} else if (drawRec) {
Rectangle rec = new Rectangle(x1, y1,Math.abs(x2-x1) , Math.abs(y2-y1));
shapes.add(rec);
drawRec = false;
}
Graphics2D j = (Graphics2D)g;
shapes.stream().map((s) -> {
((Graphics2D) j).draw((Shape) s);
return s;
}).forEach((_item) -> {
repaint();
});
}
}
#Override
public void mousePressed(MouseEvent me) {
if (click == 1){
x1 = me.getX();
y1 = me.getY();
System.out.println(x1);
System.out.println(y1);
click = 2;
}else if (click == 2) {
x2 = me.getX();
y2 = me.getY();
System.out.println(x2);
System.out.println(y2);
click = 1;
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
}
Okay so i have to make a program to create shapes using two mouseclicks and then be able to export/import them. I am trying to use arraylist for this but im having a hard time trying to get it to work. The rectangle im creating will not show up on the panel. What am i doing wrong? Please help me.
Lets start with the fact that DrawStuff hasn't actually been added to anything that is capable of painting it.
DrawStuff#paintComponent should be making decisions about updating the state of the shapes List, instead, your ActionListener and MouseListener should be making these decisions (what to add, where and what do modify), the DrawStuff panel should just be painting what's in the Shape list
You also shouldn't be modifying the state of the component from within the paintComponent calling things like setBackground could set up a repeated repaint request which could cripple your application if not your PC
Modify DrawStuff so it has it's own MouseListener and methods that allow your GUI to ask it to create new shapes. Make the shapes List a instance field so you can manage from within DrawStuff more easily
Something like...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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 javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class GUI extends JFrame implements ActionListener {
private boolean drawLine = false;
private boolean drawRec = false;
private boolean drawOval = false;
private final JButton line;
private final JButton oval;
private final JButton rectangle;
private final JPanel buttonPanel;
public DrawStuff drawPanel = new DrawStuff();
public int x1;
public int x2;
public int y1;
public int y2;
public int click;
public GUI() {
super("Graphics IO");
this.click = 1;
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 3));
line = new JButton("Line");
line.addActionListener(this);
buttonPanel.add(line);
oval = new JButton("Oval");
oval.addActionListener(this);
buttonPanel.add(oval);
rectangle = new JButton("Rectangle");
rectangle.addActionListener(this);
buttonPanel.add(rectangle);
Container contentPane = this.getContentPane();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
add(drawPanel);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == line) {
drawPanel.setDrawShape(DrawStuff.DrawShape.LINE);
} else if (source == oval) {
drawPanel.setDrawShape(DrawStuff.DrawShape.OVAL);
} else if (source == rectangle) {
drawPanel.setDrawShape(DrawStuff.DrawShape.RECTANGLE);
}
}
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) {
ex.printStackTrace();
}
GUI guiIO = new GUI();
}
});
}
public static class DrawStuff extends JPanel {
public enum DrawShape {
LINE, OVAL, RECTANGLE;
}
private ArrayList<Shape> shapes = new ArrayList<>();
private DrawShape drawShape = DrawShape.LINE;
private Shape currentShape;
public DrawStuff() {
setBackground(Color.BLUE);
MouseAdapter ma = new MouseAdapter() {
private Point clickPoint;
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
currentShape = null;
}
#Override
public void mouseReleased(MouseEvent e) {
if (currentShape != null) {
shapes.add(currentShape);
currentShape = null;
repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
Point p = e.getPoint();
switch (getDrawShape()) {
case LINE:
currentShape = new Line2D.Double(clickPoint, e.getPoint());
break;
case OVAL:
case RECTANGLE:
int x = clickPoint.x;
int y = clickPoint.y;
int width = p.x - clickPoint.x;
int height = p.y - clickPoint.y;
if (width < 0) {
x = p.x;
width *= -1;
}
if (height < 0) {
y = p.y;
height *= -1;
}
switch (getDrawShape()) {
case OVAL:
currentShape = new Ellipse2D.Double(x, y, width, height);
break;
case RECTANGLE:
currentShape = new Rectangle2D.Double(x, y, width, height);
break;
}
break;
}
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
public DrawShape getDrawShape() {
return drawShape;
}
public void setDrawShape(DrawShape drawShape) {
this.drawShape = drawShape;
currentShape = null;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLACK);
for (Shape shape : shapes) {
g2d.draw(shape);
}
if (currentShape != null) {
g2d.setColor(Color.RED);
g2d.draw(currentShape);
}
}
}
}
For example. You always need to be asking yourself "who is responsible for doing what". In this case the DrawStuff panel is actually responsible for determine "where" something is drawn, but it needs more information about "what", then based on that information it can perform the actual operation

Game throws NullPointerException

So i am making a small game called dodge were rectangles fall from the "sky" and you have to do dodge them. As i ran the game this error message just popped up and i have no clue why. Also the screen just goes white whenever i run the program.
I cannot figure this out, Ive searched for hours in my code cant figure out why. Please Halp
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at dodge.Enemy.move(Enemy.java:22)
at dodge.Enemy.draw(Enemy.java:32)
at dodge.EnemyManager.draw(EnemyManager.java:34)
at dodge.Dodge.paint(Dodge.java:38)
at javax.swing.JComponent.paintChildren(JComponent.java:887)
at javax.swing.JComponent.paint(JComponent.java:1063)
at javax.swing.JComponent.paintChildren(JComponent.java:887)
at javax.swing.JComponent.paint(JComponent.java:1063)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
at javax.swing.JComponent.paintChildren(JComponent.java:887)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5226)
at
Sorry thats long. But here is my code.
Dodge.java
package dodge;
import java.awt.event.KeyListener;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.event.*;
public class Dodge extends JPanel implements KeyListener{
private Player player;
private Stage stage;
private EnemyManager manager;
public Dodge(){
setSize(new Dimension(800, 600));
setPreferredSize(new Dimension(800, 600));
addKeyListener(this);
setFocusable(true);
stage = new Stage();
player = new Player(this, 200, 200);
manager = new EnemyManager(this, 10);
}
#Override
public void update(Graphics g){
paint(g);
}
#Override
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
stage.draw(g);
player.draw(g);
manager.draw(g);
g.dispose();
repaint();
}
#Override
public void keyReleased(KeyEvent e){
player.setXD(0);
player.setYD(0);
}
#Override
public void keyTyped(KeyEvent e){
}
public Stage getStage(){
return stage;
}
#Override
public void keyPressed(KeyEvent e){
int c = e.getKeyCode();
if(c == KeyEvent.VK_W){
}
if(c ==KeyEvent.VK_A){
player.setXD(-1);
}
if(c == KeyEvent.VK_S){
}
if(c ==KeyEvent.VK_D){
player.setXD(1);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Dodge the Rectangles");
frame.add(new Dodge());
frame.pack();
frame.setResizable(false);
frame.setSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
EnemyManager.java
package dodge;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class EnemyManager {
private int amount;
private List<Enemy> enemies = new ArrayList<Enemy>();
private Dodge instance;
public EnemyManager(Dodge instance, int a){
this.amount = a;
spawn();
this.instance = instance;
}
private void spawn(){
Random random = new Random();
int ss = enemies.size();
if(ss<amount){
for(int i = 0; i < amount - ss; i++){
enemies.add(new Enemy(instance, random.nextInt(778), 10));
}
}else if(ss>amount){
for(int i = 0; i < ss - amount; i++){
enemies.remove(i);
}
}
}
public void draw(Graphics g){
for(Enemy e : enemies) e.draw(g);
}
}
Enemy.java
package dodge;
import java.awt.*;
public class Enemy extends Entity{
private Rectangle hitbox;
private int ix, iy;
private boolean dead = false;
private Dodge instance;
public Enemy(Dodge instance, int x, int y){
super(x, y);
this.instance = instance;
hitbox = new Rectangle (x, y, 32, 32);
ix = 0;
iy = 1;
}
private void move(){
if(instance.getStage().isCollided(hitbox)){
iy = 0;
dead = true;
}
hitbox.x += ix;
hitbox.y +=iy;
}
private boolean isDead() {return dead;}
#Override
public void draw(Graphics g){
move();
g.setColor(Color.CYAN);
g.fillRect(hitbox.x, hitbox.y, hitbox.width, hitbox.height);
}
}
Entity.java
package dodge;
import java.awt.*;
public abstract class Entity {
protected int x, y, w, h;
protected boolean removed = false;
public Entity(int x, int y){
this.x = x;
this.y = y;
}
public void draw(Graphics g){
}
public int getX() {return x;}
public int getY(){return y;}
public int getW() {return w;}
public int getH(){return h;}
}
Player.java
package dodge;
import java.awt.*;
public class Player extends Entity{
private int xd, yd;
private Dodge instance;
private Rectangle hitbox;
public Player(Dodge instance, int x , int y){
super(x, y);
this.instance = instance;
w = 16; h = 16;
hitbox = new Rectangle(x, y, w, h);
}
public void draw(Graphics g){
move();
if(!instance.getStage().isCollided(hitbox)){
yd = 1;
}else yd = 0;
g.setColor(Color.ORANGE);
g.fillOval(hitbox.x, hitbox.y, hitbox.width, hitbox.height);
}
private void move(){
hitbox.x += xd;
hitbox.y +=yd;
}
public void setXD(int value){
xd = value;
}
public void setYD(int value){
yd = value;
}
}
Stage.java
package dodge;
import java.awt.*;
public class Stage {
private Rectangle platform = new Rectangle(0, 540, 800, 100);
public Stage(){
}
public boolean isCollided(Rectangle entity){
return platform.intersects(entity);
}
public void draw(Graphics g){
g.setColor(Color.WHITE);
g.fillRect(platform.x, platform.y, platform.width, platform.height);
}
}
I hope that wasnt too long. Thanks
Read the stacktrace. Either Enemy.instance or Enemy.instance.getStage() is null.
Also the screen just goes white whenever i run the program.
Don't override update() and paint(). That is old code used in AWT and is NOT the way custom painting is done in Swing. In Swing you simply override the paintComponent() method of the JPanel and don't forget to invoke super.paintComponent(). Read the section from the Swing tutorial on Custom Painting for more information and examples.
Don't invoke repaint() in a painting method. That will cause an infinite loop. The is not the way to do animation. Use a Swing Timer or a separate Thread to schedule the animation.

Categories