Question

I am trying to build a simple basic to a game for my class in Game Engine Architecture. But my JFrame just wont show anything.

My code is currently structured like this:

Implementation.java (This is some arbitrary implementation of the Engine-package I'm creating)

public class Implementation {
    public static void main(String[] args){
        World w = new World("Hej", "M:\\workspace\\SP6\\pics\\tulips.jpg",1024,768);
    }
}

World.java

public class World extends JFrame{
private static final long serialVersionUID = 1L;
private SpritePanel spritePanel;
private JPanel bottom;
private int width;
private int height;

public World(String windowCaption, String bgPath, int width, int height){
    super(windowCaption);

    spritePanel = new SpritePanel(bgPath);
    add(spritePanel, BorderLayout.CENTER);
    System.out.println(spritePanel);

    bottom = new JPanel();
    bottom.add(new JLabel("Hej"));
    add(bottom, BorderLayout.SOUTH);

    Dimension size = new Dimension(width,height);
    setSize(size);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    pack();
    setVisible(true);

    validate();
    repaint();      
}

SpritePanel.java

public class SpritePanel extends JPanel {
private static final long serialVersionUID = 1L;
private ImageIcon background;
private ArrayList<Sprite> sprites = new ArrayList<Sprite>();

public SpritePanel(String bgPath){
    background = new ImageIcon(bgPath);
    setLayout(null);
    Dimension size = new Dimension(background.getIconWidth(), background.getIconHeight());
    setPreferredSize(size);
    setMaximumSize(size);
    setMinimumSize(size);
}

@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    g.drawImage(background.getImage(), 0, 0, this);
    System.out.println("painted panel");
}
}

So the basic action flow at the moment (from what I can see):

  1. I create a new World object in the Implementation
  2. The World-constructor is called with the given parameters
  3. The window caption is set (this works)
  4. I create a new SpritePanel object with the given bgPath
  5. The SpritePanel-constructor is called and sets the ImageIcon to the image that exists in the given path
  6. The SpritePanel is added to the frame in BorderLayout.CENTER
  7. I add a new JPanel to the frame in BorderLayout.CENTER
  8. I set size and stuff
  9. I pack and set the frame to visible
  10. I validate and repaint

The thing is the paintComponent methods in the JPanel and SpritePanel doesn't seem to get called. As you can see I added a System.out.println in the paintComponent for SpritePanel and that line is never executed.

Another thing I noticed is that the pack seems to know that the components are there. Because if I comment the three lines

spritePanel = new SpritePanel(bgPath);
add(spritePanel, BorderLayout.CENTER);
System.out.println(spritePanel);

The windows size when I run the program is reduced to the size of the "bottom"-JPanel. I can't see the JLabel that I added to the panel but the window size is the size of it. So the pack() method seems to be finding the dimensions of my components.

If I comment the three lines that adds the bottom panel as well the window size is reduced to no height and the width it gets from the standard icons.

I've been trying different things to get it to work but to no avail. I have programmed with Swing before and made working programs but I just can't seem to find the problem here.

Help very much appreciated.

Was it helpful?

Solution

Something may be wrong with your with your String path. What you should do though, instead o reading a file, you should be reading a URL, loading from the class path. At time of deployment, you'll find out that the file path won't work, so it's better to package your image as an embedded resource, putting the image in the class path. I had no problems when doing this. Here's what I did.

  • Change the path to a path relative to my class path

    World w = new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
    
  • Changed loading from a file to loading from a URL from my class path

    background = new ImageIcon(SpritePanel.class.getResource(bgPath));
    
  • Put the image in resources package in my class path

enter image description here

Everything works fine

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Implementation {

    public static void main(String[] args) {
        World w = new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
    }
}

class World extends JFrame {

    private static final long serialVersionUID = 1L;
    private SpritePanel spritePanel;
    private JPanel bottom;
    private int width;
    private int height;

    public World(String windowCaption, String bgPath, int width, int height) {
        super(windowCaption);

        spritePanel = new SpritePanel(bgPath);
        add(spritePanel, BorderLayout.CENTER);
        System.out.println(spritePanel);

        bottom = new JPanel();
        bottom.add(new JLabel("Hej"));
        add(bottom, BorderLayout.SOUTH);

        Dimension size = new Dimension(width, height);
        setSize(size);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        pack();
        setVisible(true);

        validate();
        repaint();
    }

    class SpritePanel extends JPanel {

        private static final long serialVersionUID = 1L;
        private ImageIcon background;
//private ArrayList<Sprite> sprites = new ArrayList<Sprite>();

        public SpritePanel(String bgPath) {
            background = new ImageIcon(SpritePanel.class.getResource(bgPath));
            setLayout(null);
            Dimension size = new Dimension(background.getIconWidth(), background.getIconHeight());
            setPreferredSize(size);
            setMaximumSize(size);
            setMinimumSize(size);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(background.getImage(), 0, 0, this);
            System.out.println("painted panel");
        }
    }
}

Side Notes

  • No need to setSize(). You already pack(). It better to just pack anyway.
  • Put the pack() before the setLocationRelativeTo(). If you pack() after, you'll notice your frame won't be in the desired location.
  • Run your Swing apps from the Event Dispatch Thread (EDT) like this

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
            }
        });
    }
    
  • If you want to make the frame fill the screen, don't set the size. Different machines have different screen sizes. Instead use setExtendedState(JFrame.MAXIMIZED_BOTH);

  • Also, your setSize() won't work anyway because you're calling pack() after.

OTHER TIPS

My problem was that I hade overridden the getWidth() and getHeight() methods in my World-class. But look to peeskillets response for how to make things better!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top