epubjs
Version:
Render ePub documents in the browser, across many devices
157 lines (154 loc) • 19.3 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Customizing with BeanInfo</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="Customizing with BeanInfo"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-22-SECT-9"/>Customizing with BeanInfo</h1></div></div></div><p><a id="idx11142" class="indexterm"/> <a id="I_indexterm22_id822878" class="indexterm"/>So far, everything NetBeans has known about our beans has
been determined by low-level reflection—that is, by looking at the methods
of our classes. The <a id="I_indexterm22_id822892" class="indexterm"/><code class="literal">java.Beans.Introspector</code>
class gathers information on a bean using reflection, then analyzes and
describes a bean to any tool that wants to know about it. The
introspection process works only if the class follows the JavaBeans naming
conventions for its methods; furthermore, it gives us little control over
exactly what properties and events appear in NetBeans menus. For example,
we’ve seen that NetBeans by default shows all the stuff we inherit from
the base Swing component. We can change that by creating <code class="literal">BeanInfo</code> classes for our beans. A <code class="literal">BeanInfo</code> class provides the JavaBeans
introspector with explicit information about the properties, methods, and
events of a bean; we can even use it to customize the text that appears in
menus in NetBeans (and in other IDEs).</p><p>A <code class="literal">BeanInfo</code> class implements the
<code class="literal">BeanInfo</code> interface. That’s a
complicated proposition; in most situations, the introspector’s default
behavior is reasonable. Instead of implementing the <code class="literal">BeanInfo</code> interface, we extend the <code class="literal">SimpleBeanInfo</code> class, which implements all of
<code class="literal">BeanInfo</code>’s methods. We can override
specific methods to provide the information we want; when we don’t
override a method, we’ll get the introspector’s default behavior.</p><p>In the next few sections, we’ll develop the <code class="literal">DialBeanInfo</code> class that provides explicit
information about our <code class="literal">Dial</code> bean.</p><div class="sect2" title="Getting Properties Information"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-22-SECT-9.1"/>Getting Properties Information</h2></div></div></div><p><a id="idx11141" class="indexterm"/> <a id="idx11153" class="indexterm"/>We’ll start out by describing the <code class="literal">Dial</code>’s properties. To do so, we must implement
the <a id="I_indexterm22_id823024" class="indexterm"/><code class="literal">getPropertyDescriptors()</code> method. This
method simply returns an array of <code class="literal">PropertyDescriptor</code> objects—one for
each property we want to publicize.</p><p>To create a <code class="literal">PropertyDescriptor</code>,
call its constructor with two arguments: the property’s name and the
class. In the following code, we create descriptors for the <code class="literal">Dial</code>’s <code class="literal">value</code>, <code class="literal">minimum</code>, and <code class="literal">maximum</code> properties. We next call a few methods
of the <code class="literal">PropertyDescriptor</code> class to
provide additional information about each property. If our methods were
bound (generated <code class="literal">PropertyChangeEvent</code>s
when modified), we’d call the <a id="I_indexterm22_id823091" class="indexterm"/><code class="literal">setBound()</code> method of
their <code class="literal">PropertyDescriptor</code>s. Our code
is prepared to catch an <code class="literal">IntrospectionException</code>, which can occur if
something goes wrong while creating the property descriptors, such as
encountering a nonexistent method:</p><a id="I_22_tt1234"/><pre class="programlisting"> <code class="c1">//file: DialBeanInfo.java</code>
<code class="kn">package</code> <code class="n">magicbeans</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.beans.*</code><code class="o">;</code>
<code class="err"> </code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">DialBeanInfo</code> <code class="kd">extends</code> <code class="n">SimpleBeanInfo</code> <code class="o">{</code>
<code class="err"> </code>
<code class="kd">public</code> <code class="n">PropertyDescriptor</code><code class="o">[]</code> <code class="nf">getPropertyDescriptors</code><code class="o">()</code> <code class="o">{</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">PropertyDescriptor</code> <code class="n">value</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">PropertyDescriptor</code><code class="o">(</code><code class="s">"value"</code><code class="o">,</code> <code class="n">Dial</code><code class="o">.</code><code class="na">class</code><code class="o">);</code>
<code class="n">PropertyDescriptor</code> <code class="n">minimum</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">PropertyDescriptor</code><code class="o">(</code><code class="s">"minimum"</code><code class="o">,</code> <code class="n">Dial</code><code class="o">.</code><code class="na">class</code><code class="o">);</code>
<code class="n">PropertyDescriptor</code> <code class="n">maximum</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">PropertyDescriptor</code><code class="o">(</code><code class="s">"maximum"</code><code class="o">,</code> <code class="n">Dial</code><code class="o">.</code><code class="na">class</code><code class="o">);</code>
<code class="k">return</code> <code class="k">new</code> <code class="n">PropertyDescriptor</code> <code class="o">[]</code> <code class="o">{</code> <code class="n">value</code><code class="o">,</code> <code class="n">minimum</code><code class="o">,</code> <code class="n">maximum</code> <code class="o">};</code>
<code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">IntrospectionException</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="k">return</code> <code class="kc">null</code><code class="o">;</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>Perhaps the most useful thing about <code class="literal">DialBeanInfo</code> is that by providing explicit
information for our properties, we automatically hide other properties
that introspection might find. After compiling <code class="literal">DialBeanInfo</code> and packaging it with the
<code class="literal">Dial</code>, you’ll see that its <code class="literal">JComponent</code> properties no longer appear in the
NetBeans properties editor. (This has been the case all along if you
started with the precompiled example JAR.)</p><p>A <code class="literal">PropertyDescriptor</code> can
provide a lot of other information about a property: the names of the
accessor methods (if you decide not to use the standard naming
convention), information about whether the property is constrained, and
a class to use as a property editor (if the standard property editors
aren’t sufficient).</p><div class="sect3" title="Getting events information"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-22-SECT-9.1.1"/>Getting events information</h3></div></div></div><p>The <code class="literal">Dial</code> bean defines its own
event: the <code class="literal">DialEvent</code>. We’d like to
tell development tools about this event so that we can build
applications using it. The process for telling the world about our
event is similar to what we did previously: we add a method to the <code class="literal">DialBeanInfo</code> class called
<a id="I_indexterm22_id823202" class="indexterm"/><code class="literal">getEventSetDescriptors()</code>, which returns an
array of <code class="literal">EventSetDescriptor</code>s.</p><p>Events are described in terms of their listener interfaces, not
in terms of the event classes themselves, so our <code class="literal">getEventSetDescriptors()</code> method creates a
descriptor for the <code class="literal">DialListener</code>
interface. Here’s the code to add to the <code class="literal">DialBeanInfo</code> class:</p><a id="I_22_tt1235"/><pre class="programlisting"> <code class="kd">public</code> <code class="n">EventSetDescriptor</code><code class="o">[]</code> <code class="nf">getEventSetDescriptors</code><code class="o">()</code> <code class="o">{</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">EventSetDescriptor</code> <code class="n">dial</code> <code class="o">=</code> <code class="k">new</code> <code class="n">EventSetDescriptor</code><code class="o">(</code>
<code class="n">Dial</code><code class="o">.</code><code class="na">class</code><code class="o">,</code> <code class="s">"dialAdjusted"</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="s">"dialAdjusted"</code><code class="o">);</code>
<code class="n">dial</code><code class="o">.</code><code class="na">setDisplayName</code><code class="o">(</code><code class="s">"Dial Adjusted"</code><code class="o">);</code>
<code class="k">return</code> <code class="k">new</code> <code class="n">EventSetDescriptor</code> <code class="o">[]</code> <code class="o">{</code> <code class="n">dial</code> <code class="o">};</code>
<code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">IntrospectionException</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="k">return</code> <code class="kc">null</code><code class="o">;</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>In this method, we create an <code class="literal">EventSetDescriptor</code> object: <code class="literal">dial</code>. The constructor for an <code class="literal">EventSetDescriptor</code> takes four arguments: the
class that generates the event, the name of the event (the name that
is displayed, by default, by a development tool), the listener class,
and the name of the method to which the event can be delivered. (Other
constructors let you deal with listener interfaces that have several
methods.) After creating the descriptor, we call the <a id="I_indexterm22_id823278" class="indexterm"/><code class="literal">setDisplayName()</code>
method to provide a friendly name to be displayed by development tools
such as NetBeans. (This overrides the default name specified in the
constructor.)</p><p>Just as the property descriptors we supply hide the properties
that were discovered by reflection, the <code class="literal">EventSetDescriptor</code>s can hide the other
events that are inherited from the base component classes. In theory,
when you recompile <code class="literal">DialBeanInfo</code>,
package it in a JAR, and load it into NetBeans, you should see only
the two events that we have explicitly described: our own <code class="literal">DialEvent</code> and <code class="literal">PropertyChangeEvent</code> (displayed as “Dial
Adjusted” and “Bound property change”). Unfortunately, the current
version of NetBeans ignores this information.</p><p>Once we have an <code class="literal">EventSetDescriptor</code>, we can provide other
kinds of information about the event. For example, we can state that
the event is <span class="emphasis"><em>unicast</em></span>, which means that it can
have only one listener.</p></div><div class="sect3" title="Supplying icons"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-22-SECT-9.1.2"/>Supplying icons</h3></div></div></div><p>Some of the beans that come with NetBeans are displayed on the
palette with a cute icon. This makes life more pleasant for everyone.
To supply an icon for the <code class="literal">BeanInfo</code>
object we have been developing, we have it implement the <a id="I_indexterm22_id823348" class="indexterm"/><code class="literal">getIcon()</code> method. You
can supply up to four icons, with sizes of 16 × 16 or 32 × 32, in
color or monochrome. Here’s the <code class="literal">getIcon()</code> method for <code class="literal">DialBeanInfo</code>:</p><a id="I_22_tt1236"/><pre class="programlisting"> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">DialBeanInfo</code> <code class="kd">extends</code> <code class="n">SimpleBeanInfo</code> <code class="o">{</code>
<code class="o">...</code>
<code class="kd">public</code> <code class="n">java</code><code class="o">.</code><code class="na">awt</code><code class="o">.</code><code class="na">Image</code> <code class="nf">getIcon</code><code class="o">(</code><code class="kt">int</code> <code class="n">iconKind</code><code class="o">)</code> <code class="o">{</code>
<code class="err"> </code>
<code class="k">if</code> <code class="o">(</code><code class="n">iconKind</code> <code class="o">==</code> <code class="n">BeanInfo</code><code class="o">.</code><code class="na">ICON_COLOR_16x16</code><code class="o">)</code> <code class="o">{</code>
<code class="k">return</code> <code class="nf">loadImage</code><code class="o">(</code><code class="s">"DialIconColor16.gif"</code><code class="o">);</code>
<code class="o">}</code> <code class="k">else</code>
<code class="k">if</code> <code class="o">(</code><code class="n">iconKind</code> <code class="o">==</code> <code class="n">BeanInfo</code><code class="o">.</code><code class="na">ICON_COLOR_32x32</code><code class="o">)</code> <code class="o">{</code>
<code class="k">return</code> <code class="nf">loadImage</code><code class="o">(</code><code class="s">"DialIconColor32.gif"</code><code class="o">);</code>
<code class="o">}</code> <code class="k">else</code>
<code class="k">if</code> <code class="o">(</code><code class="n">iconKind</code> <code class="o">==</code> <code class="n">BeanInfo</code><code class="o">.</code><code class="na">ICON_MONO_16x16</code><code class="o">)</code> <code class="o">{</code>
<code class="k">return</code> <code class="nf">loadImage</code><code class="o">(</code><code class="s">"DialIconMono16.gif"</code><code class="o">);</code>
<code class="o">}</code> <code class="k">else</code>
<code class="k">if</code> <code class="o">(</code><code class="n">iconKind</code> <code class="o">==</code> <code class="n">BeanInfo</code><code class="o">.</code><code class="na">ICON_MONO_32x32</code><code class="o">)</code> <code class="o">{</code>
<code class="k">return</code> <code class="nf">loadImage</code><code class="o">(</code><code class="s">"DialIconMono32.gif"</code><code class="o">);</code>
<code class="o">}</code>
<code class="k">return</code> <code class="kc">null</code><code class="o">;</code>
<code class="o">}</code></pre><p>This method is called with a constant, indicating what kind of
icon is being requested; for example, <code class="literal">BeanInfo.ICON_COLOR_16x16</code> requests a 16 × 16
color image. If an appropriate icon is available, it loads the image
and returns an <code class="literal">Image</code> object. If the
icon isn’t available, it returns <code class="literal">null</code>. For convenience, you can package the
images in the same JAR file as the bean and its <code class="literal">BeanInfo</code> class.</p><p>Though we haven’t used them here, you can also use a <code class="literal">BeanInfo</code> object to provide information about
other public methods of your bean (for example, array-valued
properties) and other features.</p></div><div class="sect3" title="Creating customizers and property editors"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-22-SECT-9.1.3"/>Creating customizers and property editors</h3></div></div></div><p>JavaBeans lets you provide a <span class="emphasis"><em>customizer</em></span> for
your beans. Customizers are objects that do advanced customization for
a bean as a whole; they let you provide your own GUI for tweaking your
bean. We won’t show you how to write a customizer; it’s not too
difficult, but it’s beyond the scope of this chapter. Suffice it to
say that a customizer must implement the <a id="I_indexterm22_id823443" class="indexterm"/><code class="literal">java.beans.Customizer</code>
interface and should extend <code class="literal">Component</code> (or <code class="literal">JComponent</code>) so that it can be
displayed.</p><p>Property editors are a way of giving the properties sheet
additional capabilities. For example, you could supply a property
editor to let you edit a property type that is specific to your bean.
You could provide a property editor that would let you edit an
object’s price in dollars and cents. We’ve already seen a couple of
property editors: the editor used for <code class="literal">Color</code>-valued properties is fundamentally the
same as a property editor you might write yourself. In addition, the
<code class="literal">Molecule</code> bean uses a property
editor to specify its <code class="literal">moleculeName</code>
property. A <span class="emphasis"><em>property editor</em></span> isn’t quite as fancy
as a customizer, but describing it fully is also beyond the scope of
this chapter.</p><p>Again, describing how to write a property editor is also beyond
the scope of this chapter. However, it might help you to know that a
property editor must implement the <code class="literal">PropertyEditor</code> interface; it usually does so
by extending the <code class="literal">PropertyEditorSupport</code> class, which provides
default implementations for most of the methods.<a id="I_indexterm22_id823513" class="indexterm"/><a id="I_indexterm22_id823520" class="indexterm"/></p></div></div></div></body></html>