Chapter 17. Drawing with the 2D API

In the last few chapters, you’ve caught a glimpse of how graphics operations are performed in Java. This chapter goes into more depth about drawing techniques and the tools for working with images in Java. In the next chapter, we’ll explore image-processing tools in more detail, and we’ll look at the classes that let you generate images, pixel by pixel, on the fly.

The Big Picture

The classes you’ll use for drawing come from six packages: java.awt, java.awt.color, java.awt.font, java.awt.geom, java.awt.image, and java.awt.print. Collectively, these classes make up most of the 2D API, a comprehensive API for drawing shapes, text, and images. Figure 17.1 shows a bird’s-eye view of these classes. There’s much more in the 2D API than we can cover in two chapters. For a full treatment, see Jonathan Knudsen’s Java 2D Graphics (O’Reilly & Associates).

Graphics classes of the 2D API

Figure 17-1. Graphics classes of the 2D API

An instance of java.awt.Graphics2D is called a graphics context. It represents a drawing surface such as a component’s display area, a page on a printer, or an offscreen image buffer. A graphics context provides methods for drawing three kinds of graphics objects: shapes, text, and images. Graphics2D is called a graphics context because it also holds contextual information about the drawing area. This information includes the drawing area’s clipping region, painting color, transfer mode, text font, and geometric transformation. If you consider the drawing area to be a painter’s canvas, you might think of a graphics context as an easel that holds a set of tools and marks off the work area.

There are four ways you normally acquire a Graphics2D object. Roughly, from most common to least, they are as follows:

  • From AWT or Swing, as the result of a painting request on a component. In this case, a new graphics context for the appropriate area is acquired and passed to your component’s paint( ) or update( ) method. (The update( ) method really applies only to AWT components, not the newer Swing components.)

  • Directly from an offscreen image buffer. In this case, we ask the image buffer for a graphics context directly. We’ll use this when we discuss techniques like double buffering.

  • By copying an existing Graphics2D object. Duplicating a graphics object can be useful for more elaborate drawing operations; different copies of a Graphics2D object can draw on same area, but with different attributes and clipping regions. A Graphics2D can be copied by calling the create( ) method.

  • Directly from an onscreen component. It’s possible to ask a component to give you a Graphics2D object for its display area. However, this is almost always a mistake; if you feel tempted to do this, think about why you’re trying to circumvent the normal paint( ) /repaint( ) mechanism.

Each time a component’s paint( ) method is called, the windowing system provides the component with a new Graphics2D object for drawing in the display area. This means that attributes we set during one painting session, such as the drawing color or clipping region, are reset the next time paint( )is called. (Each call to paint( ) starts with a tidy new easel.) For the most common attributes, like foreground color, background color, and font, we can set defaults in the component itself. Thereafter, the graphics contexts for painting in that component come with those properties initialized appropriately.

If we are working in an AWT component’s update( ) method, we can assume our onscreen artwork is still intact, and we need to make only whatever changes are needed to bring the display up to date. One way to optimize drawing operations in this case is by setting a clipping region, as we’ll see shortly. If our paint( ) method is called, however, we have to assume the worst and redraw the entire display.

For backwards compatibility, a graphics context is always passed to the paint( ) method as a Graphics object. If you want to take advantage of the nifty features in the 2D API (as you almost undoubtedly will), you will need to cast this reference to a Graphics2D. You’ll see how this works in the upcoming examples.

Get Learning Java now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.