epubjs
Version:
Render ePub documents in the browser, across many devices
208 lines (201 loc) • 36.3 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Focus Navigation</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="Focus Navigation"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-18-SECT-2"/>Focus Navigation</h1></div></div></div><p><a id="idx11024" class="indexterm"/>We’ve brought up the topic of focus many times in our
discussion so far, and we’ve told you that the handling and user
navigation of focus is mostly done automatically. The focus system is very
powerful and can be heavily customized through the use of “focus traversal
policy” objects that control keyboard navigation. For typical application
behavior, you won’t have to deal with this directly, but we’ll explain a
few features you should know about.</p><p>Swing handles keyboard focus navigation through the <a id="I_indexterm18_id801341" class="indexterm"/><code class="literal">KeyboardFocusManager</code>
class. This class uses <a id="I_indexterm18_id801353" class="indexterm"/><code class="literal">FocusTraversalPolicy</code>
“strategy” objects that implement the actual schemes for locating the next
component to receive focus. There are two primary <code class="literal">FocusTraversalPolicy</code> types supplied with Java.
The first, <a id="I_indexterm18_id801372" class="indexterm"/><code class="literal">DefaultFocusTraversalPolicy</code>, is part of the AWT
package. It emulates the legacy AWT-style focus management that navigated
components in the order in which they were added to their container. The
next, <a id="I_indexterm18_id801385" class="indexterm"/><code class="literal">LayoutFocusTraversalPolicy</code>, is the default for
all Swing applications. It examines the layout and attempts to provide the
more typical navigation from left to right and top to bottom, based on
component position and size.</p><p>The focus traversal policy is inherited from containers and oriented
around groups of components known as “root cycles.” By default, each
individual window and <a id="I_indexterm18_id801403" class="indexterm"/><code class="literal">JInternalFrame</code> is its own
root cycle. In other words, focus traverses all of its child components
repeatedly (jumping from the last component back to the first), and won’t,
by default, leave the container through keyboard navigation.</p><p>The default Swing policy uses the following keys for keyboard
navigation:</p><div class="variablelist"><dl><dt><span class="term"><span class="emphasis"><em>Forward</em></span></span></dt><dd><p>Tab or Ctrl-Tab (Ctrl-Tab also works inside text areas)</p></dd><dt><span class="term"><span class="emphasis"><em>Back</em></span></span></dt><dd><p>Shift-Tab or Ctrl-Shift-Tab (Ctrl-Shift-Tab also works inside
text areas)</p></dd></dl></div><p>You can define your own focus traversal keys for forward and back
navigation, as well as for navigation across root cycles using the
<a id="I_indexterm18_id801442" class="indexterm"/><code class="literal">setFocusTraversalKeys()</code>
method of a container. Here is an example that adds the keystroke Ctrl-N
to the list of forward key navigation for components in a Frame:</p><a id="I_18_tt1070"/><pre class="programlisting"> <code class="n">frame</code><code class="o">.</code><code class="na">getFocusTraversalKeys</code><code class="o">(</code>
<code class="n">KeyboardFocusManager</code><code class="o">.</code><code class="na">FORWARD_TRAVERSAL_KEYS</code> <code class="o">);</code>
<code class="n">AWTKeyStroke</code> <code class="n">ks</code> <code class="o">=</code> <code class="n">AWTKeyStroke</code><code class="o">.</code><code class="na">getAWTKeyStroke</code><code class="o">(</code>
<code class="n">KeyEvent</code><code class="o">.</code><code class="na">VK_N</code><code class="o">,</code> <code class="n">InputEvent</code><code class="o">.</code><code class="na">CTRL_DOWN_MASK</code> <code class="o">);</code>
<code class="n">Set</code> <code class="k">new</code> <code class="o">=</code> <code class="k">new</code> <code class="n">HashSet</code><code class="o">(</code> <code class="n">old</code> <code class="o">);</code>
<code class="n">set</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="n">ks</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setFocusTraversalKeys</code><code class="o">(</code>
<code class="n">KeyboardFocusManager</code><code class="o">.</code><code class="na">FORWARD_TRAVERSAL_KEYS</code><code class="o">,</code><code class="n">set</code><code class="o">);</code></pre><p>Keys are defined by the <a id="I_indexterm18_id801468" class="indexterm"/><code class="literal">AWTKeyStroke</code> class, which
encapsulates the key and input modifiers—in this case, the Control key.
Constants in the <code class="literal">KeyboardFocusManager</code>
specify forward, back, and up or down root cycle transfer across
windows.</p><p>Finally, you can also move focus programmatically using the
following methods of <code class="literal">KeyboardFocusManager</code>:</p><a id="I_18_tt1071"/><pre class="programlisting"> <code class="n">focusNextComponent</code><code class="o">()</code>
<code class="n">focusPreviousComponent</code><code class="o">()</code>
<code class="n">upFocusCycle</code><code class="o">()</code>
<code class="n">downFocusCycle</code><code class="o">()</code></pre><div class="sect2" title="Trees"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-2.1"/>Trees</h2></div></div></div><p><a id="idx11014" class="indexterm"/> <a id="I_indexterm18_id801523" class="indexterm"/>One of Swing’s advanced components is <a id="I_indexterm18_id801530" class="indexterm"/><code class="literal">JTree</code>. Trees are good
for representing hierarchical information, like the contents of a disk
drive or a company’s organizational chart. As with all Swing components,
the data model is distinct from the visual representation. This means
you can do things such as update the data model and trust that the
visual component will be updated properly.</p><p><code class="literal">JTree</code> is powerful and complex.
It’s big enough, in fact, that like the text tools, the classes that
support <code class="literal">JTree</code> have their own package,
<a id="I_indexterm18_id801561" class="indexterm"/><code class="literal">javax.swing.tree</code>.
However, if you accept the default options for almost everything,
<code class="literal">JTree</code> is very easy to use. <a class="xref" href="ch18s02.html#learnjava3-CHP-18-FIG-6" title="Figure 18-6. The JTree class in action">Figure 18-6</a> shows a <code class="literal">JTree</code> running in a Swing application that
we’ll describe later.<a id="I_indexterm18_id801589" class="indexterm"/></p><div class="figure"><a id="learnjava3-CHP-18-FIG-6"/><div class="figure-contents"><div class="mediaobject"><a id="I_18_tt1072"/><img src="httpatomoreillycomsourceoreillyimages1707672.png" alt="The JTree class in action"/></div></div><p class="title">Figure 18-6. The JTree class in action</p></div></div><div class="sect2" title="Nodes and Models"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-2.2"/>Nodes and Models</h2></div></div></div><p><a id="idx11012" class="indexterm"/>A tree’s data model is made up of interconnected nodes. A
node has a name—typically, a parent—and some number of children
(possibly 0). In Swing, a node is represented by the <a id="I_indexterm18_id801639" class="indexterm"/><code class="literal">TreeNode</code> interface.
Nodes that can be modified are represented by <a id="I_indexterm18_id801650" class="indexterm"/><code class="literal">MutableTreeNode</code>. A
concrete implementation of this interface is <a id="I_indexterm18_id801662" class="indexterm"/><code class="literal">DefaultMutableTreeNode</code>.
One node, called the <span class="emphasis"><em>root</em></span> node, usually resides at
the top of the hierarchy.</p><p>A tree’s data model is represented by the <code class="literal">TreeModel</code> interface. Swing provides an
implementation of this interface called <code class="literal">DefaultTreeModel</code>. You can create a <code class="literal">DefaultTreeModel</code> by passing a root <code class="literal">TreeNode</code> to its constructor.</p><p>You could create a <code class="literal">TreeModel</code>
with just one node like this:</p><a id="I_18_tt1073"/><pre class="programlisting"> <code class="n">TreeNode</code> <code class="n">root</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Root node"</code><code class="o">);</code>
<code class="n">TreeModel</code> <code class="n">model</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultTreeModel</code><code class="o">(</code><code class="n">root</code><code class="o">);</code></pre><p>Here’s another example with a real hierarchy. The root node
contains two nodes, Node 1 and Group. The Group node contains Node 2 and
Node 3 as subnodes.</p><a id="I_18_tt1074"/><pre class="programlisting"> <code class="n">MutableTreeNode</code> <code class="n">root</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Root node"</code><code class="o">);</code>
<code class="n">MutableTreeNode</code> <code class="n">group</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Group"</code><code class="o">);</code>
<code class="n">root</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="n">group</code><code class="o">,</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">root</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Node 1"</code><code class="o">),</code> <code class="mi">1</code><code class="o">);</code>
<code class="n">group</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Node 2"</code><code class="o">),</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">group</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Node 3"</code><code class="o">),</code> <code class="mi">1</code><code class="o">);</code></pre><p>The second parameter to the <code class="literal">insert()</code> method is the index of the node in
the parent. After you organize your nodes, you can create a <code class="literal">TreeModel</code> in the same way as before:<a id="I_indexterm18_id801750" class="indexterm"/></p><a id="I_18_tt1075"/><pre class="programlisting"> <code class="n">TreeModel</code> <code class="n">model</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultTreeModel</code><code class="o">(</code><code class="n">root</code><code class="o">);</code></pre></div><div class="sect2" title="Save a Tree"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-2.3"/>Save a Tree</h2></div></div></div><p>Once you have a tree model, creating a <a id="I_indexterm18_id801774" class="indexterm"/><code class="literal">JTree</code> is simple:</p><a id="I_18_tt1076"/><pre class="programlisting"> <code class="n">JTree</code> <code class="n">tree</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JTree</code><code class="o">(</code><code class="n">model</code><code class="o">);</code></pre><p>The <code class="literal">JTree</code> behaves like a
souped-up <code class="literal">JList</code>. As <a class="xref" href="ch18s02.html#learnjava3-CHP-18-FIG-6" title="Figure 18-6. The JTree class in action">Figure 18-6</a> shows, the <code class="literal">JTree</code> automatically shows nodes with no
children as a sheet of paper, while nodes that contain other nodes are
shown as folders. You can expand and collapse nodes by clicking on the
little knobs to the left of the folder icons. You can also expand and
collapse nodes by double-clicking on them. You can select nodes;
multiple selections are possible using the Shift and Control keys. And,
as with a <code class="literal">JList</code>, you should put a
<code class="literal">JTree</code> in a <code class="literal">JScrollPane</code> if you want it to scroll.</p></div><div class="sect2" title="Tree Events"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-2.4"/>Tree Events</h2></div></div></div><p><a id="idx11013" class="indexterm"/> <a id="idx11041" class="indexterm"/>A tree fires off several flavors of events. You can find
out when nodes have been expanded and collapsed, when nodes are about to
be expanded or collapsed (because the user has clicked on them), and
when selections occur. Three distinct event listener interfaces handle
this information.</p><a id="I_18_tt1077"/><pre class="programlisting"> <code class="n">TreeExpansionListener</code>
<code class="n">TreeWillExpandListener</code>
<code class="n">TreeSelectionListener</code></pre><p>Tree selections are a tricky business. You can select any
combination of nodes by using the Control key and clicking on nodes.
Tree selections are described by a <a id="I_indexterm18_id801881" class="indexterm"/><code class="literal">TreePath</code>, which
describes how to get from the root node to the selected nodes.</p><p>The following example registers an event listener that prints out
the last selected node:<a id="I_indexterm18_id801895" class="indexterm"/><a id="I_indexterm18_id801902" class="indexterm"/></p><a id="I_18_tt1078"/><pre class="programlisting"> <code class="n">tree</code><code class="o">.</code><code class="na">addTreeSelectionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">TreeSelectionListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">valueChanged</code><code class="o">(</code><code class="n">TreeSelectionEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">TreePath</code> <code class="n">tp</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getNewLeadSelectionPath</code><code class="o">();</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">tp</code><code class="o">.</code><code class="na">getLastPathComponent</code><code class="o">());</code>
<code class="o">}</code>
<code class="o">});</code></pre></div><div class="sect2" title="A Complete Example"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-18-SECT-2.5"/>A Complete Example</h2></div></div></div><p><a id="idx11011" class="indexterm"/>This section contains an example that showcases the
following tree techniques:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>Construction of a tree model, using <code class="literal">DefaultMutableTreeNode</code></p></li><li class="listitem"><p>Creation and display of a <code class="literal">JTree</code></p></li><li class="listitem"><p>Listening for tree selection events</p></li><li class="listitem"><p>Modifying the tree’s data model while the <code class="literal">JTree</code> is showing</p></li></ul></div><p>Here’s the source code for the example:</p><a id="I_18_tt1079"/><pre class="programlisting"> <code class="c1">//file: PartsTree.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">javax.swing.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.event.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.tree.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">PartsTree</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="c1">// create a hierarchy of nodes</code>
<code class="n">MutableTreeNode</code> <code class="n">root</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Parts"</code><code class="o">);</code>
<code class="n">MutableTreeNode</code> <code class="n">beams</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Beams"</code><code class="o">);</code>
<code class="n">MutableTreeNode</code> <code class="n">gears</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Gears"</code><code class="o">);</code>
<code class="n">root</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="n">beams</code><code class="o">,</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">root</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="n">gears</code><code class="o">,</code> <code class="mi">1</code><code class="o">);</code>
<code class="n">beams</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"1x4 black"</code><code class="o">),</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">beams</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"1x6 black"</code><code class="o">),</code> <code class="mi">1</code><code class="o">);</code>
<code class="n">beams</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"1x8 black"</code><code class="o">),</code> <code class="mi">2</code><code class="o">);</code>
<code class="n">beams</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"1x12 black"</code><code class="o">),</code> <code class="mi">3</code><code class="o">);</code>
<code class="n">gears</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"8t"</code><code class="o">),</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">gears</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"24t"</code><code class="o">),</code> <code class="mi">1</code><code class="o">);</code>
<code class="n">gears</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"40t"</code><code class="o">),</code> <code class="mi">2</code><code class="o">);</code>
<code class="n">gears</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"worm"</code><code class="o">),</code> <code class="mi">3</code><code class="o">);</code>
<code class="n">gears</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"crown"</code><code class="o">),</code> <code class="mi">4</code><code class="o">);</code>
<code class="c1">// create the JTree</code>
<code class="kd">final</code> <code class="n">DefaultTreeModel</code> <code class="n">model</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultTreeModel</code><code class="o">(</code><code class="n">root</code><code class="o">);</code>
<code class="kd">final</code> <code class="n">JTree</code> <code class="n">tree</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JTree</code><code class="o">(</code><code class="n">model</code><code class="o">);</code>
<code class="c1">// create a text field and button to modify the data model</code>
<code class="kd">final</code> <code class="n">JTextField</code> <code class="n">nameField</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JTextField</code><code class="o">(</code><code class="s">"16t"</code><code class="o">);</code>
<code class="kd">final</code> <code class="n">JButton</code> <code class="n">button</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"Add a part"</code><code class="o">);</code>
<code class="n">button</code><code class="o">.</code><code class="na">setEnabled</code><code class="o">(</code><code class="kc">false</code><code class="o">);</code>
<code class="n">button</code><code class="o">.</code><code class="na">addActionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">ActionListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">actionPerformed</code><code class="o">(</code><code class="n">ActionEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">TreePath</code> <code class="n">tp</code> <code class="o">=</code> <code class="n">tree</code><code class="o">.</code><code class="na">getSelectionPath</code><code class="o">();</code>
<code class="n">MutableTreeNode</code> <code class="n">insertNode</code> <code class="o">=</code>
<code class="o">(</code><code class="n">MutableTreeNode</code><code class="o">)</code><code class="n">tp</code><code class="o">.</code><code class="na">getLastPathComponent</code><code class="o">();</code>
<code class="kt">int</code> <code class="n">insertIndex</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code>
<code class="k">if</code> <code class="o">(</code><code class="n">insertNode</code><code class="o">.</code><code class="na">getParent</code><code class="o">()</code> <code class="o">!=</code> <code class="kc">null</code><code class="o">)</code> <code class="o">{</code>
<code class="n">MutableTreeNode</code> <code class="n">parent</code> <code class="o">=</code>
<code class="o">(</code><code class="n">MutableTreeNode</code><code class="o">)</code><code class="n">insertNode</code><code class="o">.</code><code class="na">getParent</code><code class="o">();</code>
<code class="n">insertIndex</code> <code class="o">=</code> <code class="n">parent</code><code class="o">.</code><code class="na">getIndex</code><code class="o">(</code><code class="n">insertNode</code><code class="o">)</code> <code class="o">+</code> <code class="mi">1</code><code class="o">;</code>
<code class="n">insertNode</code> <code class="o">=</code> <code class="n">parent</code><code class="o">;</code>
<code class="o">}</code>
<code class="n">MutableTreeNode</code> <code class="n">node</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">DefaultMutableTreeNode</code><code class="o">(</code><code class="n">nameField</code><code class="o">.</code><code class="na">getText</code><code class="o">());</code>
<code class="n">model</code><code class="o">.</code><code class="na">insertNodeInto</code><code class="o">(</code><code class="n">node</code><code class="o">,</code> <code class="n">insertNode</code><code class="o">,</code> <code class="n">insertIndex</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">});</code>
<code class="n">JPanel</code> <code class="n">addPanel</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JPanel</code><code class="o">(</code><code class="k">new</code> <code class="n">GridLayout</code><code class="o">(</code><code class="mi">2</code><code class="o">,</code> <code class="mi">1</code><code class="o">));</code>
<code class="n">addPanel</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">nameField</code><code class="o">);</code>
<code class="n">addPanel</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">button</code><code class="o">);</code>
<code class="c1">// listen for selections</code>
<code class="n">tree</code><code class="o">.</code><code class="na">addTreeSelectionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">TreeSelectionListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">valueChanged</code><code class="o">(</code><code class="n">TreeSelectionEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">TreePath</code> <code class="n">tp</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getNewLeadSelectionPath</code><code class="o">();</code>
<code class="n">button</code><code class="o">.</code><code class="na">setEnabled</code><code class="o">(</code><code class="n">tp</code> <code class="o">!=</code> <code class="kc">null</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">});</code>
<code class="c1">// create a JFrame to hold the tree</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">"PartsTree v1.0"</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">200</code><code class="o">,</code> <code class="mi">200</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JScrollPane</code><code class="o">(</code><code class="n">tree</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">addPanel</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">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>The example begins by creating a node hierarchy. The root node is
called <code class="literal">Parts</code>. It contains two
subnodes named <code class="literal">Beams</code> and <code class="literal">Gears</code>, as shown:</p><a id="I_18_tt1080"/><pre class="programlisting"> <code class="n">MutableTreeNode</code> <code class="n">root</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Parts"</code><code class="o">);</code>
<code class="n">MutableTreeNode</code> <code class="n">beams</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Beams"</code><code class="o">);</code>
<code class="n">MutableTreeNode</code> <code class="n">gears</code> <code class="o">=</code> <code class="k">new</code> <code class="n">DefaultMutableTreeNode</code><code class="o">(</code><code class="s">"Gears"</code><code class="o">);</code>
<code class="n">root</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="n">beams</code><code class="o">,</code> <code class="mi">0</code><code class="o">);</code>
<code class="n">root</code><code class="o">.</code><code class="na">insert</code><code class="o">(</code><code class="n">gears</code><code class="o">,</code> <code class="mi">1</code><code class="o">);</code></pre><p>The <code class="literal">Beams</code> and <code class="literal">Gears</code> nodes contain a handful of items
each.</p><p>The “Add a part” button inserts a new item into the tree at the
level of the current node, and just after it. You can specify the name
of the new node by typing it in the text field above the button. To
determine where the node should be added, the current selection is first
obtained in the anonymous inner class <code class="literal">ActionListener</code>:</p><a id="I_18_tt1081"/><pre class="programlisting"> <code class="n">TreePath</code> <code class="n">tp</code> <code class="o">=</code> <code class="n">tree</code><code class="o">.</code><code class="na">getSelectionPath</code><code class="o">();</code>
<code class="n">MutableTreeNode</code> <code class="n">insertNode</code> <code class="o">=</code>
<code class="o">(</code><code class="n">MutableTreeNode</code><code class="o">)</code><code class="n">tp</code><code class="o">.</code><code class="na">getLastPathComponent</code><code class="o">();</code></pre><p>The new node should be added to the parent node of the current
node, so it ends up being a sibling of the current node. The only hitch
here is that if the current node is the root node, it won’t have a
parent. If a parent does exist, we determine the index of the currently
selected node, and then add the new node at the next index:</p><a id="I_18_tt1082"/><pre class="programlisting"> <code class="kt">int</code> <code class="n">insertIndex</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code>
<code class="k">if</code> <code class="o">(</code><code class="n">insertNode</code><code class="o">.</code><code class="na">getParent</code><code class="o">()</code> <code class="o">!=</code> <code class="kc">null</code><code class="o">)</code> <code class="o">{</code>
<code class="n">MutableTreeNode</code> <code class="n">parent</code> <code class="o">=</code>
<code class="o">(</code><code class="n">MutableTreeNode</code><code class="o">)</code><code class="n">insertNode</code><code class="o">.</code><code class="na">getParent</code><code class="o">();</code>
<code class="n">insertIndex</code> <code class="o">=</code> <code class="n">parent</code><code class="o">.</code><code class="na">getIndex</code><code class="o">(</code><code class="n">insertNode</code><code class="o">)</code> <code class="o">+</code> <code class="mi">1</code><code class="o">;</code>
<code class="n">insertNode</code> <code class="o">=</code> <code class="n">parent</code><code class="o">;</code>
<code class="o">}</code>
<code class="n">MutableTreeNode</code> <code class="n">node</code> <code class="o">=</code>
<code class="k">new</code> <code class="nf">DefaultMutableTreeNode</code><code class="o">(</code><code class="n">nameField</code><code class="o">.</code><code class="na">getText</code><code class="o">());</code>
<code class="n">model</code><code class="o">.</code><code class="na">insertNodeInto</code><code class="o">(</code><code class="n">node</code><code class="o">,</code> <code class="n">insertNode</code><code class="o">,</code> <code class="n">insertIndex</code><code class="o">);</code></pre><p>You must add the new node to the tree’s data model using <code class="literal">insertNodeInto()</code>—not to the <code class="literal">MutableTableNode</code> itself. The model notifies
the <code class="literal">JTree</code> that it needs to update
itself.</p><p>We have another event handler in this example, one that listens
for tree selection events. Basically, we want to enable our “Add a part”
button only if a current selection exists:</p><a id="I_18_tt1083"/><pre class="programlisting"> <code class="n">tree</code><code class="o">.</code><code class="na">addTreeSelectionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">TreeSelectionListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">valueChanged</code><code class="o">(</code><code class="n">TreeSelectionEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">TreePath</code> <code class="n">tp</code> <code class="o">=</code> <code class="n">e</code><code class="o">.</code><code class="na">getNewLeadSelectionPath</code><code class="o">();</code>
<code class="n">button</code><code class="o">.</code><code class="na">setEnabled</code><code class="o">(</code><code class="n">tp</code> <code class="o">!=</code> <code class="kc">null</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">});</code></pre><p>When you first start this application, the button is disabled. As
soon as you select something, it is enabled, and you can add nodes to
the tree with abandon. If you want to see the button disabled again, you
can unselect everything by holding the Control key and clicking on the
current selection.<a id="I_indexterm18_id802130" class="indexterm"/><a id="I_indexterm18_id802137" class="indexterm"/></p></div></div></body></html>