0

I'm trying to paint a background image onto a JFrame for a life simulation game I'm making. This is my code:

public class MainFrame extends JFrame  {
 //creates image variables
Image background;

 public MainFrame(int w, int h) {
    //creates new JFrame and sets some other properties
    super("Life Simulation");
    setLayout(new FlowLayout());
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(new Dimension(w,h));
    //creates images
    background = Toolkit.getDefaultToolkit().createImage("img/default.jpg");
    this.repaint();
    setVisible(true);
}
 @Override
 public void paint(Graphics g) {
         super.paint(g);
         Graphics2D g2d = (Graphics2D) g;
         g.drawImage(background,0,0,null);
     }
}

I've tried to repaint it before setting it visible, but nothing. When I launch my program from my main method, the JFrame is simply blank. However, if I resize it in the slightest, the paint method is called and the background image is painted.

This is my main method:

public class Main {

public static void main(String[] args) {
    MainFrame frame = new MainFrame(1080,720);
    frame.repaint(); //tried invoking paint() here as well but again to no avail
}

}

EDIT: I believe it is also worth mentioning that I have little to no experience beforehand with using paint() or any of its variants, only knowledge of how it SHOULD be implemented and its abilities.

  • 1
    Try Overriding `paintComponent` instead of just `paint`. Let me know what happens. – takendarkk Jul 14 '14 at 16:00
  • Take a look at the second answer. See if that helps. http://stackoverflow.com/questions/1097366/java-swing-revalidate-vs-repaint – imtheman Jul 14 '14 at 16:02
  • @Takendarkk `paintComponent` is an undefined method for `JFrame`, according to the error I get when trying to override such a method. And @imtheman, that result does not help either, since I am not removing any components. – Overclocked Jul 14 '14 at 16:21
  • There is no need to call `repaint()` before the component is displayed. Simply displaying it (with `setVisible(true)`) will cause it to be painted. I believe @Takendarkk is correct about the change you need to make (and should make that comment an answer, if so). – David Conrad Jul 14 '14 at 16:26
  • Ah, I think it's either the rootPane or contentPane that you need to do this on, probably the contentPane. – David Conrad Jul 14 '14 at 16:29
  • Care to elaborate? I'm sorry I'm rather new to this – Overclocked Jul 14 '14 at 16:37

1 Answers1

2

Oh, I'd like to stress the importance of providing an appropriate ImageObserver object when calling the drawImage method. Instead of passing null, I'd recommend passing this:

g.drawImage(background, 0, 0, this);

You can read about the importance of specifying an ImageObserver when loading images asynchronously via Toolkit.createImage.

Aside: Though paintComponent isn't defined for JFrame, I would recommend avoiding overriding JFrame's paint method. Instead, you could create either a reusable ImagePanel class, or just use an anonymous class, and then use that to set the content pane of your JFrame.

Here's an example of an ImagePanel class:

class ImagePanel extends JPanel {
    private Image image;

    public ImagePanel(Image image) {
        this.image = image;
    }

    @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this);
    }
}

Or if you prefer an anonymous class:

setContentPane(new JPanel() {
    @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this);
    }
});
Community
  • 1
  • 1
sgbj
  • 2,264
  • 17
  • 14
  • I was thinking about this as a backup option as well, if I could not paint an image onto the JFrame directly. The good news is that the painting now happens automatically, but the entire image will not paint, only a pixel of it. Any ideas why? – Overclocked Jul 14 '14 at 16:51
  • Images load asynchronously using `Toolkit.createImage`. It's likely that the image hasn't been loaded all the way. Have you tried specifying `this` in place of `null` in your call to `g.drawImage` in your `paint` method? Alternatively you could load the image synchronously with `ImageIO.read`. – sgbj Jul 14 '14 at 16:58
  • Yes, I did make the change to `this` in place of `null`. In fact, this appears to be the reason why paintComponent is called automatically in the first place, as before this I kept running into my original problem. – Overclocked Jul 14 '14 at 17:22
  • EDIT: Oddly enough, it works with the anonymous class but not the other way, haha! I set up this anonymous class internally within my original JFrame constructor, and it works fine. I'd love to know why it works particularly like this and not any of the other ways though @sbat – Overclocked Jul 14 '14 at 21:02
  • Aside: I would definitely +1, but you need 15 rep to do that. Damn :/ – Overclocked Jul 14 '14 at 21:02