Code for drawing BufferedImage on a JPanel

I’m literally been looking around for this and reading tutorials for hours, nearly all day and I haven’t been able to find exactly what I’m looking for. I’m trying to make my game world by using a LayeredPane with different layers representing the different graphical elements (the background, characters, etc). I initially used JLabels as components and had their icons perform this task but realized with BufferedImages and Graphics2D I could manipulate the images and so I’m trying to make the conversion.

Currently I’m running into trouble and don’t really know where to begin. I’ve decided to draw directly onto JPanels and add those as Components to the LayeredPane but I’m running into some trouble. Specifically, I don’t know all the methods needed to accomplish this. So far, all I have in my my constructor (pertaining to the BufferedImages) is:

JPanel background, character;
Graphics2D bgGraph, charGraph;
BufferedImage bg, chara; // Already contain the correct images

public mainConstructor() {

background=new JPanel();
character=new JPanel();

// In order to draw the images on their respective JPanels
bgGraph = (Graphics2D)background.getGraphics();
charGraph = (Graphics2D)character.getGraphics();

bgGraph.drawImage(bg,0,0,null);
charGraph.drawImage(chara, xpos,ypos,null);

// Other code, specifically code adding JPanels to LayeredPane
}

However this doesn’t seem to work. I’ve looked around and there’s code of people overwriting JPanels paintComponent() method and some other draw methods. I don’t really know which are relevant and which other methods would be needed to allow me to repaint/draw the specific images that need updating

Hmm, there seems to be a problem with painting on components placed on JLayeredPane’s.

http://www.java-gaming.org/index.php/topic,10366.0.html

Does anyone know any alternative to JLayeredPane? Something that would allow a number of different layers (as opposed to the normal content and glass pane)?

I don’t think that’s the problem. The issue here is that you’re trying to render directly to the panels by grabbing the graphics contexts. Instead your panels should override paintComponent() and do the rendering there. To force them to paint you’d call repaint() on some component that contains all your panels.

Although I’d have to say that using layered panes doesn’t strike me like the best solution for this kind of application.

But this may be a better question for the game design board.

Dmitri

Override the paintComponent(…) method in JPanel:

public class YourPanel extends JPanel {
  
  // your other code...

  /** 
   * Draws the component. 
   *
   * @param g  Where to draw to. 
   */
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);

    // do your drawing
    // e.g. - if you have an image that you want to draw...
    // this draws the image at coordinate (0, 0) = upper left corner in your panel
    Image image = ... 
    g.drawImage(image, 0, 0, this);
  }
}

Hmm? What would you suggest that would perform the same function?

Also kingaschi, what do you mean by // your other code here? Is the method override the only change I would make to my code?

This what I use when I need a background image on a frame so this might help:


import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;

import javax.swing.JComponent;

	public class BackgroundPanel extends JComponent
	{
		private final  Image guiImage;
		private static final long serialVersionUID = 1L;

		public BackgroundPanel(final Image setGuiImage){
			super();
			setOpaque(false);
			guiImage = setGuiImage;
		}
		@Override
		public void paintComponent(final Graphics g)
		{
			super.paintComponent(g);
			final Dimension d = getSize();
			g.drawImage(guiImage, 0, 0, d.width, d.height, null);
		}
	}

[quote]Also kingaschi, what do you mean by // your other code here? Is the method override the only change I would make to my code?
[/quote]
Correct, that’s the only change needed. By “//” I was referring to other code you might need such as a constructor where you probably pass in the image or create it or load it etc… Up to you if you need that.

Ok, I managed to get it to work. Instead of using a LayeredPane I wrote my own PriorityQueue class which allowed you to enter a number to determine the priority (think Python’s version) and then overrode the paintComponent method in JPanel to paint in order of priority (backgrounds have high priority, everything else lower).

But the problem here is I’m trying to use a JScrollPane to scroll as a character moves along the screen. The background is on a JPanel of the same size and the JScrollPane is just a small square that shows part of the background. The problem is that a huge gray box appears when I add the JScrollPane for some reason. Also, although the panel has the same dimensions as the background image, it is around 10 pixels wider for some reason.vLike this:

	
public classExtendingJPanel()
	{
		// Other code
		background=new JPanel();
		background.setPreferredSize(new Dimension(bg.getWidth(),bg.getHeight()));
		background.setOpaque(false);
		
		
		window=new JScrollPane(background,JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		window.setPreferredSize(new Dimension(bg.getWidth(),bg.getWidth()));
		window.setOpaque(false);
		add(window);
	}

Does this remove the gray square?

window.getViewport().setOpaque(false);

No, it doesn’t. I really don’t know what could be causing it…nothing is opaque…

So, what are you expecting to see behind the JScrollPane? If you put the scroll pane onto a JFrame or JWindow, gray is what you probably expecting?

That was it! I made the mistake of making an empty JPanel, simply to get the window, without painting anything on it while the actual images were painted on the JPanel it was added to, that’s why they appeared in the background. I changed it to paint directly onto that JPanel and add that to a JFrame and it worked perfectly. Now if only I could get my collision detection to work (for some reason objects stop when they collide but if I continue to hold the direction they clip through each other)