Java: how to do double-buffering in Swing?

—- Edited to address per pixel setting —-

The item blow addresses double buffering, but there’s also an issue on how to get pixels into a BufferedImage.

If you call

WriteableRaster raster = bi.getRaster()

on the BufferedImage it will return a WriteableRaster. From there you can use

int[] pixels = new int[WIDTH*HEIGHT];
// code to set array elements here
raster.setPixel(0, 0, pixels);

Note that you would probably want to optimize the code to not actually create a new array for each rendering. In addition, you would probably want to optimized the array clearing code to not use a for loop.

Arrays.fill(pixels, 0xFFFFFFFF);

would probably outperform your loop setting the background to white.

—- Edited after response —-

The key is in your original setup of the JFrame and inside the run rendering loop.

First you need to tell SWING to stop Rasterizing whenever it wants to; because, you’ll be telling it when you’re done drawing to the buffered image you want to swap out in full. Do this with JFrame’s

setIgnoreRepaint(true);

Then you’ll want to create a buffer strategy. Basically it specifies how many buffers you want to use

createBufferStrategy(2);

Now that you tried to create the buffer strategy, you need to grab the BufferStrategy object as you will need it later to switch buffers.

final BufferStrategy bufferStrategy = getBufferStrategy();

Inside your Thread modify the run() loop to contain:

...
  move();
  drawSqure(bi1);
  Graphics g = bufferStrategy.getDrawGraphics();
  g.drawImage(bi1, 0, 0, null);
  g.dispose();
  bufferStrategy.show();
...

The graphics grabbed from the bufferStrategy will be the off-screen Graphics object, when creating triple buffering, it will be the “next” off-screen Graphics object in a round-robin fashion.

The image and the Graphics context are not related in a containment scenario, and you told Swing you’d do the drawing yourself, so you have to draw the image manually. This is not always a bad thing, as you can specify the buffer flipping when the image is fully drawn (and not before).

Disposing of the graphics object is just a good idea as it helps in garbage collection. Showing the bufferStrategy will flip buffers.

While there might have been a misstep somewhere in the above code, this should get you 90% of the way there. Good luck!

—- Original post follows —-

It might seem silly to refer such a question to a javase tutorial, but have you looked into BufferStrategy and BufferCapatbilites?

The main issue I think you are encountering is that you are fooled by the name of the Image. A BufferedImage has nothing to do with double buffering, it has to do with “buffering the data (typically from disk) in memory.” As such, you will need two BufferedImages if you wish to have a “double buffered image”; as it is unwise to alter pixels in image which is being shown (it might cause repainting issues).

In your rendering code, you grab the graphics object. If you set up double buffering according to the tutorial above, this means you will grab (by default) the off-screen Graphics object, and all drawing will be off-screen. Then you draw your image (the right one of course) to the off-screen object. Finally, you tell the strategy to show() the buffer, and it will do the replacement of the Graphics context for you.

Leave a Comment