views:

443

answers:

5

I have the following code, which is run every 10ms as part of a game:

private void gameRender()
{
    if(dbImage == null)
    {
        //createImage() returns null if GraphicsEnvironment.isHeadless()
        //returns true. (java.awt.GraphicsEnvironment)
        dbImage = createImage(PWIDTH, PHEIGHT);
        if(dbImage == null)
        {
            System.out.println("dbImage is null"); //Error recieved
            return;
        }
        else
        dbg = dbImage.getGraphics();
    }

    //clear the background
    dbg.setColor(Color.white);
    dbg.fillRect(0, 0, PWIDTH, PHEIGHT);

    //draw game elements...

    if(gameOver)
    {
        gameOverMessage(dbg);
    }
}

The problem is that it enters the if statement which checks for the Image being null, even after I attempt to define the image. I looked around, and it seems that createImage() will return null if GraphicsEnvironment.isHeadless() returns true.

I don't understand exactly what the isHeadless() method's purpose is, but I thought it might have something to do with the compiler or IDE, so I tried on two, both of which get the same error (Eclipse, and BlueJ). Anyone have any idea what the source of the error is, and how I might fix it?

Thanks in advance

Jonathan

...................................................................

EDIT: I am using java.awt.Component.createImage(int width, int height). The purpose of this method is to ensure the creation of, and edit an Image that will contain the view of the player of the game, that will later be drawn to the screen by means of a JPanel. Here is some more code if this helps at all:

public class Sim2D extends JPanel implements Runnable
{

private static final int PWIDTH = 500;
private static final int PHEIGHT = 400;
private volatile boolean running = true;
private volatile boolean gameOver = false;

private Thread animator;

//gameRender()
private Graphics dbg;
private Image dbImage = null;


public Sim2D()
{   
    setBackground(Color.white);
    setPreferredSize(new Dimension(PWIDTH, PHEIGHT));

    setFocusable(true);
    requestFocus(); //Sim2D now recieves key events
    readyForTermination();

    addMouseListener( new MouseAdapter() {
        public void mousePressed(MouseEvent e)
        { testPress(e.getX(), e.getY()); }
    });
} //end of constructor

private void testPress(int x, int y)
{
    if(!gameOver)
    {
        gameOver = true; //end game at mousepress
    }
} //end of testPress()


private void readyForTermination()
{
    addKeyListener( new KeyAdapter() {
        public void keyPressed(KeyEvent e)
        { int keyCode = e.getKeyCode();
            if((keyCode == KeyEvent.VK_ESCAPE) ||
               (keyCode == KeyEvent.VK_Q) ||
               (keyCode == KeyEvent.VK_END) ||
               ((keyCode == KeyEvent.VK_C) && e.isControlDown()) )
            {
                running = false; //end process on above list of keypresses
            }
        }
    });
} //end of readyForTermination()

public void addNotify()
{
    super.addNotify(); //creates the peer
    startGame();       //start the thread
} //end of addNotify()

public void startGame()
{
    if(animator == null || !running)
    {
        animator = new Thread(this);
        animator.start();
    }
} //end of startGame()


//run method for world
public void run()
{
    while(running)
    {
        long beforeTime, timeDiff, sleepTime;

        beforeTime = System.nanoTime();

        gameUpdate(); //updates objects in game (step event in game)
        gameRender(); //renders image
        paintScreen(); //paints rendered image to screen

        timeDiff = (System.nanoTime() - beforeTime) / 1000000;
        sleepTime = 10 - timeDiff;

        if(sleepTime <= 0) //if took longer than 10ms
        {
            sleepTime = 5; //sleep a bit anyways
        }

        try{
            Thread.sleep(sleepTime); //sleep by allotted time (attempts to keep this loop to about 10ms)
        }
        catch(InterruptedException ex){}

        beforeTime = System.nanoTime();
    }

    System.exit(0);
} //end of run()

private void gameRender()
{
    if(dbImage == null)
    {
        dbImage = createImage(PWIDTH, PHEIGHT);
        if(dbImage == null)
        {
            System.out.println("dbImage is null");
            return;
        }
        else
        dbg = dbImage.getGraphics();
    }

    //clear the background
    dbg.setColor(Color.white);
    dbg.fillRect(0, 0, PWIDTH, PHEIGHT);

    //draw game elements...

    if(gameOver)
    {
        gameOverMessage(dbg);
    }
} //end of gameRender()

} //end of class Sim2D

Hope this helps clear things up a bit, Jonathan

A: 

isHeadless will only return true if you are running in a non-GUI environment (eg, within a server or servlet container).

I believe that your problem is within your createImage method itself. Can you give us more context? Which createImage method is being called and what is its implementation?

jsight
A: 

Instead of createImage(...), I usually use a BufferedImage.

camickr
I am following out of a text for educational purposes, and would prefer to keep to using an Image if at all possible so I can keep as close to the code examples and such.Is there perhaps another way around it?Are there other benefits and/or reasons to use the BufferedImage?
Jonathan
camickr is making a good point. Also, Image is an abstract class. Whenever you are working with an image, you are actually dealing with one of several possible implementations of Image under the hood. BufferedImage is one of these, and it's the one that makes sense to use.
z5h
Okay, I will attempt to use BufferedImage. Thank you.
Jonathan
A: 

According to the docs for java.awt.Component, createImage can also return null if the component is not displayable, which is most likely what's happening.

For what you are trying to do you should look at the BufferedImage class, as this isn't tied to the component.

William Rose
A: 

Looks like the thread is starting up earlier than the component is actually displayed on screen. To make sure this doesn't happen, you can override the paint(Graphics g) method of JPanel and put the code in the thread's run() method inside of the paint method. In your thread's run() methods, just call repaint().

e.g:

public void paint(Graphics g){
        **gameUpdate(); //updates objects in game (step event in game)
        gameRender(); //renders image
        paintScreen(); //paints rendered image to screen**
}

and in your run() method:

public void run(){
 while(running)
    {
        long beforeTime, timeDiff, sleepTime;

        beforeTime = System.nanoTime();

        **repaint();**

        timeDiff = (System.nanoTime() - beforeTime) / 1000000;
        sleepTime = 10 - timeDiff;

        if(sleepTime <= 0) //if took longer than 10ms
        {
            sleepTime = 5; //sleep a bit anyways
        }

        try{
            Thread.sleep(sleepTime); //sleep by allotted time (attempts to keep this loop to about 10ms)
        }
        catch(InterruptedException ex){}

        beforeTime = System.nanoTime();
    }
}
Suresh Kumar
A: 

I had exactly the same problem after I tried to implement Doublebuffering for a fractal generator. My solution: I took the example from a book but changed it (without knowing the consequences) in the way that I ran createImage INSIDE the constructor. This produced the nullpointer. Then i put this

if (_dbImage == null) {
_dbImage = createImage(getSize().width, getSize().height);
_dbGraphics = (Graphics2D)_dbImage.getGraphics();
}

inside the update-method and it worked !! Because update is called AFTER the object has been constructed.

3.14