Simple drawing and writing

Chapter: Simple drawing and writing

We will now look at some of the basic graphics (drawing and lettering) offered in AWT:

Consider the appropriate widget for drawing: At first, it seems like a Canvas object will be needed. However, you can draw directly on a Frame. Later, when we learn to place a canvas inside a frame, we will draw on canvases instead.

All drawing occurs on a graphics context: A graphics context is an instance of class Graphics. However, you cannot instantiate this class yourself. A component (like Frame) does that for you. Thus, to draw on a Frame, you need to get a Graphics instance from the frame. The way this works is, you get the Graphics instance via the paint() or update() method of Frame.

The all-important technique of overriding paint() (and, sometimes, update()): Now, AWT does not maintain "bit-mapped memory". That is, if a window is covered and later uncovered, AWT does not re-draw the contents. Thus, when re-drawing is needed, you have to do it. AWT tells you when drawing is needed by calling the paint() method. Thus, you need to override the paint() method in Frame to do your thing. (Important): Therefore, you need to extend Frame to override the paint() method. This method is given a Graphics instance as parameter. Confusing? Let's look at a simple example:

// Extend Frame in order to override paint() 
class NewFrame extends Frame {

  // Override paint(): 
  public void paint (Graphics g)
  {
    // drawString() is a Graphics method. 
    // Draw the string "Hello World" at location 100,100 
    g.drawString ("Hello World!", 100, 100);
  }

}

public class TestAwt4 {

  public static void main (String[] argv)
  {
    // Create an instance of NewFrame 
    NewFrame nf = new NewFrame ();

    // Set the title and other parameters. 
    nf.setTitle ("Hello World Test");
    nf.setResizable (true);
    nf.setBackground (Color.cyan);
    nf.setSize (500, 300);

    // Show the frame. 
    nf.setVisible (true);
  }

}

Try it and see the result:

An explanation:

To write or draw in a frame, we need to override the paint() method in Frame.

To override means we replace the default (boring) paint() method inherited from Frame.

Note that paint() is passed a Graphics context.

Only a graphics context has the means for drawing and writing.

Here are some of the methods in Graphics:

All measurements are in pixels: The frame size is 500 x 300. The drawString() method draws the specified string at a location specified from the top-left corner. (The origin is at the topleft corner).

Next, let us draw some geometric figures: We will draw un-filled and filled versions of a square, a circle and a rectangle. All the drawing methods are in Graphics. We will use methods drawRect(), drawOval() and drawRoundRect().

For example, consider the following code:

class NewFrame extends Frame {
    
    // Override paint(): 
    public void paint (Graphics g)
    {
	// Draw a Square: 
	g.drawRect (50,50,50,50);
	g.drawString ("Square", 50, 115);
	
	// Circle: 
	g.drawOval (200,50,50,50);
	g.drawString ("Circle", 200, 115);
	
	// Rounded rectangle: 
	g.drawRoundRect (350,50,75,50,20,20);
	g.drawString ("Rectangle", 350, 115);
	
	// Draw a line across the middle: 
	g.drawLine (0,150,500,150);
	
	// Now draw some filled shapes: 
	
	// Square: 
	g.fillRect (50,200,50,50);
	g.drawString ("Square", 50, 265);
	
	// Circle: 
	g.fillOval (200,200,50,50);
	g.drawString ("Circle", 200, 265);
	
	// Rounded rectangle: 
	g.fillRoundRect (350,200,75,50,20,20);
	g.drawString ("Rectangle", 350, 265);
    }
    
}

public class TestAwt5 {
    
    public static void main (String[] argv)
    {
	// Create an instance of NewFrame 
	NewFrame nf = new NewFrame ();
	
	// Set the title and other parameters. 
	nf.setTitle ("Some Geometric Figures");
	nf.setResizable (true);
	nf.setBackground (Color.cyan);
	nf.setSize (500, 300);
	nf.addWindowListener(new WindowAdapter() {
		public void windowClosing(WindowEvent e) {
		    System.exit(0);
		}
	    });
	
	// Show the frame. 
	nf.setVisible (true);
    }
    
}

Notice that we added a window listener to enable the "go-away" box. We'll explain it all later.

We can improve the code slightly by placing all the frame-related code inside NewFrame itself:

import java.awt.*;
import java.awt.event.*;

class NewFrame extends Frame {
    
    // Constructors. 
    public NewFrame (int width, int height)
    {
	// Set the title and other parameters. 
	setTitle ("Some Geometric Figures");
	setResizable (true);
	setBackground (Color.cyan);
	setSize (width, height);
	addWindowListener(new WindowAdapter() {
		public void windowClosing(WindowEvent e) {
		    System.exit(0);
		}
	    });
	
	// Show the frame. 
	setVisible (true);
    }
    
    // No-parameter constructor - use a default size. 
    public NewFrame ()
    {
	this (500, 300);
    }
    
    // Override paint(): 
    public void paint (Graphics g)
    {
	// Draw a Square: 
	g.drawRect (50,50,50,50);
	g.drawString ("Square", 50, 115);
	
	// Circle: 
	g.drawOval (200,50,50,50);
	g.drawString ("Circle", 200, 115);
	
	// Rounded rectangle: 
	g.drawRoundRect (350,50,75,50,20,20);
	g.drawString ("Rectangle", 350, 115);
	
	// Draw a line across the middle: 
	g.drawLine (0,150,500,150);
	
	// Now draw some filled shapes: 
	
	// Square: 
	g.fillRect (50,200,50,50);
	g.drawString ("Square", 50, 265);
	
	// Circle: 
	g.fillOval (200,200,50,50);
	g.drawString ("Circle", 200, 265);
	
	// Rounded rectangle: 
	g.fillRoundRect (350,200,75,50,20,20);
	g.drawString ("Rectangle", 350, 265);
    }
    
}

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

Note that we used a constructor to set Frame attributes.

A no-parameter constructor creates a default size.


Exercise 2

Add a paint() method in the following template to draw a standard 8x8 chessboard. Let the size of the chessboard be determined by minimum of the two dimensions of the frame. Place the topleft corner of the chessboard at the topleft corner of the frame. Do not be discouraged when your output looks bad!
import java.awt.*;

class NewFrame extends Frame {

  // Constructors.
  public NewFrame (int width, int height) {
    // Set the title and other parameters.
    this.setTitle ("Chessboard");
    this.setResizable (true);
    this.setBackground (Color.cyan);
    this.setSize (width, height);

    // Show the frame.
    this.setVisible (true);
  }

  // No-parameter constructor - use a default size.
  public NewFrame () {
    this (500, 300);
  }

}

public class ChessBoard {

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

}



rhyspj@gwu.edu