UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

157 lines (154 loc) 19.3 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>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>