0

I need to invoke getWidth() on my JPanel object "gameboard" and store it in a variable "width". It would seem like a simple

int width = gameboard.getWidth();

However I get an error "cannot reference field before it is defined". Which led me to believe that the wrong object was being referred to, so I changed it to int width = this.gameboard.getWidth(); Now Eclipse shows that gameboard refers to GameBoard Game.gameboard (which is the JPanel object I want), but I get a Exception in thread "AWT-EventQueue-0" Here is some of the code, I hope its enough to explain my situation (all the code is 1000+ lines as its something my professor wrote that he is having us modify).

class Game extends JFrame {
    /* Type your variable declarations here */

    // Score of game
    int score = 0;

    // Get board size
    // int width = this.gameboard.getWidth();
    // int height = this.gameboard.getHeight();

// Game objects -- Was going to pass width and height variable to these
Sprite cat = new Sprite(new ImageIcon("cat.gif").getImage(), 267, 167);
Sprite bananas1 = new Sprite(new ImageIcon("bananas.png").getImage(), randomNumber(0, gameboard.getWidth()), randomNumber(0, 480));
Sprite bananas2 = new Sprite(new ImageIcon("bananas.png").getImage(), randomNumber(gameboard.getWidth(),640), randomNumber(0, 480));

...

 /** The panel where all of the game's images are rendered */
    GameBoard gameboard = null;

...

/**
 * Constructor for the game.
 * <p>
 * <pre>
 * The following tasks are performed:
 * a frame is displayed on the screen
 * a clock is created; the clock invoked repaint 15 times per second
 * a keyboard listener listens for presses of the arrow keys & space bar
 * </pre>
 * <p>
 */
public Game() {

    /* how large is the window? */
    setSize(640,480);

    /* if the end-user clicks on the x in the upper right corner, */
    /* close this app                                             */
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    /* allow the window to receive the focus; */
    /* we want this window to see key presses */
    setFocusable(true);

    /* this window can receive keyboard events */
    addKeyListener(new MyKeyListener());

    /* make the window visible */
    setVisible(true);

    /* add MyPanel to the window */
    setLayout(new GridLayout(1,1));
    gameboard = new GameBoard();
    add(gameboard);

    validate();

}//Game




/**
 * Panel that displays all the graphics in the game.
 * <p>
 * Why do I need a panel--why can't I display the graphics in the frame?
 * I want to the top of the graphics area to be at y=0.
 * <p>
 * Offscreen buffers are used to create a rock-solid animation that does not blink.
 * <p>
 * Focus is given to the panel so that the panel can listen for key presses.
 * <p>
 * The clock invokes repaint 15 times per second.
 */
public class GameBoard extends JPanel {

    /** offscreen buffers are used to create a rock-solid animation that does not blink */
    protected Image offscreenImage = null;
    /** offscreen buffers are used to create a rock-solid animation that does not blink */
    protected Graphics offscreenGraphics = null;

    /**
     * Constructor for the main panel in this game;
     * all of the graphics are displayed on this panel.
     * <p>
     * <pre>
     * Focus is given to the panel so that the panel can listen for key pressed.
     * NOTE:  Focus determines who receives the characters that are typed on the keyboard--
     * the entity that has the focus receives the characters.
     * A keyboard listener is created to listen for key pressed.
     * A clock is created; the clock invokes repaint 15 times per second.
     * </pre>
     * <p>
     */
    public GameBoard() {
        /* allow this panel to get the focus */
        setFocusable(true);
        /* give this panel the focus */
        requestFocus();
        /* Now that this panel has the focus, this panel can receive keyboard events */
        addKeyListener(new MyKeyListener());
        /* this window can receive mouse motion events */
        addMouseMotionListener(new MyMouseMotionListener());
        /* this window can receive mouse events */
        addMouseListener(new MyMouseListener());
        /* start a clock that invokes repaint 15 times per second */
        new ThreadClock().start();
    }//MyPanel

...

    /**
     * Play the game
     * @param args Command line arguments
     */
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new Game();
            }
            });
    }//main

}//Game
cbalos
  • 879
  • 1
  • 9
  • 19

3 Answers3

3
class Game extends JFrame {
    /* Type your variable declarations here */

