Wednesday 20 July 2011

Avoid Flickering in Java Graphics Program

Issue:
 Flickering is a big problem while drawing something on screen in Java. Flickering normally occurs when drawing images one after another. Though flickering is a big problem people might think that it could be very complicated to avoid or remove it completely, but it is quite easy to that. By making some simple changes in your code you can completely remove flickering in your animations.

What causes flickering in Java? 
Before flickering problem can be solved, we should know what causes it? As we know the paint() method in Java first clears the screen and then paints a new frame on the window. So there are two operations takes place when we can the paint() or repaint() method. So some times screen gets updated between the clearing of window and painting of new frame and in that moment of time we can see the cleared window and that makes it appear to be flicker.

Remove Flickering using Double Buffering:
As now we know that the flickering occurs because of refreshing of screen between the clearing of window and painting of new frame, so the solution is to paint the window in such a way that screen doesn't get refreshed before window get completely painted.
This can be done using the Double Buffering. To implement Double Buffering a BufferedImage class. A BufferedImage object is like an Image object except it has some method that makes it easier to work with.

Code in which flickering problem occur

public void run(){
            try{
                Thread.sleep(50);
            }
             catch(Exception e){ }
            repaint();
}
public void paint(Graphics g){
         animation(g);          //this function performs all animation
}


Code for Declaration of Buffered Image object

 
BufferedImage  bf = new BufferedImage( this.getWidth(), this.getHeight(), 
BufferedImage.TYPE_INT_RGB);

Code for Remove flickering in paint method by using Buffered Image
public void run(){
           
            while(true){
            try{
                  Thread.sleep(50);
            }catch(Exception ex){
                 
            }
            paint(this.getGraphics());
            }
      }
public void paint(Graphics g){
           
            animation(bf.getGraphics()); //bf is the BufferedImage object
            g.drawImage(bf,0,0,null);
      }

This is how a Buffered Image object is use to prevent the flicker problem. When calling the animation() method a graphics object is extracted form Buffered Image. This Buffered Image graphics object is same as the normal(window) graphics object except this graphics object contains information about the Buffered Image instead of the actual window. That means the animation method paints the new frame on the Buffered Image instead of the actual window. So far the window still holds the old frame and the Buffered Image holds the new frame. Than a call is made to the drawImage() method of graphics object of the window. So now in only one operation the whole content of window is replace by  the content of Buffered Image. This is known as an atomic operation and the screen can not get refreshed while the window is partially painted. This is how the flickering problem can be solved and this code can be use for any type of application.

Now to understand why this code does not use repaint() method we need to understand the repaint() method.

Working of repaint() method:
Some people might think that repaint() method calls to the paint() method, eventually it does but it is not the whole story though. A repaint() method actually calls the update() method and the default update() method then calls to the paint() method. If you Java code did not override update(), the default implementation of update() clears the component's background and simply calls paint().
So if we want to use repaint() method we have to override update() method to avoid flickering.

public void run(){
           
            while(true){
            try{
                  Thread.sleep(50);
            }catch(Exception ex){
                 
            }
              repaint();
            }
      }

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

public void paint(Graphics g){
           
            animation(bf.getGraphics()); //bf is the BufferedImage object
            g.drawImage(bf,0,0,null);
}
 You can download code from,
http://javacodespot.110mb.com/NoFlickering.zip

No comments:

Post a Comment