Java Examples In A Nutshell (3rd Edition) [Electronic resources]

O'Reilly Media, Inc

نسخه متنی -صفحه : 285/ 142
نمايش فراداده

12.14 Custom Paint

Figure 12-8 showed a variety of shape-filling techniques; it included a large letter A filled with a complex pattern defined by the GenericPaint class. Example 12-18 shows the implementation of this class. You may want to take another look at Example 12-10 to see how the GenericPaint class is used, before you dive into the code listed here.

The GenericPaint class itself is pretty simple: it defines both the abstract color computation methods that subclasses implement and a createContext( ) method that returns a PaintContext. The implementation of PaintContext does all the hard work. This is pretty low-level stuff, so don't be dismayed if you don't understand everything. The code should at least give you a basic idea of how painting works in Java 2D.

Example 12-18. GenericPaint.java
package je3.graphics;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
/**
* This is an abstract Paint implementation that computes
 the color of each
* point to be painted by passing the coordinates of the
 point to the calling
* abstract methods computeRed( ), computeGreen( ),
 computeBlue( ) and
* computeAlpha( ).  Subclasses must implement these
 three methods to perform
* whatever type of painting is desired.  
Note that while this class provides
* great flexibility, it is not very efficient.
**/
public abstract class GenericPaint implements Paint {
/** This is the main Paint method;
  all it does is return a PaintContext */
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
RenderingHints hints) {
return new GenericPaintContext(xform);
}
/** This paint class allows translucent painting */
public int getTransparency( ) { return TRANSLUCENT; }
/**
* These three methods return the red, green, blue, and alpha values of
* the pixel that appears at the specified user-space coordinates. 
 The return
* value of each method should be between 0 and 255.
**/
public abstract int computeRed(double x, double y);
public abstract int computeGreen(double x, double y);
public abstract int computeBlue(double x, double y);
public abstract int computeAlpha(double x, double y);
/**
* The PaintContext class does all the work of painting
**/
class GenericPaintContext implements PaintContext {
ColorModel model;  // The color model
Point2D origin, unitVectorX, unitVectorY;  // For device-to-user xform
public GenericPaintContext(AffineTransform userToDevice) {
// Our color model packs RGB values into a single int
model = new DirectColorModel(32, 0x00ff0000,0x0000ff00,
0x000000ff, 0xff000000);
// The specified transform converts user to device pixels
// We need to figure out the reverse transformation, so we
// can compute the user space coordinates of each device pixel
try {
AffineTransform deviceToUser = userToDevice.createInverse( );
origin = deviceToUser.transform(new Point(0,0), null);
unitVectorX = deviceToUser.deltaTransform(new Point(1,0),null);
unitVectorY = deviceToUser.deltaTransform(new Point(0,1),null);
}
catch (NoninvertibleTransformException e) {
// If we can't invert the transform, just use device space
origin = new Point(0,0);
unitVectorX = new Point(1,0);
unitVectorY = new Point(0, 1);
}
}
/** Return the color model used by this Paint implementation */
public ColorModel getColorModel( ) { return model; }
/**
* This is the main method of PaintContext.  It must return a Raster
* that contains fill data for the specified rectangle.  It creates a
* raster of the specified size, and loops through the device pixels.
* For each one, it converts the coordinates to user space, then calls
* the computeRed( ), computeGreen( ) and computeBlue( ) methods to
* obtain the appropriate color for the device pixel.
**/
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster raster = model.createCompatibleWritableRaster(w,h);
int[  ] colorComponents = new int[4];
for(int j = 0; j < h; j++) {      // Loop through rows of raster
int deviceY = y + j; 
for(int i = 0; i < w; i++) {  // Loop through columns
int deviceX = x + i;
// Convert device coordinate to user-space coordinate
double userX = origin.getX( ) + 
deviceX * unitVectorX.getX( ) + 
deviceY * unitVectorY.getX( );
double userY = origin.getY( ) + 
deviceX * unitVectorX.getY( ) + 
deviceY * unitVectorY.getY( );
// Compute the color components of the pixel
colorComponents[0] = computeRed(userX, userY);
colorComponents[1] = computeGreen(userX, userY);
colorComponents[2] = computeBlue(userX, userY);
colorComponents[3] = computeAlpha(userX, userY);
// Set the color of the pixel
raster.setPixel(i, j, colorComponents);
}
}
return raster;
}
/** Called when the PaintContext is no longer needed. */
public void dispose( ) {  }
}
}