UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

208 lines (201 loc) 36.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>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>