|
|
The TreeTest class implements the TreeSelectionListener interface and is added as a listener to the tree contained in the center of the application. This enables the valueChanged method to be called whenever the selection in the tree changes. Unlike some of the other events in the JFC, the TreeSelectionEvent instance delivered to this method contains the information about the change in the selected path set for the tree. In this application, the paths contained in the event are written to the JTextArea instance in the right region of the display. The array of changed TreePaths is queried from the event with the getPaths method. For each path, the isAddedPath method can be called to determine if the path was added or removed from the trees selection set. The method returns true for new paths and false for paths that were selected but are no longer selected. Each path is written to the text area. The final piece of information obtained in the valueChanged method is the user object for the node. This points to an unfortunate flaw in the MutableTreeNode interface. It does not contain a getUserObject method. This forces the valueChanged method to test for the DefaultMutableTreeNode class, making this code unusable for other classes that implement the MutableTreeNode interface. This is a serious flaw in the JFC tree and greatly reduces the ability to write reusable code.
A setEditable method is passed a parameter of true to allow the tree to be edited in place. When a tree is made editable, any node in the tree can be edited. The gesture that starts the edit is look-and-feel specific. However, the single-click gesture is used in the current JFC look-and-feel implementations. For the TestTree, it is desirable to allow only leaf nodes to be editable. A custom cell editor provides this functionality for the tree. The setCellEditor method specifies an instance of the TreeLeafEditor class shown in Listing 11.9. This will be used as the editor for the tree. This class is an extension of the DefaultCellEditor class. It overrides the isCellEditable method. This method demonstrates how a TreePath to a node can be queried from a tree for given x and y coordinates. By using the isLeaf method, the cell editor then checks if the hit node is a leaf node and only returns true if it is. The tree with the TreeLeafEditor activated is shown in Figure 11.6.
Listing 11.9 The TreeLeafEditor Class
package com.foley.utility;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
/**
* A tree editor that only allows editing of leaf nodes.
* <p>
* @author Mike Foley
**/
public class TreeLeafEditor extends DefaultCellEditor {
/**
* The tree we are editing.
**/
JTree tree;
public TreeLeafEditor( JTree tree ) {
super( new JTextField() );
this.tree = tree;
}
/**
* The cell is only editable if it is a leaf node and
* the number of mouse clicks is equal to the value
* returned from the getClickCountToStart method.
* <p>
* @param event The event to test for cell editablity.
* @return True if the cell is editable given the current event.
* @see getClickCountToStart
**/
public boolean isCellEditable( EventObject event ) {
if( event instanceof MouseEvent ) {
MouseEvent mouseEvent = ( MouseEvent )event;
if( mouseEvent.getClickCount() == getClickCountToStart() ) {
TreePath hitPath = tree.getPathForLocation(
mouseEvent.getX(),
mouseEvent.getY() );
Object hitObject = hitPath.getLastPathComponent();
if( hitObject instanceof TreeNode )
return( ( ( TreeNode )hitObject ).isLeaf() );
}
}
return( false );
}
} // TreeLeafEditor
Figure 11.6 Node being edited in the TreeTest application.
The application creates a button that causes a selected node in the tree to totally expand the sub-tree for which it serves as the root. Thus, if this button is hit when the root of the tree is selected, the entire tree is expanded displaying all the leaf nodes contained in the tree. The expansion is performed in the expandChildren method that requires a TreeNode parameter. The TreeNode passed to the method serves as the root node of the sub-tree that is expanded. The method works by checking to see if the node passed to it is a leaf. If so, a path to the node is created and expanded in the tree. If the node is not a leaf, the makeVisible method found in the JTree class is called for each child of the node. This logic is repeated for each child of the original node, and its children, and so on, until the entire sub-tree data structure has been traversed. It is important to understand that only the leaf nodes need to be expanded. This is because the path to the leaf contains its parent. Thus, if all leaves are expanded, the entire sub-tree has been expanded. You will find yourself writing many recursive methods, such as the expandChild method, when traversing the nodes in a tree.
|