epubjs
Version:
Render ePub documents in the browser, across many devices
237 lines (221 loc) • 42 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>A Quick Tour of Java 2D</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="A Quick Tour of Java 2D"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-20-SECT-3"/>A Quick Tour of Java 2D</h1></div></div></div><p>Next we’ll embark on a quick tour of Java 2D, including working with
shapes and text. We’ll finish with an example of Java 2D in action.</p><div class="sect2" title="Filling Shapes"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-3.1"/>Filling Shapes</h2></div></div></div><p><a id="I_indexterm20_id809957" class="indexterm"/> <a id="I_indexterm20_id809968" class="indexterm"/>The simplest path through the rendering pipeline is
filling shapes. For example, the following code creates an ellipse and
fills it with a solid color. (This code would live inside a <code class="literal">paint()</code> method somewhere. We’ll present a
complete, ready-to-run example a little later.)</p><a id="I_20_tt1136"/><pre class="programlisting"> <code class="n">Shape</code> <code class="n">c</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Ellipse2D</code><code class="o">.</code><code class="na">Float</code><code class="o">(</code><code class="mi">50</code><code class="o">,</code> <code class="mi">25</code><code class="o">,</code> <code class="mi">150</code><code class="o">,</code> <code class="mi">150</code><code class="o">);</code> <code class="c1">// x,y,width,height</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">blue</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">fill</code><code class="o">(</code><code class="n">c</code><code class="o">);</code></pre><p>Here, <code class="literal">g2</code> is our <code class="literal">Graphics2D</code> object. The <code class="literal">Ellipse2D</code> shape class is abstract, but is
implemented by concrete inner subclasses called <code class="literal">Float</code> and <code class="literal">Double</code> that work with float or double
precision, respectively. The <code class="literal">Rectangle2D</code> class, similarly, has concrete
subclasses <code class="literal">Rectangle2D.Float</code> and
<code class="literal">Rectangle2D.Double</code>.</p><p>In the call to <a id="I_indexterm20_id810045" class="indexterm"/><code class="literal">setPaint()</code>, we tell
<code class="literal">Graphics2D</code> to use a solid color,
blue, for all subsequent filling operations. Next, the call to
<a id="I_indexterm20_id810062" class="indexterm"/><code class="literal">fill()</code> tells <code class="literal">Graphics2D</code> to fill the given shape.</p><p>All geometric shapes in the 2D API are represented by
implementations of the <code class="literal">java.awt.geom.Shape</code> interface. This interface
defines methods that are common to all shapes, like returning a
rectangle bounding box or testing if a point is inside the shape. The
<code class="literal">java.awt.geom</code> package is a
smorgasbord of useful shape classes, including <code class="literal">Rectangle2D</code>, <code class="literal">RoundRectangle2D</code> (a rectangle with rounded
corners), <code class="literal">Arc2D</code>, <code class="literal">Ellipse2D</code>, and others. In addition, a few more
basic classes in <a id="I_indexterm20_id810116" class="indexterm"/><code class="literal">java.awt</code> are <code class="literal">Shape</code>s: <a id="I_indexterm20_id810132" class="indexterm"/><code class="literal">Rectangle</code>, <a id="I_indexterm20_id810142" class="indexterm"/><code class="literal">Polygon</code>, and <a id="I_indexterm20_id810153" class="indexterm"/><code class="literal">Area</code>.</p></div><div class="sect2" title="Drawing Shape Outlines"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-3.2"/>Drawing Shape Outlines</h2></div></div></div><p><a id="I_indexterm20_id810170" class="indexterm"/> <a id="I_indexterm20_id810181" class="indexterm"/> <a id="I_indexterm20_id810189" class="indexterm"/>Drawing a shape’s outline is only a little bit more
complicated. Consider the following example:</p><a id="I_20_tt1137"/><pre class="programlisting"> <code class="n">Shape</code> <code class="n">r</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Rectangle2D</code><code class="o">.</code><code class="na">Float</code><code class="o">(</code><code class="mi">100</code><code class="o">,</code> <code class="mi">75</code><code class="o">,</code> <code class="mi">100</code><code class="o">,</code> <code class="mi">100</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setStroke</code><code class="o">(</code><code class="k">new</code> <code class="n">BasicStroke</code><code class="o">(</code><code class="mi">4</code><code class="o">));</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">yellow</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">draw</code><code class="o">(</code><code class="n">r</code><code class="o">);</code></pre><p>Here, we tell <code class="literal">Graphics2D</code> to use
a stroke that is four units wide and a solid color, yellow, for filling
the stroke. When we call <a id="I_indexterm20_id810220" class="indexterm"/><code class="literal">draw()</code>, <code class="literal">Graphics2D</code> uses the stroke to create a new
shape, the outline, from the given rectangle. The outline shape is then
filled just as before; this effectively draws the rectangle’s outline.
The rectangle itself is not filled.</p></div><div class="sect2" title="Convenience Methods"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-3.3"/>Convenience Methods</h2></div></div></div><p><a id="idx11084" class="indexterm"/> <code class="literal">Graphics2D</code> includes
quite a few convenience methods for drawing and filling common shapes;
these methods are actually inherited from the <code class="literal">Graphics</code> class. <a class="xref" href="ch20s03.html#learnjava3-CHP-20-TABLE-1" title="Table 20-1. Shape-drawing methods in the graphics class">Table 20-1</a> summarizes these methods. It’s a
little easier to call <a id="I_indexterm20_id810277" class="indexterm"/><code class="literal">fillRect()</code> rather than
instantiating a rectangle shape and passing it to <a id="I_indexterm20_id810288" class="indexterm"/><code class="literal">fill()</code>.</p><div class="table"><a id="learnjava3-CHP-20-TABLE-1"/><p class="title">Table 20-1. Shape-drawing methods in the graphics class</p><div class="table-contents"><table summary="Shape-drawing methods in the graphics class" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col/><col/></colgroup><thead><tr><th style="text-align: left"><p>Method</p></th><th style="text-align: left"><p>Description</p></th></tr></thead><tbody><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810344" class="indexterm"/> <a id="I_indexterm20_id810350" class="indexterm"/> <code class="literal">draw3DRect()</code>
</p></td><td style="text-align: left"><p>Draws a highlighted, 3D
rectangle</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810374" class="indexterm"/> <code class="literal">drawArc()</code>
</p></td><td style="text-align: left"><p>Draws an arc</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810397" class="indexterm"/> <code class="literal">drawLine()</code>
</p></td><td style="text-align: left"><p>Draws a line</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810420" class="indexterm"/> <code class="literal">drawOval()</code>
</p></td><td style="text-align: left"><p>Draws an oval</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810443" class="indexterm"/> <code class="literal">drawPolygon()</code>
</p></td><td style="text-align: left"><p>Draws a polygon, closing it by
connecting the endpoints</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810467" class="indexterm"/> <code class="literal">drawPolyline()</code>
</p></td><td style="text-align: left"><p>Draws a line connecting a series of
points, without closing it</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810491" class="indexterm"/> <code class="literal">drawRect()</code>
</p></td><td style="text-align: left"><p>Draws a rectangle</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810515" class="indexterm"/> <code class="literal">drawRoundRect()</code> </p></td><td style="text-align: left"><p>Draws a rounded-corner
rectangle</p></td></tr><tr><td style="text-align: left"><p> <code class="literal">fill3DRect()</code> </p></td><td style="text-align: left"><p>Draws a filled, highlighted, 3D
rectangle</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810556" class="indexterm"/> <code class="literal">fillArc()</code>
</p></td><td style="text-align: left"><p>Draws a filled arc</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810579" class="indexterm"/> <code class="literal">fillOval()</code>
</p></td><td style="text-align: left"><p>Draws a filled oval</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810603" class="indexterm"/> <code class="literal">fillPolygon()</code>
</p></td><td style="text-align: left"><p>Draws a filled polygon</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810626" class="indexterm"/> <code class="literal">fillRect()</code>
</p></td><td style="text-align: left"><p>Draws a filled
rectangle</p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm20_id810650" class="indexterm"/> <code class="literal">FillRoundRect()</code> </p></td><td style="text-align: left"><p>Draws a filled, rounded-corner
rectangle</p></td></tr></tbody></table></div></div><p>As you can see, for each of the <code class="literal">fill()</code> methods in the table, there is a
corresponding <code class="literal">draw()</code> method that
renders the shape as an unfilled line drawing. With the exception of
<code class="literal">fillArc()</code> and <code class="literal">fillPolygon()</code>, each method takes a simple
<code class="literal">x</code>, <code class="literal">y</code> specification for the top-left corner of the
shape and a <code class="literal">width</code> and <code class="literal">height</code> for its size.</p><p>The most flexible convenience method draws a polygon, which is
specified by two arrays that contain the <code class="literal">x</code> and <code class="literal">y</code>
coordinates of the vertices. Methods in the <code class="literal">Graphics</code> class take two such arrays and draw
the polygon’s outline or fill the polygon.</p><p>The methods listed in <a class="xref" href="ch20s03.html#learnjava3-CHP-20-TABLE-1" title="Table 20-1. Shape-drawing methods in the graphics class">Table 20-1</a>
are shortcuts for more general methods in <code class="literal">Graphics2D</code>. The more general procedure is to
first create a <code class="literal">java.awt.geom.Shape</code>
object and then pass it to the <code class="literal">draw()</code>
or <code class="literal">fill()</code> method of <code class="literal">Graphics2D</code>. For example, you could create a
<code class="literal">Polygon</code> object from coordinate
arrays. Since a <code class="literal">Polygon</code> implements
the <code class="literal">Shape</code> interface, you can pass it
to <code class="literal">Graphics2D</code>’s general <code class="literal">draw()</code> or <code class="literal">fill()</code> method.</p><p>The <code class="literal">fillArc()</code> method requires
six integer arguments. The first four specify the bounding box for an
oval—just like the <code class="literal">fillOval()</code> method.
The final two arguments specify what portion of the oval we want to
draw, as a starting angular position and an offset, both of which are
specified in degrees. The zero-degree mark is at three o’clock; a
positive angle is clockwise. For example, to draw the right half of a
circle, you might call:</p><a id="I_20_tt1138"/><pre class="programlisting"> <code class="n">g</code><code class="o">.</code><code class="na">fillArc</code><code class="o">(</code><code class="mi">0</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="n">radius</code> <code class="o">*</code> <code class="mi">2</code><code class="o">,</code> <code class="n">radius</code> <code class="o">*</code> <code class="mi">2</code><code class="o">,</code> <code class="o">-</code><code class="mi">90</code><code class="o">,</code> <code class="mi">180</code><code class="o">);</code></pre><p><code class="literal">draw3DRect()</code> automatically
chooses shading colors by “darkening” the current color. So you should
set the color to something other than black, which is the default (maybe
gray or white); if you don’t, you’ll just get a black rectangle with a
thick outline.<a id="I_indexterm20_id810843" class="indexterm"/></p></div><div class="sect2" title="Drawing Text"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-3.4"/>Drawing Text</h2></div></div></div><p><a id="I_indexterm20_id810856" class="indexterm"/> <a id="I_indexterm20_id810865" class="indexterm"/>Like drawing a shape’s outline, drawing text is just a
simple variation on filling a shape. When you ask <code class="literal">Graphics2D</code> to draw text, it determines the
shapes that need to be drawn and fills them. The shapes that represent
characters are called <a id="I_indexterm20_id810882" class="indexterm"/><span class="emphasis"><em>glyphs</em></span>. A font is a collection of
glyphs. Here’s an example of drawing text:</p><a id="I_20_tt1139"/><pre class="programlisting"> <code class="n">g2</code><code class="o">.</code><code class="na">setFont</code><code class="o">(</code><code class="k">new</code> <code class="n">Font</code><code class="o">(</code><code class="s">"Times New Roman"</code><code class="o">,</code> <code class="n">Font</code><code class="o">.</code><code class="na">PLAIN</code><code class="o">,</code> <code class="mi">64</code><code class="o">));</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">red</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">drawString</code><code class="o">(</code><code class="s">"Hello, 2D!"</code><code class="o">,</code> <code class="mi">50</code><code class="o">,</code> <code class="mi">150</code><code class="o">);</code></pre><p>When we call <code class="literal">drawString()</code>,
<code class="literal">Graphics2D</code> uses the current font to
retrieve the glyphs that correspond to the characters in the string.
Then the glyphs (which are really just <code class="literal">Shape</code>s) are filled using the current <code class="literal">Paint</code>.</p></div><div class="sect2" title="Drawing Images"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-3.5"/>Drawing Images</h2></div></div></div><p><a id="idx11090" class="indexterm"/> <a id="idx11101" class="indexterm"/>Images are treated a little differently than shapes. In
particular, the current <code class="literal">Paint</code> is not
used to render an image because the image contains its own color
information for each pixel (it <span class="emphasis"><em>is</em></span> the paint,
effectively). The following example loads an image from a file and
displays it:</p><a id="I_20_tt1140"/><pre class="programlisting"> <code class="n">Image</code> <code class="n">i</code> <code class="o">=</code> <code class="n">Toolkit</code><code class="o">.</code><code class="na">getDefaultToolkit</code><code class="o">().</code><code class="na">getImage</code><code class="o">(</code><code class="s">"camel.gif"</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">drawImage</code><code class="o">(</code><code class="n">i</code><code class="o">,</code> <code class="mi">75</code><code class="o">,</code> <code class="mi">50</code><code class="o">,</code> <code class="k">this</code><code class="o">);</code></pre><p>In this case, the call to <code class="literal">drawImage()</code> tells <code class="literal">Graphics2D</code> to place the image at the given
location. We’ll explain the fourth argument, which is used for
monitoring image loading later.</p><div class="sect3" title="Transformations and rendering"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-20-SECT-3.5.1"/>Transformations and rendering</h3></div></div></div><p><a id="idx11092" class="indexterm"/> <a id="idx11102" class="indexterm"/> <a id="idx11104" class="indexterm"/> <a id="idx11108" class="indexterm"/>Four parts of the pipeline affect every graphics
operation. In particular, all rendering is subject to being
transformed, composited, and clipped. Rendering hints are used to
affect all of <code class="literal">Graphics2D</code>’s
rendering.</p><p>This example shows how to modify the current transformation with
a translation and a rotation:</p><a id="I_20_tt1141"/><pre class="programlisting"> <code class="n">g2</code><code class="o">.</code><code class="na">translate</code><code class="o">(</code><code class="mi">50</code><code class="o">,</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">rotate</code><code class="o">(</code><code class="n">Math</code><code class="o">.</code><code class="na">PI</code> <code class="o">/</code> <code class="mi">6</code><code class="o">);</code></pre><p>Every graphics primitive drawn by <code class="literal">g2</code> will now have this transformation applied
to it (a shift of 50 units right and a rotation of 30 degrees
clockwise). We can have a similarly global effect on
compositing:</p><a id="I_20_tt1142"/><pre class="programlisting"> <code class="n">AlphaComposite</code> <code class="n">ac</code> <code class="o">=</code> <code class="n">AlphaComposite</code><code class="o">.</code><code class="na">getInstance</code><code class="o">(</code>
<code class="n">AlphaComposite</code><code class="o">.</code><code class="na">SRC_OVER</code><code class="o">,</code> <code class="o">(</code><code class="kt">float</code><code class="o">).</code><code class="mi">5</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setComposite</code><code class="o">(</code><code class="n">ac</code><code class="o">);</code></pre><p>Now, every graphics primitive we draw will be half transparent;
we’ll explain more about this later.</p><p>All drawing operations are clipped by the current clipping
shape, which is any object implementing the <a id="I_indexterm20_id811098" class="indexterm"/><code class="literal">Shape</code> interface. In
the following example, the clipping shape is set to an ellipse:</p><a id="I_20_tt1143"/><pre class="programlisting"> <code class="n">Shape</code> <code class="n">e</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Ellipse2D</code><code class="o">.</code><code class="na">Float</code><code class="o">(</code><code class="mi">50</code><code class="o">,</code> <code class="mi">25</code><code class="o">,</code> <code class="mi">250</code><code class="o">,</code> <code class="mi">150</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">clip</code><code class="o">(</code><code class="n">e</code><code class="o">);</code></pre><p>You can obtain the current clipping shape using <a id="I_indexterm20_id811121" class="indexterm"/><code class="literal">getClip()</code>; this is
handy if you want to restore it later using the <a id="I_indexterm20_id811132" class="indexterm"/><code class="literal">setClip()</code>
method.</p><p>Finally, the rendering hints influence all drawing operations.
In the following example, we tell <code class="literal">Graphics2D</code> to use anti-aliasing, a technique
that smoothes out the rough pixel edges of shapes and text:</p><a id="I_20_tt1144"/><pre class="programlisting"> <code class="n">g2</code><code class="o">.</code><code class="na">setRenderingHint</code><code class="o">(</code><code class="n">RenderingHints</code><code class="o">.</code><code class="na">KEY_ANTIALIASING</code><code class="o">,</code>
<code class="n">RenderingHints</code><code class="o">.</code><code class="na">VALUE_ANTIALIAS_ON</code><code class="o">);</code></pre><p>The <a id="I_indexterm20_id811164" class="indexterm"/><code class="literal">RenderingHints</code> class
contains other keys and values that represent other rendering hints.
If you really like to fiddle with knobs and dials, this is a good
class to check out.<a id="I_indexterm20_id811176" class="indexterm"/><a id="I_indexterm20_id811183" class="indexterm"/><a id="I_indexterm20_id811190" class="indexterm"/><a id="I_indexterm20_id811197" class="indexterm"/><a id="I_indexterm20_id811204" class="indexterm"/><a id="I_indexterm20_id811211" class="indexterm"/></p></div></div><div class="sect2" title="The Whole Iguana"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-3.6"/>The Whole Iguana</h2></div></div></div><p>Let’s put everything together now, just to show how graphics
primitives travel through the rendering pipeline. The following example
demonstrates the use of <code class="literal">Graphics2D</code>
from the beginning to the end of the rendering pipeline. With very few
lines of code, we are able to draw some pretty complicated stuff (see
<a class="xref" href="ch20s03.html#learnjava3-CHP-20-FIG-2" title="Figure 20-2. Exercising the 2D API">Figure 20-2</a>).</p><p>Here’s the code:</p><a id="I_20_tt1145"/><pre class="programlisting"> <code class="c1">//file: Iguana.java</code>
<code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.awt.event.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.awt.geom.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">Iguana</code> <code class="kd">extends</code> <code class="n">JComponent</code> <code class="o">{</code>
<code class="kd">private</code> <code class="n">Image</code> <code class="n">image</code><code class="o">;</code>
<code class="kd">private</code> <code class="kt">int</code> <code class="n">theta</code><code class="o">;</code>
<code class="kd">public</code> <code class="nf">Iguana</code><code class="o">()</code> <code class="o">{</code>
<code class="n">image</code> <code class="o">=</code> <code class="n">Toolkit</code><code class="o">.</code><code class="na">getDefaultToolkit</code><code class="o">().</code><code class="na">getImage</code><code class="o">(</code>
<code class="s">"Piazza di Spagna.small.jpg"</code><code class="o">);</code>
<code class="n">theta</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code>
<code class="n">addMouseListener</code><code class="o">(</code><code class="k">new</code> <code class="n">MouseAdapter</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">mousePressed</code><code class="o">(</code><code class="n">MouseEvent</code> <code class="n">me</code><code class="o">)</code> <code class="o">{</code>
<code class="n">theta</code> <code class="o">=</code> <code class="o">(</code><code class="n">theta</code> <code class="o">+</code> <code class="mi">15</code><code class="o">)</code> <code class="o">%</code> <code class="mi">360</code><code class="o">;</code>
<code class="n">repaint</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">});</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">paint</code><code class="o">(</code><code class="n">Graphics</code> <code class="n">g</code><code class="o">)</code> <code class="o">{</code>
<code class="n">Graphics2D</code> <code class="n">g2</code> <code class="o">=</code> <code class="o">(</code><code class="n">Graphics2D</code><code class="o">)</code><code class="n">g</code><code class="o">;</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setRenderingHint</code><code class="o">(</code><code class="n">RenderingHints</code><code class="o">.</code><code class="na">KEY_ANTIALIASING</code><code class="o">,</code>
<code class="n">RenderingHints</code><code class="o">.</code><code class="na">VALUE_ANTIALIAS_ON</code><code class="o">);</code>
<code class="kt">int</code> <code class="n">cx</code> <code class="o">=</code> <code class="n">getSize</code><code class="o">().</code><code class="na">width</code> <code class="o">/</code> <code class="mi">2</code><code class="o">;</code>
<code class="kt">int</code> <code class="n">cy</code> <code class="o">=</code> <code class="n">getSize</code><code class="o">().</code><code class="na">height</code> <code class="o">/</code> <code class="mi">2</code><code class="o">;</code>
<code class="n">g2</code><code class="o">.</code><code class="na">translate</code><code class="o">(</code><code class="n">cx</code><code class="o">,</code> <code class="n">cy</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">rotate</code><code class="o">(</code><code class="n">theta</code> <code class="o">*</code> <code class="n">Math</code><code class="o">.</code><code class="na">PI</code> <code class="o">/</code> <code class="mi">180</code><code class="o">);</code>
<code class="n">Shape</code> <code class="n">oldClip</code> <code class="o">=</code> <code class="n">g2</code><code class="o">.</code><code class="na">getClip</code><code class="o">();</code>
<code class="n">Shape</code> <code class="n">e</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Ellipse2D</code><code class="o">.</code><code class="na">Float</code><code class="o">(-</code><code class="n">cx</code><code class="o">,</code> <code class="o">-</code><code class="n">cy</code><code class="o">,</code> <code class="n">cx</code> <code class="o">*</code> <code class="mi">2</code><code class="o">,</code> <code class="n">cy</code> <code class="o">*</code> <code class="mi">2</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">clip</code><code class="o">(</code><code class="n">e</code><code class="o">);</code>
<code class="n">Shape</code> <code class="n">c</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Ellipse2D</code><code class="o">.</code><code class="na">Float</code><code class="o">(-</code><code class="n">cx</code><code class="o">,</code> <code class="o">-</code><code class="n">cy</code><code class="o">,</code> <code class="n">cx</code> <code class="o">*</code> <code class="mi">3</code> <code class="o">/</code> <code class="mi">4</code><code class="o">,</code> <code class="n">cy</code> <code class="o">*</code> <code class="mi">2</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="k">new</code> <code class="n">GradientPaint</code><code class="o">(</code><code class="mi">40</code><code class="o">,</code> <code class="mi">40</code><code class="o">,</code> <code class="n">Color</code><code class="o">.</code><code class="na">blue</code><code class="o">,</code>
<code class="mi">60</code><code class="o">,</code> <code class="mi">50</code><code class="o">,</code> <code class="n">Color</code><code class="o">.</code><code class="na">white</code><code class="o">,</code> <code class="kc">true</code><code class="o">));</code>
<code class="n">g2</code><code class="o">.</code><code class="na">fill</code><code class="o">(</code><code class="n">c</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">yellow</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">fillOval</code><code class="o">(</code><code class="n">cx</code> <code class="o">/</code> <code class="mi">4</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="n">cx</code><code class="o">,</code> <code class="n">cy</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setClip</code><code class="o">(</code><code class="n">oldClip</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setFont</code><code class="o">(</code><code class="k">new</code> <code class="n">Font</code><code class="o">(</code><code class="s">"Times New Roman"</code><code class="o">,</code> <code class="n">Font</code><code class="o">.</code><code class="na">PLAIN</code><code class="o">,</code> <code class="mi">64</code><code class="o">));</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="k">new</code> <code class="n">GradientPaint</code><code class="o">(-</code><code class="n">cx</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="n">Color</code><code class="o">.</code><code class="na">red</code><code class="o">,</code>
<code class="n">cx</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="n">Color</code><code class="o">.</code><code class="na">black</code><code class="o">,</code> <code class="kc">false</code><code class="o">));</code>
<code class="n">g2</code><code class="o">.</code><code class="na">drawString</code><code class="o">(</code><code class="s">"Hello, 2D!"</code><code class="o">,</code> <code class="o">-</code><code class="n">cx</code> <code class="o">*</code> <code class="mi">3</code> <code class="o">/</code> <code class="mi">4</code><code class="o">,</code> <code class="n">cy</code> <code class="o">/</code> <code class="mi">4</code><code class="o">);</code>
<code class="n">AlphaComposite</code> <code class="n">ac</code> <code class="o">=</code> <code class="n">AlphaComposite</code><code class="o">.</code><code class="na">getInstance</code><code class="o">(</code>
<code class="n">AlphaComposite</code><code class="o">.</code><code class="na">SRC_OVER</code><code class="o">,</code> <code class="o">(</code><code class="kt">float</code><code class="o">).</code><code class="mi">75</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setComposite</code><code class="o">(</code><code class="n">ac</code><code class="o">);</code>
<code class="n">Shape</code> <code class="n">r</code> <code class="o">=</code> <code class="k">new</code> <code class="n">RoundRectangle2D</code><code class="o">.</code><code class="na">Float</code><code class="o">(</code><code class="mi">0</code><code class="o">,</code> <code class="o">-</code><code class="n">cy</code> <code class="o">*</code> <code class="mi">3</code> <code class="o">/</code> <code class="mi">4</code><code class="o">,</code>
<code class="n">cx</code> <code class="o">*</code> <code class="mi">3</code> <code class="o">/</code> <code class="mi">4</code><code class="o">,</code> <code class="n">cy</code> <code class="o">*</code> <code class="mi">3</code> <code class="o">/</code> <code class="mi">4</code><code class="o">,</code> <code class="mi">20</code><code class="o">,</code> <code class="mi">20</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setStroke</code><code class="o">(</code><code class="k">new</code> <code class="n">BasicStroke</code><code class="o">(</code><code class="mi">4</code><code class="o">));</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">magenta</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">fill</code><code class="o">(</code><code class="n">r</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setPaint</code><code class="o">(</code><code class="n">Color</code><code class="o">.</code><code class="na">green</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">draw</code><code class="o">(</code><code class="n">r</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">drawImage</code><code class="o">(</code><code class="n">image</code><code class="o">,</code> <code class="o">-</code><code class="n">cx</code> <code class="o">/</code> <code class="mi">2</code><code class="o">,</code> <code class="o">-</code><code class="n">cy</code> <code class="o">/</code> <code class="mi">2</code><code class="o">,</code> <code class="k">this</code><code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code><code class="o">[]</code> <code class="n">args</code><code class="o">)</code> <code class="o">{</code>
<code class="n">JFrame</code> <code class="n">frame</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JFrame</code><code class="o">(</code><code class="s">"Iguana"</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setLayout</code><code class="o">(</code><code class="k">new</code> <code class="n">BorderLayout</code><code class="o">());</code>
<code class="n">frame</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">Iguana</code><code class="o">(),</code> <code class="n">BorderLayout</code><code class="o">.</code><code class="na">CENTER</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setSize</code><code class="o">(</code><code class="mi">300</code><code class="o">,</code> <code class="mi">300</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setDefaultCloseOperation</code><code class="o">(</code> <code class="n">JFrame</code><code class="o">.</code><code class="na">EXIT_ON_CLOSE</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code></pre><div class="figure"><a id="learnjava3-CHP-20-FIG-2"/><div class="figure-contents"><div class="mediaobject"><a id="I_20_tt1146"/><img src="httpatomoreillycomsourceoreillyimages1707692.png.jpg" alt="Exercising the 2D API"/></div></div><p class="title">Figure 20-2. Exercising the 2D API</p></div><p>The <code class="literal">Iguana</code> class is a subclass
of <code class="literal">JComponent</code> with a very fancy
<code class="literal">paint()</code> method. The <code class="literal">main()</code> method takes care of creating a
<code class="literal">JFrame</code> that holds the <code class="literal">Iguana</code> component.</p><p><code class="literal">Iguana</code>’s constructor loads a
small image (we’ll talk more about this later) and sets up a mouse event
handler. This handler changes a member variable, <code class="literal">theta</code>, and repaints the component. Each time
you click, the entire drawing is rotated by 15 degrees.</p><p><code class="literal">Iguana</code>’s <code class="literal">paint()</code> method does some pretty interesting
stuff, but none of it is very difficult. First, user space is
transformed so that the origin is at the center of the component. The
user space is then rotated by <code class="literal">theta</code>:</p><a id="I_20_tt1147"/><pre class="programlisting"> <code class="n">g2</code><code class="o">.</code><code class="na">translate</code><code class="o">(</code><code class="n">cx</code><code class="o">,</code> <code class="n">cy</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">rotate</code><code class="o">(</code><code class="n">theta</code> <code class="o">*</code> <code class="n">Math</code><code class="o">.</code><code class="na">PI</code> <code class="o">/</code> <code class="mi">180</code><code class="o">);</code></pre><p><code class="literal">Iguana</code> saves the current
(default) clipping shape before setting it to a large ellipse. Then,
<code class="literal">Iguana</code> draws two filled ellipses. The
first is drawn by instantiating an <code class="literal">Ellipse2D</code> and filling it; the second is drawn
using the <code class="literal">fillOval()</code> convenience
method. (We’ll talk about the color gradient in the first ellipse in the
next section.) As you can see in <a class="xref" href="ch20s03.html#learnjava3-CHP-20-FIG-2" title="Figure 20-2. Exercising the 2D API">Figure 20-2</a>, both ellipses are clipped by the
elliptical clipping shape. After filling the two ellipses, <code class="literal">Iguana</code> restores the old clipping shape.</p><p>Next, <code class="literal">Iguana</code> draws some text
(see the section <a class="xref" href="ch20s06.html" title="Using Fonts">Using Fonts</a>). The next
action is to modify the compositing rule as follows:</p><a id="I_20_tt1148"/><pre class="programlisting"> <code class="n">AlphaComposite</code> <code class="n">ac</code> <code class="o">=</code> <code class="n">AlphaComposite</code><code class="o">.</code><code class="na">getInstance</code><code class="o">(</code>
<code class="n">AlphaComposite</code><code class="o">.</code><code class="na">SRC_OVER</code><code class="o">,</code> <code class="o">(</code><code class="kt">float</code><code class="o">).</code><code class="mi">75</code><code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">setComposite</code><code class="o">(</code><code class="n">ac</code><code class="o">);</code></pre><p>The only thing this means is that we want everything to be drawn
with transparency. The <a id="I_indexterm20_id811429" class="indexterm"/><code class="literal">AlphaComposite</code> class
defines constants that represent different compositing rules, much the
way the <code class="literal">Color</code> class contains
constants that represent different predefined colors. In this case,
we’re asking for the <span class="emphasis"><em>source over destination</em></span> rule
(<code class="literal">SRC_OVER</code>), but with an additional
alpha multiplier of 0.75. Source over destination means that whatever
we’re drawing (the source) should be placed on top of whatever’s already
there (the destination). The alpha multiplier means that everything we
draw will be treated at 0.75, or three quarters, of its normal opacity,
allowing the existing drawing to “show through.”</p><p>You can see the effect of the new compositing rule in the rounded
rectangle and the image, which both allow previously drawn elements to
show through.</p></div></div></body></html>