Image Flicker / Double Buffering

I’ve been using a different method of double buffering and drawing to a jpanel, but I’d like to try using the jpanel’s native paint / paintComponent method instead.

So, I understand this is a common problem with using a jpanel’s native paint / paint component method. But some people accomplish this simply enough, and claim that it is double buffered by default. I can’t seem to figure it out. I’ve tried reading all kinds of posts and tried all kinds of methods, and I still get a slight flicker. I’m not sure if this is due to double buffering or not – it doesn’t flicker badly. Just a little bit, and just some of the time.

Here’s my current code:
JPanel’s paintComponent method:

	JPanel jpanel = new JPanel() {
        public void paintComponent(Graphics g) {
           super.paintComponent(g);
           if(currentState()!=null) currentState().draw(bufferGraphics);
           g.drawImage(bufferImage, 0, 0, width * scale, height * scale, jpanel); 
       }
	};

And then my call in the game loop:

			if (currentTime - lastRender >= fpslimit) {
				jpanel.repaint();
				//render();
				fps++;
				lastRender = currentTime;
			}

As I remember my earlier trials, I think you should be overriding the update method.


@Override
public void update(Graphics g)
{
    paint(g);
}

And do the painting in the paint method. This is what I did when I tried to get into game programming 4 years ago.

No luck. I also tried moving different components around between paint and paintComponent, and moving repaint() into those components as well, They all produce the same result.

I use this method:

public class ImageRenderer implements ImageProducer, ImageObserver {

	private int[] pixels;
	private int width;
	private int height;
	private ColorModel colorModel;
	private ImageConsumer consumer;
	private Image source;

	public ImageRenderer(Component canvas, int width, int height) {
		this.width = width;
		this.height = height;
		this.pixels = new int[width * height];
		this.colorModel = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); // R G B masks, and 24 bit color
		this.source = canvas.createImage(this);
		YourDrawingCanvas.setPixels(pixels); //Draw to the pixels array using the YourDrawingCanvas class
	}

	public void draw(Graphics g, int x, int y) {
		if (g != null) {
			render();
			g.drawImage(source, x, y, this);
		}
	}

	@Override
	public synchronized void addConsumer(ImageConsumer c) {
		if (consumer == null) {
			consumer = c;
			c.setDimensions(width, height);
			c.setProperties(null);
			c.setColorModel(colorModel);
			c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES | ImageConsumer.SINGLEPASS);
		}
	}

	@Override
	public synchronized boolean isConsumer(ImageConsumer c) {
		return (consumer == c) ? true : false;
	}

	@Override
	public synchronized void removeConsumer(ImageConsumer c) {
		if (consumer == c) {
			consumer = null;
		}
	}

	@Override
	public void startProduction(ImageConsumer c) {
		addConsumer(c);
	}

	@Override
	public void requestTopDownLeftRightResend(ImageConsumer c) {
		System.out.println("TDLR");
	}

	private synchronized void render() {
		if (consumer != null) {
			consumer.setPixels(0, 0, width, height, colorModel, pixels, 0, width);
			consumer.imageComplete(ImageConsumer.TOPDOWNLEFTRIGHT);
		}
	}

	@Override
	public boolean imageUpdate(Image img, int flags, int x, int y, int width, int height) {
		return (flags & (ImageObserver.ALLBITS | ImageObserver.ABORT)) == 0;
	}
}

Instantiate using

renderer = new ImageRenderer(**INSERT INSTANCE OF FRAME/JFRAME**, **Width of Frame/JFrame**, **Height of Frame/JFrame**);

Update/Draw

renderer(frame.getGraphics(), 0, 0);