Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My JFrame doesn't show anything

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.

like image 417
chanpa Avatar asked Jan 27 '14 13:01

chanpa


People also ask

How do I display a JFrame?

A JFrame is like a Window with border, title, and buttons. We can implement most of the java swing applications using JFrame. By default, a JFrame can be displayed at the top-left position of a screen. We can display the center position of JFrame using the setLocationRelativeTo() method of Window class.

Is JFrame a GUI?

JFrame class is a type of container which inherits the java. awt. Frame class. JFrame works like the main window where components like labels, buttons, textfields are added to create a GUI.

What is the difference between JFrame and frame?

JFrame is a top-level container that provides a window on the screen. A frame is actually a base window on which other components rely, namely the menu bar, panels, labels, text fields, buttons, etc. Almost every other Swing application starts with the JFrame window.

What is the difference between JFrame and JDialog?

JFrame is a normal window with its normal buttons (optionally) and decorations. JDialog on the other side does not have a maximize and minimize buttons and usually are created with JOptionPane static methods, and are better fit to make them modal (they block other components until they are closed).


1 Answers

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.
like image 72
Paul Samsotha Avatar answered Oct 05 '22 12:10

Paul Samsotha