Double Buffering

The process of directly painting an image to the screen, completely erasing that image, then painting a new image in its place causes flickering. Double buffering avoids this flickering by creating an off-screen image that is later transferred to the screen.


When the user draws on the canvas, useTool() grabs the current off-screen layer and creates a Graphics2D context associated with that layer. The paint tools draw onto the Graphics2D cgBuffer and stores those changes in BufferedImage cvMem.

Tools.java -- Painting onto off-screen image
56
57
58
59
60
61
62
63
64
65
66
67
68
public void useTool(int numTool, int oldX, int oldY, int newX, int newY) {  // Selects specific tool
    cvMem = layersArray.getImageArray().get(layersArray.getcLayerNum());    // Grabs the current layer
    cgBuffer = (Graphics2D) cvMem.getGraphics();    // Creates the graphics context for that layer to be used in double buffering
    cgBuffer.setColor(menuBar.paintColor);
     
    // The y-coordinates are subtracted by the menu bar's height, because the canvas layers do not include the menu bar
    if (numTool == 1)
        pencil(oldX, oldY - paintLab.getMenuHeight(), newX, newY - paintLab.getMenuHeight());
    else if (numTool == 2)
        brush(oldX, oldY - paintLab.getMenuHeight(), newX, newY - paintLab.getMenuHeight());
    else if (numTool == 3)
        spray(newX, newY - paintLab.getMenuHeight());
}
 
				public void useTool(int numTool, int oldX, int oldY, int newX, int newY) {  // Selects specific tool
					cvMem = layersArray.getImageArray().get(layersArray.getcLayerNum());    // Grabs the current layer
					cgBuffer = (Graphics2D) cvMem.getGraphics();    // Creates the graphics context for that layer to be used in double buffering
					cgBuffer.setColor(menuBar.paintColor);
					
					// The y-coordinates are subtracted by the menu bar's height, because the canvas layers do not include the menu bar
					if (numTool == 1)
						pencil(oldX, oldY - paintLab.getMenuHeight(), newX, newY - paintLab.getMenuHeight());
					else if (numTool == 2)
						brush(oldX, oldY - paintLab.getMenuHeight(), newX, newY - paintLab.getMenuHeight());
					else if (numTool == 3)
						spray(newX, newY - paintLab.getMenuHeight());
				}
				

In my paint program, Graphics2D g2Frame paints the off-screen image stored in ArrayList<BufferedImage> imageArray at the index of int cLayerNum onto the screen. Instead of clearing the entire screen, update() alters the display with only the changes made.

PaintApp.java -- Updating the visible image with changes from off-screen image
202
203
204
205
206
207
208
209
210
211
public void update(Graphics g) {
    // When repaint() is called, the update() then calls paint()
    // Since "default implementation of update() clears the Component's background before calling paint()",
    // I removed the background layers from flickering by drawing the layers here
    for (int k = 0; k < layersArray.getImageArray().size(); k++) {
        g2Frame.drawImage(layersArray.getImageArray().get(k), 0, getMenuHeight(), this);
    }
    paint(g);
}
 
				public void update(Graphics g) {
					// When repaint() is called, the update() then calls paint()
					// Since "default implementation of update() clears the Component's background before calling paint()", 
					// (see http://journals.ecs.soton.ac.uk/java/tutorial/ui/drawing/update.html)
					// I removed the background layers from flickering by drawing the layers here
					for (int k = 0; k < layersArray.getImageArray().size(); k++) {
						g2Frame.drawImage(layersArray.getImageArray().get(k), 0, getMenuHeight(), this);
					}
					paint(g);
				}