The methods paint(), repaint() and update()

Chapter: The methods paint(), repaint() and update()

The class Component defines methods called paint(), repaint() and update().

The way these methods interact can sometimes create strange results.

First, consider what the methods are intended for:

Here's an example of a weird effect:

The code below responds to mouse-clicks and draws line segments. After each mouse click, repaint() is called. (A mistake). The code:

import java.awt.*;
import java.awt.event.*;
class NewFrame extends Frame 
    implements ActionListener, MouseListener {
    
    // Constructor. 
    public NewFrame (int width, int height)
    {
	// Set the title and other frame parameters. 
	this.setTitle ("Paint and Update");
	this.setResizable (true);
	this.setBackground (Color.cyan);
	this.setSize (width, height);
	
	// Create a quit button. 
	Button b = new Button ("Quit");
	b.setBackground (Color.red);
	b.setFont (new Font ("Serif", Font.PLAIN | Font.BOLD, 15));
	b.addActionListener (this);
	// this.setLayout (new BorderLayout()); 
	this.add (b, BorderLayout.SOUTH);
	
	// Add mouse-listening to the frame itself. 
	this.addMouseListener (this);
	
	// Show the frame. 
	this.setVisible (true);
    }
    
    public void actionPerformed (ActionEvent a)
    {
	System.exit (0); // Quit button pressed. 
    }
    
    int current_x=0, current_y=0;
    int new_x, new_y;
    
    // These methods are required to implement  
  // the MouseListener interface. 
    public void mouseClicked (MouseEvent m)
    {
	new_x = m.getX();
	new_y = m.getY();
	
	// Call repaint to reflect new line. 
	repaint();
    }
    
    public void mouseEntered (MouseEvent m) {}
    public void mouseExited (MouseEvent m) {}
    public void mousePressed (MouseEvent m) {}
    public void mouseReleased (MouseEvent m) {}
    
    public void paint (Graphics g)
    {
	System.out.println ("Paint: cx=" + current_x + ",cy=" + current_y
			    + ", nx=" + new_x + ",ny=" + new_y);
	g.drawLine (current_x, current_y, new_x, new_y);
	current_x = new_x;
	current_y = new_y;
    }
    
} // End of class "NewFrame" 

public class TestAwt25 {
    
    public static void main (String[] argv)
    {
	NewFrame nf = new NewFrame (300, 200);
    }
    
}

The call to repaint ends up calling update.

But update clears the screen before calling paint().

Thus, only the most recent line segment will be visible. This problem can be fixed by calling paint instead of repaint:

  public void mouseClicked (MouseEvent m)
  {
    new_x = m.getX();
    new_y = m.getY();

    // Instead of calling repaint(), 
    // call paint() directly, with the 
    // correct graphics context. 
    Graphics g = this.getGraphics();
    paint (g); 
  }

Note that a Graphics instance needs to be passed to paint.

The getGraphics() is used to retrieve the instance.

Now the problem is eliminated.

However, this code still has a problem: every time the frame is re-sized, the background is cleared (overwritten).

This is because update is called and update clears the background. To solve the above problem, we simply override update() and make sure the background is not cleared:

  // Override update() and make sure the 
  // background is not cleared. 
  public void update (Graphics g)
  {
    paint (g);
  }

Since repaint() calls update() and we have made update "safe", we can now go back to calling repaint() in mouseClicked().

Generally, many programs that perform animations will want to avoid flicker by redefining update as above.


rhyspj@gwu.edu