epubjs
Version:
Render ePub documents in the browser, across many devices
218 lines (200 loc) • 35.1 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Creating Custom Components</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="Creating Custom Components"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-18-SECT-6"/>Creating Custom Components</h1></div></div></div><p><a id="idx11022" class="indexterm"/>In this chapter and the previous one, we’ve worked with
different user interface objects. We’ve used Swing’s impressive repertoire
of components as building blocks and extended their functionality, but we
haven’t actually created any new components. In this section, we create an
entirely new component from scratch, a <span class="emphasis"><em>dial</em></span>.</p><p>Until now, our examples have been fairly self-contained; they
generally know everything about what to do and don’t rely on additional
parts to do processing. Our menu example created a <code class="literal">DinnerFrame</code> class that had a menu of dinner
options, but it included all the processing needed to handle the user’s
selections. If we wanted to process the selections differently, we’d have
to modify the class. A true component separates the detection of user
input from the handling of those choices. It lets the user take some
action and then informs other interested parties by emitting
events.</p><div class="sect2" title="Generating Events"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-6.1"/>Generating Events</h2></div></div></div><p><a id="I_indexterm18_id804113" class="indexterm"/>Because we want our new classes to be components, they
should communicate the way components communicate: by generating event
objects and sending those events to listeners. So far, we’ve written a
lot of code that listened for events but haven’t seen an example that
generated its own custom events.</p><p>Generating events sounds like it might be difficult, but it isn’t.
You can either create new kinds of events by subclassing <code class="literal">java.util.EventObject</code>, or use one of the
standard event types. In either case, you just need to allow
registration of listeners for your events and provide a means to deliver
events to those listeners. Swing’s <code class="literal">JComponent</code> class provides a protected member
variable called <code class="literal">listenerList</code>, which
you can use to keep track of event listeners. It’s an instance of
<code class="literal">EventListenerList</code>; basically it acts
like the maître d’ at a restaurant, keeping track of all event
listeners, sorted by type.</p><p>Often, you won’t need to worry about creating a custom event type.
<code class="literal">JComponent</code> has methods that support
firing of generic <code class="literal">PropertyChangeEvent</code>s whenever one of a
component’s properties changes. The example we’ll look at next uses this
infrastructure to fire <code class="literal">PropertyChangeEvent</code>s whenever a value
changes.</p></div><div class="sect2" title="A Dial Component"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-6.2"/>A Dial Component</h2></div></div></div><p><a id="idx11007" class="indexterm"/>The standard Swing classes don’t have a component that’s
similar to an old-fashioned dial—for example, the volume control on your
radio. (The <code class="literal">JSlider</code> fills this role,
of course.) In this section, we implement a <code class="literal">Dial</code> class. The dial has a value that can be
adjusted by clicking and dragging to “twist” the dial (see <a class="xref" href="ch18s06.html#learnjava3-CHP-18-FIG-11" title="Figure 18-11. The Dial component">Figure 18-11</a>). As the value of the dial
changes, <code class="literal">DialEvent</code>s are fired off by
the component. The dial can be used just like any other Java component.
We even have a custom <code class="literal">DialListener</code>
interface that matches the <code class="literal">DialEvent</code>
class.</p><div class="figure"><a id="learnjava3-CHP-18-FIG-11"/><div class="figure-contents"><div class="mediaobject"><a id="I_18_tt1099"/><img src="httpatomoreillycomsourceoreillyimages1707677.png.jpg" alt="The Dial component"/></div></div><p class="title">Figure 18-11. The Dial component</p></div><p>Here’s the <code class="literal">Dial</code> code:</p><a id="I_18_tt1100"/><pre class="programlisting"> <code class="c1">//file: Dial.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.util.*</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">Dial</code> <code class="kd">extends</code> <code class="n">JComponent</code> <code class="o">{</code>
<code class="kt">int</code> <code class="n">minValue</code><code class="o">,</code> <code class="n">nvalue</code><code class="o">,</code> <code class="n">maxValue</code><code class="o">,</code> <code class="n">radius</code><code class="o">;</code>
<code class="kd">public</code> <code class="nf">Dial</code><code class="o">()</code> <code class="o">{</code> <code class="k">this</code><code class="o">(</code><code class="mi">0</code><code class="o">,</code> <code class="mi">100</code><code class="o">,</code> <code class="mi">0</code><code class="o">);</code> <code class="o">}</code>
<code class="kd">public</code> <code class="nf">Dial</code><code class="o">(</code><code class="kt">int</code> <code class="n">minValue</code><code class="o">,</code> <code class="kt">int</code> <code class="n">maxValue</code><code class="o">,</code> <code class="kt">int</code> <code class="n">value</code><code class="o">)</code> <code class="o">{</code>
<code class="n">setMinimum</code><code class="o">(</code> <code class="n">minValue</code> <code class="o">);</code>
<code class="n">setMaximum</code><code class="o">(</code> <code class="n">maxValue</code> <code class="o">);</code>
<code class="n">setValue</code><code class="o">(</code> <code class="n">value</code> <code class="o">);</code>
<code class="n">setForeground</code><code class="o">(</code> <code class="n">Color</code><code class="o">.</code><code class="na">lightGray</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">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">spin</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code>
<code class="o">});</code>
<code class="n">addMouseMotionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">MouseMotionAdapter</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">mouseDragged</code><code class="o">(</code><code class="n">MouseEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">spin</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code>
<code class="o">});</code>
<code class="o">}</code>
<code class="kd">protected</code> <code class="kt">void</code> <code class="nf">spin</code><code class="o">(</code> <code class="n">MouseEvent</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code>
<code class="kt">int</code> <code class="n">y</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getY</code><code class="o">();</code>
<code class="kt">int</code> <code class="n">x</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getX</code><code class="o">();</code>
<code class="kt">double</code> <code class="n">th</code> <code class="o">=</code> <code class="n">Math</code><code class="o">.</code><code class="na">atan</code><code class="o">((</code><code class="mf">1.0</code> <code class="o">*</code> <code class="n">y</code> <code class="o">-</code> <code class="n">radius</code><code class="o">)</code> <code class="o">/</code> <code class="o">(</code><code class="n">x</code> <code class="o">-</code> <code class="n">radius</code><code class="o">));</code>
<code class="kt">int</code> <code class="n">value</code><code class="o">=(</code><code class="kt">int</code><code class="o">)(</code><code class="n">th</code> <code class="o">/</code> <code class="o">(</code><code class="mi">2</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="o">*</code> <code class="o">(</code><code class="n">maxValue</code> <code class="o">-</code> <code class="n">minValue</code><code class="o">));</code>
<code class="k">if</code> <code class="o">(</code><code class="n">x</code> <code class="o"><</code> <code class="n">radius</code><code class="o">)</code>
<code class="n">setValue</code><code class="o">(</code> <code class="n">value</code> <code class="o">+</code> <code class="o">(</code><code class="n">maxValue</code><code class="o">-</code><code class="n">minValue</code><code class="o">)</code> <code class="o">/</code> <code class="mi">2</code> <code class="o">+</code> <code class="n">minValue</code><code class="o">);</code>
<code class="k">else</code> <code class="nf">if</code> <code class="o">(</code><code class="n">y</code> <code class="o"><</code> <code class="n">radius</code><code class="o">)</code>
<code class="n">setValue</code><code class="o">(</code> <code class="n">value</code> <code class="o">+</code> <code class="n">maxValue</code> <code class="o">);</code>
<code class="k">else</code>
<code class="nf">setValue</code><code class="o">(</code> <code class="n">value</code> <code class="o">+</code> <code class="n">minValue</code><code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">paintComponent</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="kt">int</code> <code class="n">tick</code> <code class="o">=</code> <code class="mi">10</code><code class="o">;</code>
<code class="n">radius</code> <code class="o">=</code> <code class="n">Math</code><code class="o">.</code><code class="na">min</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="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">tick</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">getForeground</code><code class="o">().</code><code class="na">darker</code><code class="o">()</code> <code class="o">);</code>
<code class="n">g2</code><code class="o">.</code><code class="na">drawLine</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">tick</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="n">radius</code> <code class="o">*</code> <code class="mi">2</code> <code class="o">+</code> <code class="n">tick</code><code class="o">,</code> <code class="n">radius</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">2</code><code class="o">)</code> <code class="o">);</code>
<code class="n">draw3DCircle</code><code class="o">(</code> <code class="n">g2</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="kc">true</code> <code class="o">);</code>
<code class="kt">int</code> <code class="n">knobRadius</code> <code class="o">=</code> <code class="n">radius</code> <code class="o">/</code> <code class="mi">7</code><code class="o">;</code>
<code class="kt">double</code> <code class="n">th</code> <code class="o">=</code> <code class="n">nvalue</code> <code class="o">*</code> <code class="o">(</code><code class="mi">2</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="o">/</code> <code class="o">(</code><code class="n">maxValue</code> <code class="o">-</code> <code class="n">minValue</code><code class="o">);</code>
<code class="kt">int</code> <code class="n">x</code> <code class="o">=</code> <code class="o">(</code><code class="kt">int</code><code class="o">)(</code><code class="n">Math</code><code class="o">.</code><code class="na">cos</code><code class="o">(</code><code class="n">th</code><code class="o">)</code> <code class="o">*</code> <code class="o">(</code><code class="n">radius</code> <code class="o">-</code> <code class="n">knobRadius</code> <code class="o">*</code> <code class="mi">3</code><code class="o">)),</code>
<code class="n">y</code> <code class="o">=</code> <code class="o">(</code><code class="kt">int</code><code class="o">)(</code><code class="n">Math</code><code class="o">.</code><code class="na">sin</code><code class="o">(</code><code class="n">th</code><code class="o">)</code> <code class="o">*</code> <code class="o">(</code><code class="n">radius</code> <code class="o">-</code> <code class="n">knobRadius</code> <code class="o">*</code> <code class="mi">3</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">1</code><code class="o">));</code>
<code class="n">draw3DCircle</code><code class="o">(</code><code class="n">g2</code><code class="o">,</code> <code class="n">x</code> <code class="o">+</code> <code class="n">radius</code> <code class="o">-</code> <code class="n">knobRadius</code><code class="o">,</code>
<code class="n">y</code> <code class="o">+</code> <code class="n">radius</code> <code class="o">-</code> <code class="n">knobRadius</code><code class="o">,</code> <code class="n">knobRadius</code><code class="o">,</code> <code class="kc">false</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kd">private</code> <code class="kt">void</code> <code class="nf">draw3DCircle</code><code class="o">(</code>
<code class="n">Graphics</code> <code class="n">g</code><code class="o">,</code> <code class="kt">int</code> <code class="n">x</code><code class="o">,</code> <code class="kt">int</code> <code class="n">y</code><code class="o">,</code> <code class="kt">int</code> <code class="n">radius</code><code class="o">,</code> <code class="kt">boolean</code> <code class="n">raised</code><code class="o">)</code>
<code class="o">{</code>
<code class="n">Color</code> <code class="n">foreground</code> <code class="o">=</code> <code class="n">getForeground</code><code class="o">();</code>
<code class="n">Color</code> <code class="n">light</code> <code class="o">=</code> <code class="n">foreground</code><code class="o">.</code><code class="na">brighter</code><code class="o">();</code>
<code class="n">Color</code> <code class="n">dark</code> <code class="o">=</code> <code class="n">foreground</code><code class="o">.</code><code class="na">darker</code><code class="o">();</code>
<code class="n">g</code><code class="o">.</code><code class="na">setColor</code><code class="o">(</code><code class="n">foreground</code><code class="o">);</code>
<code class="n">g</code><code class="o">.</code><code class="na">fillOval</code><code class="o">(</code><code class="n">x</code><code class="o">,</code> <code class="n">y</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="n">g</code><code class="o">.</code><code class="na">setColor</code><code class="o">(</code><code class="n">raised</code> <code class="o">?</code> <code class="n">light</code> <code class="o">:</code> <code class="n">dark</code><code class="o">);</code>
<code class="n">g</code><code class="o">.</code><code class="na">drawArc</code><code class="o">(</code><code class="n">x</code><code class="o">,</code> <code class="n">y</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="mi">45</code><code class="o">,</code> <code class="mi">180</code><code class="o">);</code>
<code class="n">g</code><code class="o">.</code><code class="na">setColor</code><code class="o">(</code><code class="n">raised</code> <code class="o">?</code> <code class="n">dark</code> <code class="o">:</code> <code class="n">light</code><code class="o">);</code>
<code class="n">g</code><code class="o">.</code><code class="na">drawArc</code><code class="o">(</code><code class="n">x</code><code class="o">,</code> <code class="n">y</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="mi">225</code><code class="o">,</code> <code class="mi">180</code><code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="n">Dimension</code> <code class="nf">getPreferredSize</code><code class="o">()</code> <code class="o">{</code>
<code class="k">return</code> <code class="k">new</code> <code class="nf">Dimension</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="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">setValue</code><code class="o">(</code> <code class="kt">int</code> <code class="n">value</code> <code class="o">)</code> <code class="o">{</code>
<code class="k">this</code><code class="o">.</code><code class="na">nvalue</code> <code class="o">=</code> <code class="n">value</code> <code class="o">-</code> <code class="n">minValue</code><code class="o">;</code>
<code class="n">repaint</code><code class="o">();</code>
<code class="n">fireEvent</code><code class="o">();</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">int</code> <code class="nf">getValue</code><code class="o">()</code> <code class="o">{</code> <code class="k">return</code> <code class="n">nvalue</code><code class="o">+</code><code class="n">minValue</code><code class="o">;</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">setMinimum</code><code class="o">(</code><code class="kt">int</code> <code class="n">minValue</code><code class="o">)</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">minValue</code> <code class="o">=</code> <code class="n">minValue</code><code class="o">;</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">int</code> <code class="nf">getMinimum</code><code class="o">()</code> <code class="o">{</code> <code class="k">return</code> <code class="n">minValue</code><code class="o">;</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">setMaximum</code><code class="o">(</code><code class="kt">int</code> <code class="n">maxValue</code><code class="o">)</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">maxValue</code> <code class="o">=</code> <code class="n">maxValue</code><code class="o">;</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">int</code> <code class="nf">getMaximum</code><code class="o">()</code> <code class="o">{</code> <code class="k">return</code> <code class="n">maxValue</code><code class="o">;</code> <code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">addDialListener</code><code class="o">(</code><code class="n">DialListener</code> <code class="n">listener</code><code class="o">)</code> <code class="o">{</code>
<code class="n">listenerList</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="n">DialListener</code><code class="o">.</code><code class="na">class</code><code class="o">,</code> <code class="n">listener</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">removeDialListener</code><code class="o">(</code><code class="n">DialListener</code> <code class="n">listener</code><code class="o">)</code> <code class="o">{</code>
<code class="n">listenerList</code><code class="o">.</code><code class="na">remove</code><code class="o">(</code> <code class="n">DialListener</code><code class="o">.</code><code class="na">class</code><code class="o">,</code> <code class="n">listener</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kt">void</code> <code class="nf">fireEvent</code><code class="o">()</code> <code class="o">{</code>
<code class="n">Object</code><code class="o">[]</code> <code class="n">listeners</code> <code class="o">=</code> <code class="n">listenerList</code><code class="o">.</code><code class="na">getListenerList</code><code class="o">();</code>
<code class="k">for</code> <code class="o">(</code> <code class="kt">int</code> <code class="n">i</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code> <code class="n">i</code> <code class="o"><</code> <code class="n">listeners</code><code class="o">.</code><code class="na">length</code><code class="o">;</code> <code class="n">i</code> <code class="o">+=</code> <code class="mi">2</code> <code class="o">)</code>
<code class="k">if</code> <code class="o">(</code> <code class="n">listeners</code><code class="o">[</code><code class="n">i</code><code class="o">]</code> <code class="o">==</code> <code class="n">DialListener</code><code class="o">.</code><code class="na">class</code> <code class="o">)</code>
<code class="o">((</code><code class="n">DialListener</code><code class="o">)</code><code class="n">listeners</code><code class="o">[</code><code class="n">i</code> <code class="o">+</code> <code class="mi">1</code><code class="o">]).</code><code class="na">dialAdjusted</code><code class="o">(</code>
<code class="k">new</code> <code class="nf">DialEvent</code><code class="o">(</code><code class="k">this</code><code class="o">,</code> <code class="n">getValue</code><code class="o">())</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">"Dial v1.0"</code><code class="o">);</code>
<code class="kd">final</code> <code class="n">JLabel</code> <code class="n">statusLabel</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JLabel</code><code class="o">(</code><code class="s">"Welcome to Dial v1.0"</code><code class="o">);</code>
<code class="kd">final</code> <code class="n">Dial</code> <code class="n">dial</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Dial</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="n">dial</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">add</code><code class="o">(</code><code class="n">statusLabel</code><code class="o">,</code> <code class="n">BorderLayout</code><code class="o">.</code><code class="na">SOUTH</code><code class="o">);</code>
<code class="n">dial</code><code class="o">.</code><code class="na">addDialListener</code><code class="o">(</code><code class="k">new</code> <code class="n">DialListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">dialAdjusted</code><code class="o">(</code><code class="n">DialEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">statusLabel</code><code class="o">.</code><code class="na">setText</code><code class="o">(</code><code class="s">"Value is "</code> <code class="o">+</code> <code class="n">e</code><code class="o">.</code><code class="na">getValue</code><code class="o">());</code>
<code class="o">}</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">setSize</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="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><p>Here’s <code class="literal">DialEvent</code>, a simple
subclass of <code class="literal">java.util.EventObject</code>:</p><a id="I_18_tt1101"/><pre class="programlisting"> <code class="c1">//file: DialEvent.java</code>
<code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">DialEvent</code> <code class="kd">extends</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">EventObject</code> <code class="o">{</code>
<code class="kt">int</code> <code class="n">value</code><code class="o">;</code>
<code class="n">DialEvent</code><code class="o">(</code> <code class="n">Dial</code> <code class="n">source</code><code class="o">,</code> <code class="kt">int</code> <code class="n">value</code> <code class="o">)</code> <code class="o">{</code>
<code class="kd">super</code><code class="o">(</code> <code class="n">source</code> <code class="o">);</code>
<code class="k">this</code><code class="o">.</code><code class="na">value</code> <code class="o">=</code> <code class="n">value</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">int</code> <code class="nf">getValue</code><code class="o">()</code> <code class="o">{</code>
<code class="k">return</code> <code class="n">value</code><code class="o">;</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>Finally, here’s the code for <code class="literal">DialListener</code>:</p><a id="I_18_tt1102"/><pre class="programlisting"> <code class="c1">//file: DialListener.java</code>
<code class="kd">public</code> <code class="kd">interface</code> <code class="nc">DialListener</code> <code class="kd">extends</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">EventListener</code> <code class="o">{</code>
<code class="kt">void</code> <code class="nf">dialAdjusted</code><code class="o">(</code> <code class="n">DialEvent</code> <code class="n">e</code> <code class="o">);</code>
<code class="o">}</code></pre><p>Let’s start from the top of the <code class="literal">Dial</code> class. We’ll focus on the structure and
leave you to figure out the trigonometry on your own.</p><p><code class="literal">Dial</code>’s <code class="literal">main()</code> method demonstrates how to use the dial
to build a user interface. It creates a <code class="literal">Dial</code> and adds it to a <code class="literal">JFrame</code>. Then <code class="literal">main()</code> registers a dial listener on the dial.
Whenever a <code class="literal">DialEvent</code> is received, the
value of the dial is examined and displayed in a <code class="literal">JLabel</code> at the bottom of the frame
window.</p><p>The constructor for the <code class="literal">Dial</code>
class stores the dial’s minimum, maximum, and current values; a default
constructor provides a minimum of <code class="literal">0</code>,
a maximum of <code class="literal">100</code>, and a current value
of <code class="literal">0</code>. The constructor sets the
foreground color of the dial and registers listeners for mouse events.
If the mouse is pressed or dragged, <code class="literal">Dial</code>’s <code class="literal">spin()</code> method is called to update the dial’s
value. <code class="literal">spin()</code> performs some basic
trigonometry to figure out what the new value of the dial should
be.</p><p><code class="literal">paintComponent()</code> and <code class="literal">draw3DCircle()</code> do a lot of trigonometry to
figure out how to display the dial. <code class="literal">draw3DCircle()</code> is a private helper method that
draws a circle that appears either raised or depressed; we use this to
make the dial look three-dimensional.</p><p>The next group of methods provides ways to retrieve or change the
dial’s current setting and the minimum and maximum values. The important
thing to notice here is the pattern of get and set methods for all of
the important values used by the <code class="literal">Dial</code>. We will talk more about this in <a class="xref" href="ch22.html" title="Chapter 22. JavaBeans">Chapter 22</a>. Also, notice that the <code class="literal">setValue()</code> method does two important things: it repaints the
component to reflect the new value and fires the <code class="literal">DialEvent</code>
signifying the change.</p><p>The final group of methods in the <code class="literal">Dial</code> class provides the plumbing necessary for
our event firing. <code class="literal">addDialListener()</code>
and <code class="literal">removeDialListener()</code> take care of
maintaining the listener list. Using the <code class="literal">listenerList</code> member variable we inherited from
<code class="literal">JComponent</code> makes this an easy task.
The <code class="literal">fireEvent()</code> method retrieves the
registered listeners for this component. It sends a <code class="literal">DialEvent</code> to any registered <code class="literal">DialListener</code>s.<a id="I_indexterm18_id804588" class="indexterm"/></p></div><div class="sect2" title="Model and View Separation"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-6.3"/>Model and View Separation</h2></div></div></div><p>The <code class="literal">Dial</code> example is overly
simplified. All Swing components, as we’ve discussed, keep their data
model and view separate. In the <code class="literal">Dial</code>
component, we’ve combined these elements in a single class, which limits
its reusability. To have <code class="literal">Dial</code>
implement the MVC paradigm, we would have developed a dial data model
and something called a UI-delegate that handled displaying the component
and responding to user events. For a full treatment of this subject, see
the <code class="literal">JogShuttle</code> example in O’Reilly’s
<span class="emphasis"><em>J</em></span><a class="ulink" href="http://shop.oreilly.com/product/9780596004088.do"><span class="emphasis"><em>ava
Swing</em></span></a>.</p><p>In <a class="xref" href="ch19.html" title="Chapter 19. Layout Managers">Chapter 19</a>, we’ll take what we know
about components and containers and put them together using layout
managers to create complex GUIs.<a id="I_indexterm18_id804651" class="indexterm"/></p></div></div></body></html>