UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

218 lines (200 loc) 35.1 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>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">&lt;</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">&lt;</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">&lt;</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>