Can paintComponent() be used in an AbstractAction class? - java

I am trying to make a program that creates a JPanel, and when the user presses W, A, S, and D, a cube that is drawn will navigate around in the window (by a certain amount every time a key is pressed), I have created the MoveCubeUp class, and I override the paintComponent method in it to repaint the cube when it is called, but it will not work. Could someone explain why?
public MyPanel(){
…
MoveSquareUp m=new MoveSquareUp(squareX, squareY);
getInputMap().put(KeyStroke.getKeyStroke(("W"), "pressed"));
getActionMap().put("pressed", m)
}
class MoveSquareUp extends AbstractAction{
public int squareXX, squareYY;
public moveSquare(){
squareXX=squareX+5;
}
//I define the paintComponent method to draw the rectangle with its set height
//at squareXX, squareYY
//action method is null (I am still trying to figure out binding keys to
//actions but the paintComponent not working is preventing that
}
I apologize if that was poorly formatted. 1st post :/
Does the paint method need to be defined within the class that extends JFrame, and if so, how can I use it with an abstractAction class (or how can I avoid the AbstractAction class altogether)?

The crux of your problem is that you need to learn to separate your model from your view from your control. Here the model is the location of your sprite, the view is the GUI that draws this position, and the control will hold the actions including your AbstractAction, and they all should be separate from each other if possible.
So to answer your direct question -- no paintComponent should definitely not be inside of an AbstractAction, since the former is a key part of the view while the latter is a key part of the control. Instead have your view reflect the state of the model, and the model's state will be changed by the control (the actions).
Regarding your other question, should all painting methods be part of the JFrame: none of the painting methods should be in a class extending JFrame since this class is a complex class that creates a top level window and several sub components to display your GUI, and if you override its painting, you can effect painting of sub components in bad ways. Instead draw in the paintComponent method of a class that extends JPanel, and then display this object in your JFrame.
For example:
package pkg3;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
public class GamePanel extends JPanel {
private static final int ANIMATION_DELAY = 15;
private final int HEIGHT = 400;
private final int WIDTH = 600;
private Square square;
private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
private Map<Integer, Direction> keyToDir = new HashMap<>();
// !! private Circle circle;
private Timer animationTimer;
public GamePanel() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
keyToDir.put(KeyEvent.VK_UP, Direction.UP);
keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
setKeyBindings();
setBackground(Color.white);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
square = new Square();
animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener());
animationTimer.start();
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
final InputMap inputMap = getInputMap(condition);
final ActionMap actionMap = getActionMap();
boolean[] keyPressed = { true, false };
for (Integer keyCode : keyToDir.keySet()) {
Direction dir = keyToDir.get(keyCode);
for (boolean onKeyPress : keyPressed) {
boolean onKeyRelease = !onKeyPress; // to make it clear how
// bindings work
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0, onKeyRelease);
Object key = keyStroke.toString();
inputMap.put(keyStroke, key);
actionMap.put(key, new KeyBindingsAction(dir, onKeyPress));
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
square.display(g);
}
private class AnimationListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent evt) {
boolean repaint = false;
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
square.move(dir);
repaint = true;
}
}
if (repaint) {
repaint();
}
}
}
private class KeyBindingsAction extends AbstractAction {
private Direction dir;
boolean pressed;
public KeyBindingsAction(Direction dir, boolean pressed) {
this.dir = dir;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent evt) {
dirMap.put(dir, pressed);
}
}
private static void createAndShowGUI() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("GamePanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
enum Direction {
UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
private int incrX;
private int incrY;
private Direction(int incrX, int incrY) {
this.incrX = incrX;
this.incrY = incrY;
}
public int getIncrX() {
return incrX;
}
public int getIncrY() {
return incrY;
}
}
class Square {
private int x = 0;
private int y = 0;
private int w = 20;
private int h = w;
private int step = 1;
private Color color = Color.red;
private Color fillColor = new Color(255, 150, 150);
private Stroke stroke = new BasicStroke(3f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
public void display(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(fillColor);
g2d.fillRect(x, y, w, h);
g2d.setStroke(stroke);
g2d.setColor(color);
g2d.drawRect(x, y, w, h);
g2d.dispose();
}
public void setStep(int step) {
this.step = step;
}
public void move(Direction dir) {
x += step * dir.getIncrX();
y += step * dir.getIncrY();
}
}

Related

I'm trying to write a snake game, but the KeyListener does not work

I had tried to add the listener to the object of the Snake class , to the object of the Window class and object of JFrame class I created in the constructor of the Snake class, but it still does not work. Сharacters that must be written and the snake must turn, if i press any key, but it doesn't happen. Сan it be because of the snakeThread?
public class Main {
public static void main(String[] args) {
Window window = new Window();
System.out.print("k");
}
}
import javax.swing.*;
import java.awt.*;
public class Window extends JPanel {
private Snake snake;
public Window() {
super(true);
snake = Snake.getSnake(50, 50);
Thread snakeThread = new Thread(snake);
snakeThread.start();
}
#Override
public void paint(Graphics g) {
super.paint(g);
snake.paint(g);
}
}
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class Snake extends JPanel implements Runnable {
public static int length;
public static ArrayList<Point> parts;
public static Field field;
public static Food food;
public static int speedX=0;
public static int speedY=1;
private static Snake snake = null;
public static final int TIME_DELTA = 1000;
public static Snake getSnake(int w, int h)
{
if(snake == null) {
snake = new Snake(w, h);
snake.addKeyListener(new Turn(snake));
}
return snake;
}
private Snake(int Width, int Heigth) {
JFrame jf = new JFrame();
jf.setSize(500,500);
jf.add(this); //this - это Jpanel которым расширяется Snake
jf.setVisible(true);
food = new Food();field = Field.getField();
Point start = new Point((int)Width/2, (int)Heigth/2); //размеры поля, а не окна
parts = new ArrayList<>();parts.add(start);
Point p1 = new Point((int)start.getX(), ((int)start.getY())-1);parts.add(p1);
Point p2 = new Point((int)start.getX(), ((int)p1.getY())-1);
parts.add(p2);length = 3;
}
private boolean checkHead()
{
for (int i=1; i<parts.size(); ++i)
{
if(parts.get(parts.size()-1).getLocation() == parts.get(i).getLocation())
return false;
}
if(parts.get(parts.size()-1).getX() <=0 || parts.get(parts.size()-1).getX() >= field.sizeX ||
parts.get(parts.size()-1).getY() <=0 || parts.get(parts.size()-1).getY() >= field.sizeY )
return false;
return true;
}
public static void move()
{
for (Point i: parts)
{
i.y=i.y-1*speedY;
i.x-=1*speedX;
}
}
public static void eat()
{
Point np = new Point ((int)parts.get(length).getX(),(int)parts.get(length).getY()-1 );
parts.add(np);
++length;
food.respawn();
}
public static boolean checkFood()
{
if(parts.get(parts.size()-1).getX() == food.x && parts.get(parts.size()-1).getY()==food.y)
return true;
else
return false;
}
#Override
public void paint(Graphics g) {
super.paint(g);
for (Point i: parts)
g.fillRect((int) i.getX() * 10, (int) i.getY() * 10, 8, 8);
g.setColor(Color.RED);
g.fillRect(food.x * 10, food.y * 10, 8, 8);
g.setColor(Color.BLACK);
}
#Override
public void run() {
while (checkHead()) {
move();
repaint();
if(checkFood())
eat();
try {
Thread.sleep(TIME_DELTA);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void turn(char Key)
{
int delta = 0;
for(Point i: parts)
{
switch (Key) {
case 'a':
i.y=parts.get(parts.size()-1).y;
i.x=parts.get(parts.size()-1).x+delta;
break;
case'd':
i.y=parts.get(parts.size()-1).y;
i.x=parts.get(parts.size()-1).x-delta;
break;
case 'w':
i.x=parts.get(parts.size()-1).x;
i.y=parts.get(parts.size()-1).y-delta;
break;
case's':
i.x=parts.get(parts.size()-1).x;
i.y=parts.get(parts.size()-1).y+delta;
break;
}
++delta;
}
repaint();
}
}
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Food extends JPanel {
public static int x;
public static int y;
private static Random random;
public Food()
{
super(true);
random = new Random();
x = random.nextInt(50);
y = random.nextInt(50);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
g.fillRect(x * 10, y * 10, 8, 8);
g.setColor(Color.BLACK);
}
public void respawn()
{
x = random.nextInt(40);
y = random.nextInt(40);
repaint();
}
}
The listener is here:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Turn implements KeyListener {
private char key = 'O';
private Snake snake;
public Turn(Snake s)
{
this.snake = s;
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("0");//when I press a button, "0" must be written, but it doesn't
if(e.getKeyChar() == 'A')
{
System.out.println("a");//this character too
if(snake.speedX==0)
{
snake.speedX=-1;//speedX was not changed
snake.speedY=0;
key='a';
}
}
else if (e.getKeyChar() == 'W')
{
System.out.println("w");
if(snake.speedY==0)
{
snake.speedY=-1;
snake.speedX=0;
key='w';
}
}
else if (e.getKeyChar() == 'S')
{
System.out.println("s");
if(snake.speedY==0)
{
snake.speedY=1;
snake.speedX=0;
key='s';
}
}
else if (e.getKeyChar() == 'D')
{
System.out.println("d");
if(snake.speedX==0)
{
snake.speedX=1;
snake.speedY=0;
key='d';
}
}
if(key!='O')
snake.turn(key);
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Never invoke paint(...) directly on a component. If you need to paint a component you invoke repaint() on that component. Swing will then paint(...) that component and invoke paint(...) on all the child components added to the panel.
So this means you need to add the Snake component to the parent game panel. It also means there is no reason to override the paint() method of the Window panel.
Don't use static variables and methods. This is an indication of poor design. Remove the static keyword from the variables and methods.
For animation you should be using a Swing Timer, not a Thread. Updates to Swing components should be done on the Event Dispatch Thread (EDT). The Timer will execute code on the EDT.
Don't use a KeyListener. Swing was designed to be used with Key Bindings. See: Motion Using the Keyboard for more information and examples.
Custom painting is done by overriding paintComponent(...) not paint(...).
The point of the main() method is to create the frame and add the game panel to the frame. The game panel should NOT create the frame.
I agree with everything in the answer from camickr. There are many things wrong in your code, and starting from scratch with those things in mind will help avoid many of the issues you are facing.
However, your actual issue is this line private static Snake snake = null; and this method:
public static Snake getSnake(int w, int h)
{
if(snake == null) {
snake = new Snake(w, h);
snake.addKeyListener(new Turn(snake));
}
return snake;
}
You should NEVER need to create a self reference inside a class like that. The Snake class is already a Snake object, so using private static Snake snake = null; inside the class simply creates a new reference to a completely new and different Snake within your Snake. Instead, you need to use the this keyword to refer to the Snake object, for example, this.addKeyListener(new Turn(this)); instead of snake.addKeyListener(new Turn(snake));
Delete/remove the getSnake method, you are trying to mix static and non static objects and it is not needed, we can move the keylistener part of the method to our constructor (see below). Note that if you want to update the width and height of your snake then you should make a different method that updates the parts and p1 and p2 separately.
Fixing the Snake class:
The fixed Snake class might look something like this:
public class Snake extends JPanel implements Runnable {
//None of the variables or methods should be static
//remove the static keyword from everywhere in the Snake class
public int length;
public ArrayList<Point> parts;
public Field field;
public Food food;
public int speedX=0;
public int speedY=1;
public final int TIME_DELTA = 1000;
//The constructor needs to be a public method (Not private)
public Snake(int Width, int Heigth) {
//Delete all the JFrame code,
//it should be done in the main method
//Add the key ilstener here (moved from the getSnake method)
this.addKeyListener(new Turn(this));
//Create the snake
food = new Food();
field = Field.getField();
Point start = new Point((int)Width/2, (int)Heigth/2); //размеры поля, а не окна
parts = new ArrayList<>();
parts.add(start);
Point p1 = new Point((int)start.getX(), ((int)start.getY())-1);parts.add(p1);
Point p2 = new Point((int)start.getX(), ((int)p1.getY())-1);
parts.add(p2);
length = 3;
}
//Rest of the code removed for clarity
...
}
Fix the main method and delete the Window class:
To use this updated Snake class you can completely delete the Window class and use something like this in your main class:
public class Main {
public static void main(String[] args) {
//Create JFrame
JFrame jf = new JFrame();
jf.setSize(500,500);
//Create Snake
Snake snake = new Snake(50, 50);
//Add Snake to JFrame and set the frame visible
jf.add(snake);
jf.setVisible(true);
//Finally start the Snake thread
Thread snakeThread = new Thread(snake);
snakeThread.start();
}
}
There are still a bunch of things that need fixing, but this should solve your key listener not working.
Other fixes:
Instead of key listeners a better solution is to use key bindings. We can create a key binding like this in you main method:
//Key binding to trigger when KeyEvent.VK_W ('w') is pressed
snake.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "NORTH");
snake.getActionMap().put("NORTH", new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
//Your code here to change the snake direction
//we can call the turn method from inside this snake object/class
snake.turn('w');
}
});
You should override protected void paintComponent(Graphics g) instead of public void paint(Graphics g), inside your Snake class like this:
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Point i: parts)
g2d.fillRect((int) i.getX() * 10, (int) i.getY() * 10, 8, 8);
g2d.setColor(Color.RED);
g2d.fillRect(food.x * 10, food.y * 10, 8, 8);
g2d.setColor(Color.BLACK);
}
Lastly, instead of making your Snake class implement Runniable you should create a simple stand alone swing timer something like this inside your Snake class:
void startTimer(){
//Start timer to update snake location every 100ms
Timer timer = new Timer(100, new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae){
//Your code here to update and repaint the snake location
snake.updateLocation();
}
});
timer.start();
}
And in your main method you can simple use snake.startTimer(); instead of Thread snakeThread = new Thread(snake); and snakeThread.start();