    // Score of game
    int score = 0;

    // Get board size
    int width = this.gameboard.getWidth();
    int height = this.gameboard.getHeight();

    /** The panel where all of the game's images are rendered */
    GameBoard gameboard = null;

Based on this you will have a number of problems...

  1. When you initialise width and height, GameBoard will be null. This will cause a NullPointerException, this will occur because the instance fields are initialized before the constructor is executed
  2. If you were to initialise the GameBoard when it is declared (GameBoard gameboard = new GameBoard()), then when width and height are read, they will be 0, as gameBoard will not have been added to the parent container nor will it have been laid out.

This then raises the question, why? If you need to know the width or height of the gameboard, you should just ask it when you need to know.

You should know that with the frame been resizable, storing the values in this way is just useless, if the user resizes the frame, the values become invalid...

Side notes...

  • setFocusable(true); is really useless, there is a JRootPane and content pane and it's contents (and possibly a glass pane) between the keyboard and the frame itself, any of these could steal focus from the frame, rendering this useless...
  • addKeyListener(new MyKeyListener()); for the reasons above, this is useless, you should be using key bindings instead, which overcomes all the problems of focus...
  • setVisible(true); should be done last, after you've initialised the UI and added all the initial components
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • See my updated code (near the top) to see what I am trying to do with the width and height. I was instructed by my professor to use `gameboard.getWidth()` to get the width of the board, so I can set the max int of the `randomNumber()` method. Its an intro programming class, and he has really dumbed it down, so I feel like there should be a way (that he is intending us to use) to use `gameboard.getWidth()` or a variation of that up around where I have it now (thats the only place he claims we need to write any code) – cbalos Apr 12 '14 at 09:35
  • It really makes little difference, until the frame is realised (made visible on the screen) and the `GameBoard` is laid out, `getWidth` and `getHeight` will return `0`. You need to be able to determine when this state changes. – MadProgrammer Apr 12 '14 at 09:41
  • Is there where the component listener would come in? – cbalos Apr 12 '14 at 09:42
  • Yes, but understand, a component listener will be notified multiple times as the componet is realised and changes due to other changes in the ui – MadProgrammer Apr 12 '14 at 10:29
  • 1
    Take a look at http://stackoverflow.com/questions/19020702/moving-a-ball-on-the-screen-with-buttons-cant-program-the-initial-position/19021365#19021365 this for some ideas – MadProgrammer Apr 12 '14 at 10:35
1

You're trying to reference gameboard before you've defined it (i.e. too early in the source code), that's the compile time error, however, gameboard is null, so it would throw an error anyways.

You need to set the width and height after you've built and displayed it, so it actually has a width and a height.

Even better, get rid of the width and height variables, since you can get them directly from gameboard if you need them (and they're guaranteed to represent the actual values). Keeping these extra variables will only introduce more bugs for you.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • From my understanding, a JPanel would always return 0 width without a component listener, is this true? Do you mean I should use getWidth() wherever I need to get the width, rather than storing it as a variable? – cbalos Apr 12 '14 at 09:11
  • Component listeners are not related to anything here. Yes, I meant that you should call getWidth(). There is no advantage in keeping a separate variable, which will also get out of synch if the size happens to change. – Kayaman Apr 12 '14 at 09:15
  • So if I call getWidth() after gameboard has been constructed and added to the JFrame, would it return the width? The reason I mention this and the component listener is this answer: http://stackoverflow.com/a/8336316/3090356 – cbalos Apr 12 '14 at 09:27
  • I wouldn't use a ComponentListener. The comment discusses its downsides as well. The correct sizes are returned when the panel is rendered, i.e. it's visible. At what point do you intend to use the width? Is the user interface visible at that point? I'd just stop worrying and use the getWidth() when you actually need that value. – Kayaman Apr 12 '14 at 10:04
0

You should instanciate your gameboard variable.

public class Game extends JFrame {

    this.gameboard = new GameBoard();

    // Score of game
    int score = 0;

    // Get board size
    int width = this.gameboard.getWidth();
    int height = this.gameboard.getHeight();
}
Hunsu
  • 3,281
  • 7
  • 29
  • 64