bs7280
bs7280

Reputation: 1094

Java Jpanel Appearing only half the time

So I am trying to make a game in java that will display a grid of images as the background, for now it is just grass with the occasional rock as my images, and when it works I get a large display of a grid of 32 by 32 images like expected, but about two thirds of the time, Nothing in my panel appears!

I have eliminated alot of features for the sake of getting down to the problem, and When I run the code, even without repainting several times a second, it will still only sometimes work.

Main class

import javax.swing.JFrame;


public class Main {



    public static void main(String[] args) {
        //Creating a new frame for the whole game and everything
        JFrame frame = new JFrame("Lawlz this is my game");
        frame.setSize(800,800);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setResizable(false);

        //adding the game panel to the main frame
        frame.add(new GameFrame());
    }

}

Game Frame Class (where the pannel is made) THis is the code with nearly everything commented out. Even the animation and player class, yet it still will not display anything about half the time.

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GameFrame extends JPanel {//implements ActionListener {

    Timer mainTimer;
    Player player;
    Random rand = new Random();
    Grid GameGrid = new Grid(25, 25);

    int enemyCount = 5;

    //Constructer!
    public GameFrame()
    {
        setFocusable(true);
        //player = new Player(100,100);
    }

    //Does all of the drawing for the game
    public void paint(Graphics g)
    {
        //Sends to the JPanel class (super class)
        super.paint(g);

        //gets a graphics 2d object
        Graphics2D g2d = (Graphics2D)g;

        GameGrid.draw(g2d);
    }
}

The GameGrid class, which basically holds lots of 'grid space' objects, each one basically just being an image. It is also responsible for, at this point, printing out most of everything that is drawn with the draw() method

import java.awt.Graphics2D;
import java.util.ArrayList;


public class Grid {

    ArrayList<GridSpace> grid = new ArrayList<GridSpace>();
    int width;
    int height;

    public Grid(int w, int h)
    {
        width = w;
        height = h;

        //Temporary for creating the x and y values by using the size of the images
        int gw = new GridSpace(0,0).getGridImg().getWidth(null);
        int gh = new GridSpace(0,0).getGridImg().getHeight(null);

        for(int i = 0; i < h; i++)
        {
            for(int n = 0; n < w; n++)
            {
                grid.add(new GridSpace(n*gw,i*gh));   //GridSpace(n*ImageWidth, i*ImageHeight)
            }
        }
    }

    public void draw(Graphics2D g2d)
    {
        for(int i = 0; i < width; i++)
        {
            for(int n = 0; n < height; n++)
            {
                GridSpace tempSpace = GetGridSpaceByID(GetCoordinates(n,i)); //gets the GridSpace object for this corrdinate
                g2d.drawImage(tempSpace.getGridImg(),tempSpace.x,tempSpace.y,null);
            }
        }
    }

    public void test(Graphics2D g2d)
    {
        GridSpace tempSpace = GetGridSpaceByID(GetCoordinates(0,0));
        g2d.drawImage(tempSpace.getGridImg(),tempSpace.x,tempSpace.y,null);
    }

    public GridSpace GetGridSpaceByID(int n)
    {
        return grid.get(n);
    }

    public int GetCoordinates(int x, int y)
    {
        return x + y * width;
    }


}

And finally, the GridSpace object which basically just stores an image

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.util.Random;

import javax.swing.ImageIcon;


public class GridSpace {
    Random r = new Random();
    ImageIcon ic;
    int x = 0;
    int y = 0;

    public GridSpace(int x,int y)
    {
        this.x = x;
        this.y = y;

        //Stores an image for this grid space
        //ic = new ImageIcon("C:\\Users\\Ben\\Desktop\\pic1.png");
        if(r.nextInt(10) < 9)
        {
            ic = new ImageIcon("C:\\Users\\Ben\\Desktop\\Video Game\\grass1.jpg");
        }
        else
        {
            ic = new ImageIcon("C:\\Users\\Ben\\Desktop\\Video Game\\grass2.jpg");
        }
    }

    public Image getGridImg()
    {
        //Image image = ic.getImage();
        return ic.getImage();
    }
}

Upvotes: 1

Views: 746

Answers (3)

Radu Murzea
Radu Murzea

Reputation: 10920

Some of these issues can also appear if you're calling Swing-related code in the main thread. Try doing it in the EDT (Event Dispatch Thread).

To do this, change your Main class to this:

import javax.swing.JFrame;

public class Main {

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater (new Runnable ()
        {
            public void run ()
            {
                //Creating a new frame for the whole game and everything
                JFrame frame = new JFrame("Lawlz this is my game");
                frame.setSize(800,800);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
                frame.setResizable(false);

                //adding the game panel to the main frame
                frame.add(new GameFrame());
            }
        });
    }
}

See here for more details.

Upvotes: 2

Andrew Thompson
Andrew Thompson

Reputation: 168845

  1. GameFrame (which might more accurately be called GamePanel) should override getPreferredSize() to return a dimension suitable for the game play area. The frame itself has its own decorations, and will be bigger.
  2. The order of calls in the main is wrong. Call setVisible(true) as the very last part.
  3. Also note the advice to start the GUI on the EDT.

Here is a main from my current 'frame demo' template that shows that last two points & provides some other good tips.

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            // the GUI as seen by the user (without frame)
            JPanel gui = new JPanel(new BorderLayout());
            gui.setBorder(new EmptyBorder(2,3,2,3));

            // TODO!
            gui.setPreferredSize(new Dimension(400,100));
            gui.setBackground(Color.WHITE);

            JFrame f = new JFrame("Demo");
            f.add(gui);
            // Ensures JVM closes after frame(s) closed and
            // all non-daemon threads are finished
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            // See http://stackoverflow.com/a/7143398/418556 for demo.
            f.setLocationByPlatform(true);

            // ensures the frame is the minimum size it needs to be
            // in order display the components within it
            f.pack();
            // should be done last, to avoid flickering, moving,
            // resizing artifacts.
            f.setVisible(true);
        }
    };
    // Swing GUIs should be created and updated on the EDT
    // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
    SwingUtilities.invokeLater(r);
}

Upvotes: 2

Reimeus
Reimeus

Reputation: 159854

As you're currently adding adding the GameFrame panel after calling

frame.setVisible(true);

it will not be painted until an event such as resize is carried out. You should have this call to setVisible as the last method in your main method. Also use paintComponent rather than paint to take advantage of Swing's optimized paint model.

Obligatory Link: Painting in AWT and Swing

Upvotes: 2

Related Questions