Java Reference
In-Depth Information
import java.awt.image.BufferedImage;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
You could have implemented two separate helper methods for setting up the
CUSTOM16
and
CUSTOM24
icons, but there's quite a lot of common code so I made it one method. The first step is to obtain the
BufferedImage
object that the
icon
argument contains. The
getImage()
method returns a reference of type
Image
, so you need to cast it to the proper type. The
getWidth()
method for
image
returns the width of the
image, which in this particular case is the same as the height. There's a
getHeight()
method for when they
differ. You want to draw a filled rectangle indented from the boundaries of the image, but the indents need
to be different for the 16 ×16 and 24 ×24 images so that the menu item and toolbar button appear similar to
the others in the same set.
The
createGraphics()
method returns a
Graphics2D
object that you can use to draw on the image. In
both cases you draw a filled rectangle in the color specified by the second argument. The differences for the
two sizes of image are the dimensions of the rectangle and the position of its top-left corner.
For a 24 ×24 image that is used on a toolbar button, you draw a capital
'C'
for “Custom" centrally on
the image to distinguish the custom color toolbar button from those that are used to set the standard colors.
To determine the position for the text on the image, you create a
java.awt.font.TextLayout
object that
provides information about styled text. In this case the text is just a single character
"C"
that you pass to the
TextLayout
constructor. The second argument is the font used to draw the text and the third argument is a
FontRenderContext
object that encapsulates the context in which the text is rendered, and you obtain both
by calling methods for
g2D
. The
TextLayout
object needs all this information to determine the layout of the
text. The
getBounds()
method for
textLayout
returns a rectangle that encloses the text. You use the height
and width of this rectangle in conjunction with the width of the filled rectangle to determine the position
where the text is to be drawn. Finally the
drawString()
method draws
"C"
on the image.
Note how the color for drawing the text is set. If you were to use a fixed color, the user might choose
the same color as a custom color, in which case the text would be invisible. To contrast the text with the
background, you subtract the RGB values for the filled rectangle color from 255 and use these to create a
new
Color
object for the text. The only instance in which this won't produce a contrasting color is if the
RGB component values are all 128, but this color is an unlikely shade of mid-gray anyway. If you want to
take care of this, you could check for these RGB values, and use
Color.BLACK
for the text in this case.
Displaying the Color Chooser Dialog
Add a field to
SketcherFrame
to hold the current custom color:
private Color customColor = DEFAULT_ELEMENT_COLOR;
// Current custom color
It is initialized with the default color at the outset. This needs to be a field that is independent of
elementCo-
lor
because you want to remember the last custom color that was chosen, even when the element color is
changed to one of the standard colors.
Events from the custom color menu items and toolbar button are handled by the
actionPerformed()
member of the
ColorAction
class.