UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

237 lines (221 loc) 42 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <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>