17.1 A Simple Tree


Before we look at the models supporting the JTree class, let's look at a very simple example of a tree built with some of the various L&Fs (Figure 17-1). The javax.swing.DefaultMutableTreeNode class serves as our node class. You don't have to worry about specifically making a node a leaf. If the node has no references to other nodes by the time you display it, it's a leaf.

Figure 17-1. A simple JTree in the Metal, Motif, and Mac L&Fs
figs/swng2.1701.gif

This example works by building up a series of unconnected nodes (using the DefaultMutableTreeNode class) and then connecting them. As long as we stick to the default classes provided with the tree package, we can build a regular model out of our nodes quite quickly. In this example, we build the model based on an empty root node, and then populate the tree by attaching the other nodes to the root or to each other. You can also build the tree first, and then create the model from the root node. Both methods have the same result. With a valid tree model in place, we can make a real JTree object and display it.

// TestTree.java // A simple test to see how we can build a tree and populate it // import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.tree.*; public class TestTree extends JFrame {   JTree tree;   DefaultTreeModel treeModel;   public TestTree( ) {     super("Tree Test Example");     setSize(400, 300);     setDefaultCloseOperation(EXIT_ON_CLOSE);   }   public void init( ) {     // Build up a bunch of TreeNodes. We use DefaultMutableTreeNode because the     // DefaultTreeModel can use it to build a complete tree.     DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");     DefaultMutableTreeNode subroot = new DefaultMutableTreeNode("SubRoot");     DefaultMutableTreeNode leaf1 = new DefaultMutableTreeNode("Leaf 1");     DefaultMutableTreeNode leaf2 = new DefaultMutableTreeNode("Leaf 2");          // Build our tree model starting at the root node, and then make a JTree out     // of it.     treeModel = new DefaultTreeModel(root);     tree = new JTree(treeModel);     // Build the tree up from the nodes we created.     treeModel.insertNodeInto(subroot, root, 0);     // Or, more succinctly:     subroot.add(leaf1);     root.add(leaf2);     // Display it.     getContentPane( ).add(tree, BorderLayout.CENTER);   }   public static void main(String args[]) {     TestTree tt = new TestTree( );     tt.init( );     tt.setVisible(true);   } }

As you can see, the action happens in the init( ) method. We create several nodes using the DefaultMutableTreeNode class. The DefaultTreeModel class provides us with a basis for working with the tree, and we add our nodes to that model. All the trees in this chapter follow the same basic steps gathering nodes, creating a tree, and populating the tree though again, not necessarily in that order. We also look at other things you can do with trees, including how to catch selection events and how to change the presentation of the nodes and leaves.

And just to prove that it's not hard to listen to selections from a tree, Figure 17-2 shows an expanded example that displays the most recently selected item in a JLabel at the bottom of the application.

Figure 17-2. The TestTree program with an active TreeSelectionListener label
figs/swng2.1702.gif

To make this work, we add a listener directly to the JTree object. The listener responds much like a ListSelectionListener, but is slightly modified to handle the specifics of tree selections. (For example, selection intervals may have to cross over an expanded node, and all the nodes under the expanded entry must also be selected.) Even though we allow multiple entries to be selected, we show only the lead entry of the selection to keep output simple. Here's the chunk of code we need to add to the init( ) method in the TestTree class:

    // Create and add our message label for the selection output.     final JLabel messageLabel = new JLabel("Nothing selected.");     add(messageLabel, BorderLayout.SOUTH);     // Add our selection listener and have it report to     // our messageLabel.     tree.addTreeSelectionListener(new TreeSelectionListener( ) {       public void valueChanged(TreeSelectionEvent tse) {         TreePath tp = tse.getNewLeadSelectionPath( );         messageLabel.setText("Selected: " + tp.getLastPathComponent( ));       }     });

Of course, you should be sure to import javax.swing.event.* to access the TreeSelectionListener and TreeSelectionEvent classes.

17.1.1 Tree Terminology

Let's look at a simple tree made up of the letters A-Z, shown in Figure 17-3.

Figure 17-3. A simple tree
figs/swng2.1703.gif

Here are a few definitions of terms used with trees:

Node

Any entry in the tree. A, J, and T are all nodes.

Root

The top-level entry of the tree. A root cannot have a parent, and a tree can have only one root. The root in this example is A.

Child

Any of the nodes attached below a given node. M is a child of G.

Parent

The node attached above a given node. Any typical node has only one parent, and the root of the tree is the only node with no parent. G is the parent of M, and C is the parent of G.

Sibling

Any child of a node's parent. A node is also its own sibling. B's siblings are B, C, and D.

Descendant

Any child, or child of a child, or child of a child of a child, etc. A node is also its own descendant. L, S, W, and X are the descendants of L.

Ancestor

Any parent, or parent's parent, or parent's parent's parent, etc. A node is also its own ancestor. A, D, I, and P are the ancestors of P.

Level

The distance (measured in number of ancestors) from a node to the root node. The biggest level is also called the height or depth of a tree. A's level is 0, while T's level is 4.

Path

A list of nodes leading from one node to another. Typically, a path is from the root to another node.

Row

In a graphical representation of a tree, the mapping of a path to a corresponding row number on the screen. A would always be row 0, while other nodes might map to different rows, depending on which nodes are expanded and which are collapsed. If you think of taking a snapshot of a JTree and converting it to a JList, the row of the entry in the tree would correspond to the index of the entry in the list.

Collapsed

In a visual representation of a tree, a node is "collapsed" if you cannot see any of its children. In our example, none of the nodes are collapsed.

Expanded

In a visual representation of a tree, a node is "expanded" if you can see its children. In our example, all the nodes are expanded. (While you can expand or collapse a leaf, it has no effect, as leaves have no children by definition.)

Visible

A visible node is one that can be seen without expanding any of its parents. In a visual representation of a tree, a node might be offscreen (in a scrollpane, for example) but still be considered visible.

As a quick overview, Figure 17-4 details how the various tree classes work together to display a tree. We'll look at each of these classes in detail. JTrees use TreeCellRenderers to graphically display a tree represented by a TreeModel. TreeModels encode a tree using TreeNodes that contain an Object (your data for that node) and possibly references to other TreeNodes. Once displayed, the nodes of the tree can be selected according to the rules of a TreeSelectionModel. If supported, you can edit any one of the nodes in the tree using a TreeCellEditor.

Figure 17-4. JTree class diagram
figs/swng2.1704.gif


Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net