Is the paint method supposed to constantly be called in a JPanel? Is there a way to stop it?

Nicola Ken Barozzi

First of all, why would you want to stop paint() from being called in a graphical component?

If you do it nothing will be drawn. Unless, of course, you call it on your own, but why stopping something to create something else that does the same thing, and in a standard and consistent way between components?

Usually you deal with paint() and the methods that call it for performance reasons or to eliminate flickering. For the first part performance is rarely on the paint side, and if it is you don't eliminate paint(). As for flickering as you will see in a moment things can be done quite easily.

Maybe you think that paint(), being called continuously, can bog down your app speed; it is not so, because it is not called continuously but only when needed by the window manager (for example resizes, windows overlapping, etc.) or by you, when you do animations.

Let's start by looking at the class Component; Panel extends Component, an uses the paint system written in Component. The following considerations are for all classes that extend Component directly or indirectly. The code is from the source code of the Java classes V1.2.2.

/**
 * Paints this component.  This method is called when the contents
 * of the component should be painted in response to the component
 * first being shown or damage needing repair.  The clip rectangle
 * in the Graphics parameter will be set to the area which needs
 * to be painted.
 * @param g The graphics context to use for painting.
 * @see       java.awt.Component#update
 * @since     JDK1.0
 */
public void paint(Graphics g) {
}

As you can see paint does nothing.

By searching "paint(" in the file you can find that paint() is called by the following methods:

update()
paintAll()
print()

Let's see update:

/**
 * Updates this component.
 * 
 * The AWT calls the update method in response to a
 * call to repaint. The appearance of the
 * component on the screen has not changed since the last call to
 * update or paint. You can assume that
 * the background is not cleared.
 * 
 * The update method of Component
 * does the following:
 * 
 * - Clears this component by filling it 
 *     with the background color.
 * - Sets the color of the graphics context to be
 *     the foreground color of this component.
 * - Calls this component's paint 
 *     method to completely redraw this component.
 *
 * The origin of the graphics context, its
 * (0, 0) coordinate point, is the
 * top-left corner of this component. The
 * clipping region of the
 * graphics context is the bounding rectangle
 * of this component.
 * @param g the specified context to use for updating.
 * @see java.awt.Component#paint
 * @see java.awt.Component#repaint()
 * @since JDK1.0
 */
public void update(Graphics g) {
  if ((this instanceof java.awt.Canvas) ||
      (this instanceof java.awt.Panel) ||
      (this instanceof java.awt.Frame) ||
      (this instanceof java.awt.Dialog) ||
      (this instanceof java.awt.Window)) {

    g.clearRect(0, 0, width, height);
  }
  paint(g);
}

As is stated in the documentation of the method, update() is called by repaint().

In the code you see that it Sets the color of the graphics context to be the foreground color of this component. Calls this component's paint method to completely redraw this component.

To eliminate flickering usually you only need to write a class that extends Component (or any other class that inherits directly or indirectly from it like Panel) with this method:

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

Flickering is created by the continuous alternation of the animation frames and foreground-colored rectangles, and with the above code you don't draw the rectangle any more.

Here is paintAll():

/**
 * Paints this component and all of its subcomponents.
 * 
 * The origin of the graphics context, its
 * (0, 0) coordinate point, is the
 * top-left corner of this component. The clipping region of the
 * graphics context is the bounding rectangle of this component.
 * @param g the graphics context to use for painting.
 * @see java.awt.Component#paint 
 * @since JDK1.0
 */
public void paintAll(Graphics g) {
  ComponentPeer peer = this.peer;
  if (visible && (peer != null)) {
    validate();
    if (peer instanceof java.awt.peer.LightweightPeer) {
      paint(g);
    } else {
      peer.paint(g);
    }
  }
}

It calls paint only with a java.awt.peer.LightweightPeer.

Here is print():

/**
 * Prints this component. Applications should override this method
 * for components that must do special processing before being
 * printed or should be printed differently than they are painted.
 * 
 * The default implementation of this method calls the
 * paint method.
 * 
 * The origin of the graphics context, its
 * (0, 0) coordinate point, is the
 * top-left corner of this component. The clipping region of the
 * graphics context is the bounding rectangle of this component.
 * @param g the graphics context to use for printing.
 * @see java.awt.Component#paint(java.awt.Graphics)
 * @since JDK1.0
 */
public void print(Graphics g) {
paint(g);
}

print() just calls paint(). From these three methods you can see that to totally eliminate calls to paint() you just need to write a class that extends Component (or any other class that inherits directly or indirectly from it like Panel) with theses methods:

public void update(Graphics g) {
}

public void paintAll(Graphics g) {
  ComponentPeer peer = this.peer; 
  if (visible && (peer != null)) {
    validate();
  if (!(peer instanceof java.awt.peer.LightweightPeer)) {
    peer.paint(g); 
  }
}

public void print(Graphics g) {}

This way paint() never gets called.

By the way it is interesting to see that you can make print() call another method; in this way the printed components can differ visually from the one seen on the screen!

Now let's get back to repaint() that calls update. In fact paint() doesn't get called in the code above but update() does, even if it is empty, by repaint().
You can also see that all other methods in Component call only repaint().

Here is repaint():

/**
 * Repaints this component. 
 *
 * This method causes a call to this component's update
 * method as soon as possible. 
 * @see java.awt.Component#update(java.awt.Graphics)
 * @since JDK1.0 
 */ 
public void repaint() {
  /* getToolkit().getEventQueue().
         removeSourceEvents(this,PaintEvent.PAINT); */ 
  repaint(0, 0, 0, width,
  height);
}

It says that it calls update() but the method is not there!
The getToolkit().getEventQueue().removeSourceEvents(this, PaintEvent.PAINT) removes any pending events for the specified source object (from the EventQueue documentation).

So let' see the other repaint:

/**
 * Repaints the specified rectangle of this component within 
 * tm milliseconds. 
 * 
 * This method causes a call to this component's 
 * update method. 
 * @param tm maximum time in milliseconds before update. 
 * @param x the x coordinate. 
 * @param y the y coordinate. 
 * @param width the width. 
 * @param height the height. 
 * @see java.awt.Component#update(java.awt.Graphics)
 * @since JDK1.0 
 */
public void repaint(long tm, int x, int y, int width, int height) {
  if (this.peer instanceof java.awt.peer.LightweightPeer) {
    // Needs to be translated to parent coordinates since 
    // a parent native container provides the actual repaint 
    // services. Additionally, the request is restricted to 
    // the bounds of the component. 
    int px = this.x + ((x < 0) ? 0 : x); 
    int py = this.y + ((y < 0) ? 0 : y);
    int pwidth = (width > this.width) ? this.width : width; 
    int pheight = (height > this.height) ? this.height : height; 
    parent.repaint(tm, px, py, pwidth, pheight); 
  }
  else { 
    ComponentPeer peer = this.peer; 
    if ((peer != null) && (width > 0) && (height > 0)) {
      peer.repaint(tm, x, y, width, height); 
    }
  }
}

Here you see that it is the peer that calls the update() method; repaint just asks AWT to schedule a call to update(). Anyway, to block repaint do it like is done before with update(), paintAll(), print().

For more information on the AWT methods, how they work and on how to eliminate flickering see the AWT and Swing Tutorials at http://www.javasoft.com/tutorial

Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

About | Sitemap | Contact