3

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); } } 
1
  • Don't use a KeyListener for this but rather use Key Bindings. The bindings are a higher level concept and their use allows you to get around the kludge of making JPanels focusable and KeyListeners not working if anything happens to steal the focus. Commented May 14, 2015 at 0:13

3 Answers 3

5

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(); } } 
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, but this stops me from changing x and y, I actually only want that to be the starting position. Correct me if it's actually not stopping me from doing that :)
@RichardKoetschruyter: what exactly is your program doing? Perhaps if we understood things better, we can come up with a better solution.
sorry, last question I was told to keep it brief. I want to have a square in the middle of the screen, and by pressing the arrow keys, I want it to move around, and stop moving in a direction once the arrow key that belongs to that direction is no longer pressed. I just created all of the code, I only can't get the square to start at a relative position to the screen size. I now use a keylistener to put it in the middle by pressing escape, because the size seems to have been set once I press escape.
2

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

2 Comments

Why create two new Board(...) objects?
oh my fault just to test something :D
1

You can take x and y values after the panel has become visible, in the next EDT cycle, by using SwingUtilities.invokeLater, for example.

1 Comment

Thanks for your answer, I've never worked with SwingUtilities, but I'll give it a try, and see what that class can do, hopefully it'll help me with this problem

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.