Communication between a listener and a timer

im fairly new to java and am confused on how to do this. I have a key listener that listens for WASD which indicate movement of my Snake. The key listener changes the x and y positions of my Snakes segments. I have a timer linked to a listener called "Listener" that repaints the movements onto a buffer and onto the screen. My question is, why does the movement indicated by my key listener not make it to the buffer? Also, I know my move function works becuase snek.move(4); works in the timer. Final note, this is a Snake game i've barely begun.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class SnekePanel extends JPanel
{
private static final int FRAME1 = 1000;
private static final int FRAME2 = 1000;
private static final Color BACKGROUND = new Color(0, 0, 0);
private BufferedImage myImage;
private Graphics myBuffer;
private Sneke snek;
private Food food;
private Timer t;
private int points = 0;
public SnekePanel()
{
myImage = new BufferedImage(FRAME1, FRAME2, BufferedImage.TYPE_INT_RGB);
myBuffer = myImage.getGraphics();
myBuffer.setColor(BACKGROUND);
myBuffer.fillRect(0, 0, FRAME1,FRAME2);
int xPos = (int)(Math.random()*(FRAME1-100) + 50);
int yPos = (int)(Math.random()*(FRAME2-100)+ 50);
food = new Food(xPos, yPos, 10, Color.RED);
snek = new Sneke(200,200,1,Color.WHITE);
t = new Timer(5, new Listener());
t.start();
addKeyListener(new Key());
setFocusable(true);
}
public void paintComponent(Graphics g)
{
g.drawImage(myImage, 0, 0, getWidth(), getHeight(), null);
}
private class Key extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_W)
{
snek.move(1);
}
if(e.getKeyCode() == KeyEvent.VK_A)
{
snek.move(2);
}
if(e.getKeyCode() == KeyEvent.VK_S)
{
snek.move(3);
}
if(e.getKeyCode() == KeyEvent.VK_D)
{
snek.move(4);
}
}
}
private class Listener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(snek.checkBlock() != 0)
{
myBuffer.setColor(BACKGROUND);
myBuffer.fillRect(0,0,FRAME1,FRAME2);
snek.move(4);
collide(snek, food);
food.draw(myBuffer);
snek.draw(myBuffer);
myBuffer.setColor(Color.BLACK);
repaint();
}
}
}
private void collide(Sneke b, Food pd)
{
int sx = b.getX(snek.getLength()-1);
int sy = b.getY(snek.getLength()-1);
int fx = pd.getX();
int fy = pd.getY();
if(sx == sy && fx == fy)
{
snek.setLength(snek.getLength()+1);
}
}
}
why does the movement indicated by my key listener not make it to the buffer?
A more important question in my mind is: why do you think that it should make it to the buffer? You're only painting the buffer after calling snek.move(4) and so it appears that only that would make it into the buffer.
Myself, I'd do things differently, including (among other things)
I would create an int field -- or better a Direction enum that encapsulates up, down, left and right.
I'd give my GUI a field of this above, and I'd set it in the KeyListener.
I'd actually prefer using Key Bindings and not a KeyListener since it is much less dodgy when it comes to focus issues, but either could work.
In my Timer, I'd move the sprite based on the state of the value in the field
For example, try running this:
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class SnakePanel extends JPanel {
// size of the GUI
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
// background and snake color
private static final Color BG = Color.BLACK;
private static final Color SNAKE_COLOR = Color.RED;
private static final int SEGMENT_WIDTH = 20;
// distance moved in each timer tick, and time between each tick
private static final int DELTA = 5;
private static final int TIMER_DELAY = 40; // in msecs
// number of segments in the worm
private static final int WORM_LENGTH = 80;
// initial direction
private Direction direction = Direction.RIGHT;
// initial point
private Point point = new Point(PREF_W / 2, PREF_H / 2);
// Snake is little more than a List of Points
private List<Point> snakePointList = new LinkedList<>();
public SnakePanel() {
// set background color
setBackground(BG);
// fill snake list with points
for (int i = 0; i < WORM_LENGTH; i++) {
snakePointList.add(new Point(point));
}
// set key bindings
setKeyBindings();
// create and start Timer
new Timer(TIMER_DELAY, new TimerListener()).start();
}
// set up our key bindings
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
setKeyStroke(inputMap, actionMap, keyStroke, Direction.UP);
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
setKeyStroke(inputMap, actionMap, keyStroke, Direction.DOWN);
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
setKeyStroke(inputMap, actionMap, keyStroke, Direction.LEFT);
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
setKeyStroke(inputMap, actionMap, keyStroke, Direction.RIGHT);
}
private void setKeyStroke(InputMap inputMap, ActionMap actionMap, KeyStroke keyStroke,
Direction dir) {
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), new MyKeyAction(dir));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// smooth out our graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// draw each oval in the Snake
for (Point pt : snakePointList) {
drawPoint(g2, pt);
}
}
private void drawPoint(Graphics2D g2, Point pt) {
g2.setColor(SNAKE_COLOR);
// The pt is actually the center point
// so we need to draw an oval that is centered on this point
int x = pt.x - SEGMENT_WIDTH / 2;
int y = pt.y - SEGMENT_WIDTH / 2;
g2.drawOval(x, y, SEGMENT_WIDTH, SEGMENT_WIDTH);
}
// set gui's size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
// Action used by key binding
private class MyKeyAction extends AbstractAction {
private Direction dir;
public MyKeyAction(Direction dir) {
this.dir = dir;
}
public void actionPerformed(ActionEvent e) {
// all it does is set the Direction direction enum field
// for this GUI
// the Timer then uses this field
SnakePanel.this.direction = dir;
};
}
// timer ActionListener
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// create a new Point whose direction depends
// on the direction field * multiplier, DELTA
int x = point.x + direction.getX() * DELTA;
int y = point.y + direction.getY() * DELTA;
// create new point and add to snakePointList
point = new Point(x, y);
snakePointList.add(point);
// remove last point in list
snakePointList.remove(0);
repaint();
}
}
// Direction enum
enum Direction {
UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
private Direction(int x, int y) {
this.x = x;
this.y = y;
}
private int x;
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
}
private static void createAndShowGui() {
SnakePanel mainPanel = new SnakePanel();
JFrame frame = new JFrame("SnakePanel");
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());
}
}

