Introduction to Java Programming-Comprehensive Version (6th Edition)
31.8. JTree
JTree is a Swing component that displays data in a treelike hierarchy, as shown in Figure 31.16.
Figure 31.16. JTree displays data in a treelike hierarchy.
All the nodes displayed in the tree are in the form of a hierarchical indexed list. The tree can be used to navigate structured data with hierarchical relationships. A node can have child nodes. A node is called a leaf if it has no children; a node with no parent is called the root of its tree. A tree may consist of many subtrees, each node acting as the root for its own subtree .
A nonleaf node can be expanded or collapsed by double-clicking on the node or on the node's handle in front of the node. The handle usually has a visible sign to indicate whether the node is expanded or collapsed. For example, on Windows, the + symbol indicates that the node can be expanded, and the - symbol, that it can be collapsed .
Like JTable , JTree is a very complex component with many supporting interfaces and classes. JTree is in the javax.swing package, but its supporting interfaces and classes are all included in the javax.swing.tree package. The supporting interfaces are TreeModel , TreeSelectionModel , TreeNode , and MutableTreeNode , and the supported classes are DefaultTreeModel , DefaultMutableTreeNode , DefaultTreeCellEditor , DefaultTreeCellRenderer , and TreePath .
While JTree displays the tree, the data representation of the tree is handled by TreeModel , TreeNode , and TreePath . TreeModel represents the entire tree, TreeNode represents a node, and TreePath represents a path to a node. Unlike the ListModel or TableModel , TreeModel does not directly store or manage tree data. Tree data is stored and managed in TreeNode and TreePath . DefaultTreeModel is a concrete implementation of TreeModel . MutableTreeNode is a subinterface of TreeNode , which represents a tree node that can be mutated by adding or removing child nodes, or by changing the contents of a user object stored in the node.
The TreeSelectionModel interface handles tree node selection. The DefaultTreeCellRenderer class provides a default tree node renderer that can display a label and/or an icon in a node. The DefaultTreeCellEditor can be used to edit the cells in a text field.
A TreePath is an array of Object s that are vended from a TreeModel . The elements of the array are ordered such that the root is always the first element (index 0) of the array. Figure 31.17 shows how these interfaces and classes are interrelated.
Figure 31.17. JTree contains many supporting interfaces and classes.
Figure 31.18 shows the constructors, frequently used properties, and methods of JTree .
Figure 31.18. The JTree class is for creating, customizing, and manipulating trees.
(This item is displayed on page 1070 in the print version)
The JTree class contains seven constructors for creating trees. You can create a tree using its no-arg constructor, a tree model, a tree node, a Hashtable , an array, or a vector. Using the no-arg constructor, a sample tree is created as shown in Figure 31.16. Using a Hashtable , an array, or a vector, a root is created but not displayed. All the keys in a Hashtable , all the objects in an array, and all the elements in a vector are added into the tree as children of the root. If you wish the root to be displayed, set the rootVisible property to true .
All the methods related to path selection are also defined in the TreeSelectionModel interface, which will be covered in §31.11, " TreePath and TreeSelectionModel ."
Listing 31.11 gives an example that creates four trees: a default tree using the no-arg constructor, a tree created from an array of objects, a tree created from a vector, and a tree created from a hash table, as shown in Figure 31.19. Enable the user to dynamically set the properties for rootVisible , rowHeight , and showsRootHandles .
Figure 31.19. You can dynamically set the properties for rootVisible , rowHeight , and showRootHandles in a tree.
(This item is displayed on page 1072 in the print version)
Listing 31.11. SimpleTreeDemo.java
(This item is displayed on pages 1070 - 1072 in the print version)
1 import java.awt.*; 2 import java.awt.event.*; 3 import javax.swing.*; 4 import javax.swing.event.*; 5 import java.util.*; 6 7 public class SimpleTreeDemo extends JApplet { 8 // Create a default tree 9 private JTree jTree1 = new JTree(); 10 11 // Create a tree with an array of Objects. 12 private JTree jTree2 = new JTree( new String[] 13 { "dog" , "cow" , "cat" , "pig" , "rabbit" }); 14 15 // Create a tree with a Hashtable 16 private Vector vector = new Vector(Arrays.asList( 17 new Object[]{ "red" , "green" , "black" , "white" , "purple" })); 18 private JTree jTree3 = new JTree(vector); 19 20 private Hashtable<Integer, String> hashtable = 21 new Hashtable<Integer, String>(); 22 private JTree jTree4; 23 24 // Create a combo box for selecting rootVisible 25 private JComboBox jcboRootVisible = new JComboBox( 26 new String[]{ "false" , "true" }); 27 28 // Create a combo box for selecting showRootHandles 29 private JComboBox jcboShowsRootHandles = new JComboBox( 30 new String[] { "false" , "true" }); 31 32 // Create a spinner for selecting row height 33 private JSpinner jSpinnerRowHeight = new JSpinner( 34 new SpinnerNumberModel( 16 , 1 , 50 , 1 )); 35 36 public SimpleTreeDemo() { 37 jTree1.setRootVisible( false ); 38 39 hashtable.put( 1 , "red" ); 40 hashtable.put( 2 , "green" ); 41 hashtable.put( 3 , "blue" ); 42 hashtable.put( 4 , "yellow" ); 43 jTree4 = new JTree(hashtable); 44 45 JPanel panel1 = new JPanel( new GridLayout( 1 , 4 )); 46 panel1.add( new JScrollPane(jTree1) ); 47 panel1.add( new JScrollPane(jTree2)); 48 panel1.add( new JScrollPane(jTree3)); 49 panel1.add( new JScrollPane(jTree4)); 50 51 JPanel panel2 = new JPanel(); 52 panel2.add( new JLabel( "rootVisible" )); 53 panel2.add(jcboRootVisible); 54 panel2.add( new JLabel( "rowHeight" )); 55 panel2.add(jSpinnerRowHeight); 56 panel2.add( new JLabel( "showsRootHandles" )); 57 panel2.add(jcboShowsRootHandles); 58 59 add(panel1, BorderLayout.CENTER); 60 add(panel2, BorderLayout.SOUTH); 61 62 // Register listeners 63 jcboRootVisible.addActionListener( new ActionListener() { 64 public void actionPerformed(ActionEvent e) { 65 boolean rootVisible = 66 jcboRootVisible.getSelectedItem().equals( "true" ); 67 jTree1.setRootVisible(rootVisible); 68 jTree2.setRootVisible(rootVisible); 69 jTree3.setRootVisible(rootVisible); 70 jTree4.setRootVisible(rootVisible); 71 } 72 }); 73 74 jcboShowsRootHandles.addActionListener( new ActionListener() { 75 public void actionPerformed(ActionEvent e) { 76 boolean showsRootHandles = 77 jcboShowsRootHandles.getSelectedItem().equals( "true" ); 78 jTree1.setShowsRootHandles(showsRootHandles); 79 jTree2.setShowsRootHandles(showsRootHandles); 80 jTree3.setShowsRootHandles(showsRootHandles); 81 jTree4.setShowsRootHandles(showsRootHandles); 82 } 83 }); 84 85 jSpinnerRowHeight.addChangeListener( new ChangeListener() { 86 public void stateChanged(ChangeEvent e) { 87 int height = 88 ((Integer)(jSpinnerRowHeight.getValue())).intValue(); 89 jTree1.setRowHeight(height); 90 jTree2.setRowHeight(height); 91 jTree3.setRowHeight(height); 92 jTree4.setRowHeight(height); 93 } 94 }); 95 } 96 }
|
Four trees are created in this example. The first is created using the no-arg constructor (line 9) with a sample tree. The second is created using an array of objects (lines 12 “13). All the objects in the array become the children of the root. The third is created using a vector (lines 16 “18). All the elements in the vector become the children of the root. The fourth is created using a hash table (lines 39 “43). A Hashtable is like a Map . Hashtable was introduced earlier than Java 2 and has since been replaced by Map . It is used in the Java API (e.g., JTree ), which was developed before Java 2. The keys of the hash table become the children of the root.
JTree doesn't directly support scrolling. To create a scrollable tree, create a JScrollPane and add an instance of JTree to the scroll pane (lines 46 “49).
The example enables you to specify whether the root is visible and whether the root handles are visible from two combo boxes (lines 63 “83). It also lets you specify the row height of the node in a spinner (lines 85 “94).