JPanel size is not known on start

When I create a Board instance from my Square instance, I try to assign the size of the window to the integers x and y. I fail to do this because it seems like on start the size is 0. In the constructor in Board.java, x and y shouldn't be -50 like they end up now.
Square.java:
package Square;
import javax.swing.*;
public class Square extends JFrame {
public Square(){
add(new Board());
setSize(800, 800);
setVisible(true);
}
public static void main(String[] args){
new Square();
}
}
Board.java
package Square;
import javax.swing.*;
import java.awt.*;
public class Board extends JPanel{
int x,y;
public Board(){
x = width-50;
y = height-50;
}
public int width = (int) getSize().getWidth();
public int height = (int) getSize().getHeight();
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(x,y, 100, 100);
}
}
Full Code for clarification:
Square.java
package Square;
import javax.swing.*;
public class Square extends JFrame {
public Square(){
Board board = new Board();
board.start();
add(board);
setTitle("Square");
setSize(800, 800);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args){
Square square = new Square();
square.setVisible(true);
square.setLocation(2000, 150);
}
}
Board.java
package Square;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Board extends JPanel implements ActionListener{
Timer timer;
int x, y;
int velX = 0;
int velY = 0;
public Board(){
setFocusable(true);
timer = new Timer(1, this);
addKeyListener(new TAdapter());
}
class TAdapter extends KeyAdapter{
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch(keyCode){
case KeyEvent.VK_ESCAPE: x = width()/2-50; y = height()/2-50; break;
case KeyEvent.VK_RIGHT: velX = 1; break;
case KeyEvent.VK_DOWN: velY = 1; break;
case KeyEvent.VK_LEFT: velX = -1; break;
case KeyEvent.VK_UP: velY = -1; break;
}
}
public void keyReleased(KeyEvent e){
velX = 0;
velY = 0;
}
}
public int width(){ return (int) getSize().getWidth();}
public int height(){ return (int) getSize().getHeight();}
public void start(){
timer.setInitialDelay(100);
timer.start();
x = width()/2-50;
y = height()/2-50;
}
#Override
public void actionPerformed(ActionEvent e) {
x += velX;
y += velY;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x,y, 100, 100);
}
}
Put the calculation into your paintComponent method. In general you want to avoid having code in paintComponent that will slow it down, but these calls shouldn't give too much penalty. Also, if your program is re-sizable, you'll need to be able to re-calculate the sizes of things on the go like this:
public void paintComponent(Graphics g){
super.paintComponent(g);
int x = getWidth() - 50;
int y = getHeight() - 50;
g.fillRect(x, y, 100, 100);
}
but of course in your real program, you will want to avoid "magic" numbers
Another issue: don't call setSize() on your JFrame. Instead, if you want to specify a hard size, do so in the JPanel by overriding its getPreferredSize() method. This will also then give you the suggested parameters that can be used for your calculations.
For 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 DrawRect extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private static final int DELTA = 50;
private static final Color RECT_COLOR = Color.red;
private static final int RECT_WIDTH = 100;
private static final int TIMER_DELAY = 15;
private int rectX = PREF_W - DELTA;
private int rectY = PREF_H - DELTA;
public DrawRect() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, RECT_WIDTH, RECT_WIDTH);
}
#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) {
rectX--;
rectY--;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawRect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawRect());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also, check out the key bindings animation code from this answer of mine.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
public class GamePanel extends JPanel {
private static final int ANIMATION_DELAY = 15;
private final int HEIGHT = 400;
private final int WIDTH = 600;
private Square square;
private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
private Map<Integer, Direction> keyToDir = new HashMap<>();
// !! private Circle circle;
private Timer animationTimer;
public GamePanel() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
keyToDir.put(KeyEvent.VK_UP, Direction.UP);
keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
// !! addKeyListener(new DirectionListener());
setKeyBindings();
setBackground(Color.white);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
square = new Square();
animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener());
animationTimer.start();
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
final InputMap inputMap = getInputMap(condition);
final ActionMap actionMap = getActionMap();
boolean[] keyPressed = { true, false };
for (Integer keyCode : keyToDir.keySet()) {
Direction dir = keyToDir.get(keyCode);
for (boolean onKeyPress : keyPressed) {
boolean onKeyRelease = !onKeyPress; // to make it clear how bindings work
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0,
onKeyRelease);
Object key = keyStroke.toString();
inputMap.put(keyStroke, key);
actionMap.put(key, new KeyBindingsAction(dir, onKeyPress));
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
square.display(g);
}
private class AnimationListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent evt) {
boolean repaint = false;
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
square.move(dir);
repaint = true;
}
}
if (repaint) {
repaint();
}
}
}
private class KeyBindingsAction extends AbstractAction {
private Direction dir;
boolean pressed;
public KeyBindingsAction(Direction dir, boolean pressed) {
this.dir = dir;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent evt) {
dirMap.put(dir, pressed);
}
}
private static void createAndShowGUI() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("GamePanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
enum Direction {
UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
private int incrX;
private int incrY;
private Direction(int incrX, int incrY) {
this.incrX = incrX;
this.incrY = incrY;
}
public int getIncrX() {
return incrX;
}
public int getIncrY() {
return incrY;
}
}
class Square {
private int x = 0;
private int y = 0;
private int w = 20;
private int h = w;
private int step = 1;
private Color color = Color.red;
private Color fillColor = new Color(255, 150, 150);
private Stroke stroke = new BasicStroke(3f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
public void display(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(fillColor);
g2d.fillRect(x, y, w, h);
g2d.setStroke(stroke);
g2d.setColor(color);
g2d.drawRect(x, y, w, h);
g2d.dispose();
}
public void setStep(int step) {
this.step = step;
}
public void move(Direction dir) {
x += step * dir.getIncrX();
y += step * dir.getIncrY();
}
}
Hey your codestyle is horrible, but i try to help :). You can't get a size of an undrawn window. First Things first, your Constructor is wrong, you add the Board that actually create the Board Obj. Calling the Constructor of Board, which has no drawn parent yet and no x,y set. Try to initialize your variables in the Constructor. So just use width and height and fill the values in the constructor. Next, just tell your board its creation size by passing its parent size trough constructor variables.
I think you try to learn java and this is much more elegant. Furthermore, try to do all parent modification before adding some to it. So first setSize, add some Layout (Border/Flow/whatuwish) then get the frames ContentPane and add your Board component. To make things clear, you can't get e.g. the parent and parent size in Contructor because your board Obj isn't created and added yet. If you wish to getParent() and its size, create the Object add it to JFrame and than you can call getParent().getSize(). You get 0 because your JPanel isn't drawn at this time (before creation). If you wish to get the Parent Size just pass the JFrame Ref to Constructor or its size. Another Advise, don't create things in things in things, keep in mind with your code you create your JPanel as first Obj... Here is some example code:
Square:
public class Square extends JFrame {
public static void main(String[] args){
Square square = new Square();
square.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension d = new Dimension(800,800);
square.setPreferredSize(d);
square.setSize(d);
//too much, every Jframe has BorderLayout enabled
square.getContentPane().setLayout(new BorderLayout());
square.getContentPane().add(new Board(square), BorderLayout.CENTER);
square.pack();
square.setVisible(true);
}
}
Board:
public class Board extends JPanel{
int x,y;
JFrame parent;
public Board(JFrame parent){
int width = parent.getPreferredSize().width;
int height = parent.getPreferredSize().height;
x = width-50;
y = height-50;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(x,y, 100, 100);
}
}
You can take x and y values after the panel has become visible, in the next EDT cycle, by using SwingUtilities.invokeLater, for example.

Java swing: Extended jpanel class will not brighten upon repainting.

I have done much more complicated problems with no issues for my course, but this is giving me fits! My problem is simple, I cannot brighten or change the color of my jpanels. I feel I a missing something crucial in how my extended jpanel class interacts with my overridden paint component as well as my other classes. The mission is simple, when one jpanel is clicked it's color should brighten, while the other two colors dim.
Run down: I extended Jframe and added 3 panels to it. I have added a mouse listener to each. When each is pressed the mouse listener does work "print statements confirmed". However it does not change the objects color. I thought that by including my mouse adapter in my TrafficLight class I would be able to change the color and call repaint. I have played with in all the ways I can think, is my organization wrong?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class TrafficLight3 extends JFrame {
//class variables
public JPanel red;
public JPanel yellow;
public JPanel green;
public Color r;
public Color y;
public Color gr;
public static void main ( String [] args ) {
TrafficLight3 tl = new TrafficLight3 ( );
}
// Constructor
public TrafficLight3( ) {
setTitle( "Traffic Light" );
setLayout ( new GridLayout ( 3, 1 ) );
setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
r = Color.RED;
red = new StopLightPanel( 100, r );
red.setPreferredSize( new Dimension ( 120, 120 ) );
red.addMouseListener ( new MouseClicked( ) );
add( red );
y = Color.YELLOW;
yellow = new StopLightPanel( 100, y );
yellow.setPreferredSize( new Dimension ( 120, 120 ) );
yellow.addMouseListener ( new MouseClicked( ) );
add( yellow );
gr = Color.GREEN;
green = new StopLightPanel( 100, gr );
green.addMouseListener ( new MouseClicked( ) );
green.setPreferredSize( new Dimension ( 120, 120 ) );
add ( green );
pack();
setLocationRelativeTo(null);
setVisible( true );
}
class MouseClicked extends MouseAdapter {
#Override
public void mouseClicked ( MouseEvent me ) {
if (me.getSource().equals( red ) ) {
r = r.brighter();
y = y.darker();
gr = gr.darker();
repaint();
}
if (me.getSource().equals( yellow )) {
r = r.darker();
y = y.brighter();
gr = gr.darker();
repaint();
}
if (me.getSource().equals( red )) {
r = r.darker();
y = y.darker();
gr = gr.brighter();
repaint();
}
}
}
class StopLightPanel extends JPanel {
private int diameter;
public Color color;
public StopLightPanel ( int d, Color c) {
diameter = d;
color = c;
}
public void paintComponent ( Graphics g ) {
super.paintComponent( g );
g.setColor ( color );
g.fillOval ( 10, 10, diameter, diameter );
}
}
}
You're changing a variable's value in one location, and expecting a completely different variable, the one owned by the JPanel, to change in concert, but that's not how variables work.
Instead, I would give my stop light panel a method, say public void setLightOn(boolean lightOn) and would call this method in my MouseListener. The method would change the color of the JPanel and repaint it.
For example:
class StopLightPanel extends JPanel {
private int diameter;
private Color onColor;
private Color offColor;
private boolean lightOn;
public boolean isLightOn() {
return lightOn;
}
public void setLightOn(boolean lightOn) {
this.lightOn = lightOn;
repaint();
}
public StopLightPanel(int d, Color c) {
diameter = d;
onColor = c.brighter();
offColor = c.darker().darker();
lightOn = false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Color color = lightOn ? onColor : offColor;
g.setColor(color);
g.fillOval(10, 10, diameter, diameter);
}
}
For example,
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
#SuppressWarnings("serial")
class TrafficLight3 extends JFrame {
private static final int DIAMETER = 100;
private static final Color[] COLORS = { Color.red, Color.yellow, Color.green };
private StopLightPanel[] lightPanels = new StopLightPanel[COLORS.length];
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TrafficLight3();
}
});
}
public TrafficLight3() {
setTitle("Traffic Light");
setLayout(new GridLayout(3, 1));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
MouseAdapter mouseClicked = new MouseClicked();
for (int i = 0; i < COLORS.length; i++) {
lightPanels[i] = new StopLightPanel(DIAMETER, COLORS[i]);
lightPanels[i].addMouseListener(mouseClicked);
add(lightPanels[i]);
}
pack();
setLocationRelativeTo(null);
setVisible(true);
}
class MouseClicked extends MouseAdapter {
// better overriding mousePressed not mouseClicked
#Override
public void mousePressed(MouseEvent me) {
// set all lights dark
for (StopLightPanel lightPanel : lightPanels) {
lightPanel.setLightOn(false);
}
// turn only selected light on.
((StopLightPanel) me.getSource()).setLightOn(true);
}
}
class StopLightPanel extends JPanel {
// avoid "magic" numbers
private static final int GAP = 10;
private int diameter;
private Color onColor;
private Color offColor;
private boolean lightOn;
public boolean isLightOn() {
return lightOn;
}
public void setLightOn(boolean lightOn) {
this.lightOn = lightOn;
repaint();
}
public StopLightPanel(int diameter, Color color) {
this.diameter = diameter;
this.onColor = color.brighter();
this.offColor = color.darker().darker();
this.lightOn = false;
}
#Override
public Dimension getPreferredSize() {
int prefW = diameter + 2 * GAP;
int prefH = prefW;
return new Dimension(prefW, prefH);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// smooth out the edge of our circle
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color color = lightOn ? onColor : offColor;
g2.setColor(color);
g2.fillOval(GAP, GAP, diameter, diameter);
}
}
}
Somewhat MCV-ified. Missing interfaces though
import java.awt.*;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumMap;
import java.util.Map;
#SuppressWarnings("serial")
class TrafficLight3 {
private static final int DIAMETER = 100;
private static void createAndShowGui() {
StopLightModel model = new StopLightModel();
StopLightView view = new StopLightView(DIAMETER);
new StopLightControl(view, model);
JFrame frame = new JFrame("Traffic Light");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(view.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum MyColor {
RED(Color.red, "Red"),
YELLOW(Color.yellow, "Yellow"),
GREEN(Color.green, "Green");
public Color getColor() {
return color;
}
public String getName() {
return name;
}
private MyColor(Color color, String name) {
this.color = color;
this.name = name;
}
private Color color;
private String name;
}
class StopLightModel {
public static final String SELECTED_COLOR = "selected color";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private MyColor selectedColor = null;
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public MyColor getSelectedColor() {
return selectedColor;
}
public void setSelectedColor(MyColor selectedColor) {
MyColor oldValue = this.selectedColor;
MyColor newValue = selectedColor;
this.selectedColor = selectedColor;
pcSupport.firePropertyChange(SELECTED_COLOR, oldValue, newValue);
}
}
class StopLightControl {
private StopLightView view;
private StopLightModel model;
public StopLightControl(final StopLightView view, final StopLightModel model) {
this.view = view;
this.model = model;
view.setStopLightControl(this);
model.addPropertyChangeListener(new ModelListener());
}
public void setSelectedColor(MyColor myColor) {
model.setSelectedColor(myColor);
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (StopLightModel.SELECTED_COLOR.equals(evt.getPropertyName())) {
MyColor myColor = model.getSelectedColor();
view.setSelectedColor(myColor);
}
}
}
}
class StopLightView {
private JPanel mainPanel = new JPanel(new GridLayout(0, 1));
private StopLightControl control;
private Map<MyColor, StopLightPanel> colorPanelMap = new EnumMap<>(MyColor.class);
public StopLightView(int diameter) {
MouseAdapter mouseClicked = new MouseClicked();
for (MyColor myColor : MyColor.values()) {
StopLightPanel lightPanel = new StopLightPanel(diameter, myColor);
lightPanel.addMouseListener(mouseClicked);
mainPanel.add(lightPanel);
colorPanelMap.put(myColor, lightPanel);
}
}
public void setSelectedColor(MyColor myColor) {
for (MyColor color : MyColor.values()) {
colorPanelMap.get(color).setLightOn(color == myColor);
}
}
public JComponent getMainPanel() {
return mainPanel;
}
public void setStopLightControl(StopLightControl control) {
this.control = control;
}
private class MouseClicked extends MouseAdapter {
#Override
public void mousePressed(MouseEvent mEvt) {
if (control == null) {
return;
}
StopLightPanel panel = (StopLightPanel) mEvt.getSource();
control.setSelectedColor(panel.getMyColor());
}
}
}
#SuppressWarnings("serial")
class StopLightPanel extends JPanel {
// avoid "magic" numbers
private static final int GAP = 10;
private int diameter;
private MyColor myColor;
private Color onColor;
private Color offColor;
private boolean lightOn;
public boolean isLightOn() {
return lightOn;
}
public void setLightOn(boolean lightOn) {
this.lightOn = lightOn;
repaint();
}
public StopLightPanel(int diameter, MyColor myColor) {
this.diameter = diameter;
this.myColor = myColor;
this.onColor = myColor.getColor().brighter();
this.offColor = myColor.getColor().darker().darker();
this.lightOn = false;
}
public MyColor getMyColor() {
return myColor;
}
#Override
public Dimension getPreferredSize() {
int prefW = diameter + 2 * GAP;
int prefH = prefW;
return new Dimension(prefW, prefH);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// smooth out the edge of our circle
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color color = lightOn ? onColor : offColor;
g2.setColor(color);
g2.fillOval(GAP, GAP, diameter, diameter);
}
}
There is no relationship between the color you are changing in the actionListener and the color the panel is using to paint itself.
Taking a look at the JavaDocs you would note that
darker/brighter
Returns: Creates a new Color that is a darker/brighter version
of this Color.
darker/brighter doesn't change the Color object itself, but creates a new Color object which is darker/brighter than the color you are using
What you should probably do is set the color you want to each panel when the actionListener triggered.
Better yet, you should be using some kind of model, changing the model would notify each instance of the panel and it would then respond by updating itself...

Paint method gets called but doesn't redraw

The problem here is that the paintComponent() method gets called, it gets the necessary variables for fillRect() but doesn't actually draw anything after a key is pressed. I don't understand why since the returned value of mato.getPositionX() does get incremented every time the D key is pressed and the incremented value gets passed to fillRect(). Here's the code:
Screen class
public class Screen extends JFrame implements KeyListener {
private Mato mDrawScreensMato;
public Screen() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
setLocationRelativeTo(null);
setSize(400, 400);
DrawScreen screen = new DrawScreen();
mDrawScreensMato = screen.getMato();
addKeyListener(this);
add(screen);
}
//keyTyped
#Override
public void keyPressed(KeyEvent ke) {
int c = ke.getKeyCode();
if (c == KeyEvent.VK_D) {
mDrawScreensMato.setPositionX(mDrawScreensMato.getPositionX() + 1);
repaint();
}
}
//keyReleased
}
DrawScreen class
public class DrawScreen extends JPanel {
private Mato mato;
public DrawScreen() {
mato = new Mato();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
System.out.println(mato.getPositionX());
g2d.fillRect(
mato.getPositionX(), mato.getPositionY(),
mato.MATO_WIDTH, mato.MATO_HEIGHT
);
}
public Mato getMato() {
return mato;
}
}
Mato class
public class Mato {
final int MATO_WIDTH = 20;
final int MATO_HEIGHT = 20;
final int MATO_START_POS_X = 20;
final int MATO_START_POS_Y = 40;
private int positionX;
private int positionY;
public Mato(){
positionX = MATO_START_POS_X;
positionY = MATO_START_POS_Y;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionX() {
return positionX;
}
//Get/Set positionY
}
The main cause of your problem is you are calling setVisible to early...
The general rule of thumb is, call setVisible only after you have prepared the UI
public Screen() {
DrawScreen screen = new DrawScreen();
mDrawScreensMato = screen.getMato();
addKeyListener(this);
add(screen);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// This is a useless call as DrawScreen
// does not provide appropriate sizing hints to the layout manager
pack();
setSize(400, 400);
// This needs to be called AFTER the size of window has been determined,
// as it uses the size of the window to determine it's location
setLocationRelativeTo(null);
setVisible(true);
}
KeyListener is notoriously troublesome, you would better of using Key Bindings

Categories