Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Get a Better Job. Enterprise Careers on InfoWorld
Get a Better Job. Enterprise Careers on InfoWorld
ITKnowledge
Search this book:
 
Search the site:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


Pulling It All Together: A Complete JTree Example

The previous sections have presented the interfaces and classes that are required to take full advantage of the JTree class. This section will present an example that uses these classes to create a complete tree example application.

The TreeTest application in Listing 11.8 creates a JTree instance and displays it in an ApplicationFrame. The resulting application is shown in Figure 11.5. The tree’s data model is created in the createTreeModel method. An instance of the DefaultMutableTreeNode class is created for each node in the tree. The user object for the node is passed to the constructor. In this example, the user object is the String that represents the name of the node. However, any Object can be used as the user object. By default, the toString method on the user object is called to query the String that represents the node in the tree.


Figure 11.5  The TreeTest application.

The structure of the tree is determined by calling the add method on the parent node and passing the child node as the parameter to this method. The child node must be an instance that implements the MutableTreeNode interface. The add method works similarly to the add methods you saw for menus in Chapter 9, "Menus and Toolbars." The new node is placed as the last child of the parent node. When the parent is expanded, the children are shown in the order they were added to the node. The add method it is not defined in the MutableTreeNode interface, but is part of the DefaultMutableTreeNode class’s public API.

The placement of a node added to its parent can be specified if added by using the insert method. This method requires the index where the child is added into the parent node. The createTreeModel method finishes by creating an instance of the DefaultTreeModel class. The root node for the tree is passed to the constructor to bind the model to the tree nodes.

The visual components are instantiated and arranged in the createTreePanel method. A split pane is created for the center of the application. The JSplitPane class is presented in Chapter 16, "Split Pane." An instance of the JTree class is created by using the model returned from the createTreeModel method as its data model. This tree is added as the left component in the split pane. A JTextArea is created and added to the right region of the split pane. The selected nodes in the tree will be displayed in this area. A panel with a BorderLayout is created, and the split pane is added as the center region of this panel. A panel containing buttons is placed in the south region of this panel. One button expands the selected node in the tree and all its children. The other button clears the text in the JTextArea instance. Finally, a TreeSelectionListener is added to the tree. This will enable the valueChanged method to be called whenever the selection in the tree changes. The panel containing the split pane and button panel is returned from the createTreePanel method and set as the content pane of the ApplicationFrame instance.

Listing 11.8 The TreeTest Application

package com.foley.test;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.border.*;
import com.foley.utility.ApplicationFrame;

/**
 * An application that displays a JTree.
 *
 * @author Mike Foley
 **/
public class TreeTest
    implements ActionListener, TreeSelectionListener {

    /**
     * The tree used in the center of the display.
     **/
    JTree tree;

    /**
     * The component where the selected path is displayed.
     **/
    JTextArea textArea;

    /**
     * The text contained in the JTextArea initially and after a clear.
     **/
    private static final String INITIAL_TEXT = "Selected Path Events\n";

    /**
     * Create the tree test component.
     * The display is a tree in the center of a BorderLayout.
     * The EAST region contains a JTextArea where selected
     * paths are displayed.
     * The bottom region contains buttons.
     * <p>
     * @return The component containing the tree.
     **/
    public JComponent createTreePanel() {

        JSplitPane treePanel = new JSplitPane();

        tree = new JTree( createTreeModel() );
        tree.setEditable( true );
        tree.setCellEditor( new TreeLeafEditor( tree ) );
        tree.addTreeSelectionListener( this );
        tree.setBorder( BorderFactory.createLoweredBevelBorder() );

        treePanel.setLeftComponent( new JScrollPane( tree ) );

        JPanel buttonPanel = new JPanel();
        JButton expand = new JButton( "Expand Selected" );
        expand.addActionListener( this );
        JButton clear = new JButton( "Clear Path Display" );
        clear.addActionListener( new ActionListener() {
            public void actionPerformed( ActionEvent event ) {
                textArea.setText( INITIAL_TEXT );
            }
        } );
        buttonPanel.add( expand );
        buttonPanel.add( clear );

        textArea = new JTextArea( INITIAL_TEXT, 16, 50 );
        textArea.setBackground( expand.getBackground() );
        textArea.setBorder( null );
textArea.setBorder( BorderFactory.createEmptyBorder(4,4,4,4) );
        treePanel.setRightComponent( new JScrollPane( textArea ) );

        JPanel totalPanel = new JPanel();
        totalPanel.setLayout( new BorderLayout() );
        totalPanel.add( treePanel, BorderLayout.CENTER );
        totalPanel.add( buttonPanel, BorderLayout.SOUTH );
        totalPanel.setBorder( BorderFactory.createLoweredBevelBorder() );

        return( totalPanel );

    }

    /**
     * Create the data model used in the tree contained
     * in the application.
     * <p>
     * @return The data model for the tree.
     **/
    protected TreeModel createTreeModel() {
        DefaultMutableTreeNode root =
                     new DefaultMutableTreeNode( "Music Collection" );

        DefaultMutableTreeNode albums =
                     new DefaultMutableTreeNode( "Albums" );
        DefaultMutableTreeNode cds = new DefaultMutableTreeNode( "CDs" );
        DefaultMutableTreeNode tapes =
                     new DefaultMutableTreeNode( "Tapes" );

        root.add( albums );
        root.add( cds );
        root.add( tapes );

        DefaultMutableTreeNode stonesAlbums =
                  new DefaultMutableTreeNode( "Rolling Stones" );
        albums.add( stonesAlbums );
        stonesAlbums.add( new DefaultMutableTreeNode( "Hot Rocks" ) );
        stonesAlbums.add(
              new DefaultMutableTreeNode( "Black and Blue" ) );
        stonesAlbums.add(
              new DefaultMutableTreeNode( "Sticky Finger" ) );

        DefaultMutableTreeNode c1 =
               new DefaultMutableTreeNode( "Classical" );
        DefaultMutableTreeNode c2 =
               new DefaultMutableTreeNode( "Best Rock of the 60s" );
        DefaultMutableTreeNode c3 =
               new DefaultMutableTreeNode( "70s Disco Favorites" );
        DefaultMutableTreeNode c4 =
                new DefaultMutableTreeNode( "Broadway Hits" );
        DefaultMutableTreeNode c5 =
                new DefaultMutableTreeNode( "Country’s Best?" );

        cds.add( c1 );
        cds.add( c2 );
        cds.add( c3 );
        cds.add( c4 );
        cds.add( c5 );

        DefaultMutableTreeNode s1 =
           new DefaultMutableTreeNode( "Rolling Stones" );
        DefaultMutableTreeNode s2 =
           new DefaultMutableTreeNode( "Beatles" );
        DefaultMutableTreeNode s3 =
           new DefaultMutableTreeNode( "The Who" );

        c1.add( new DefaultMutableTreeNode( "Beethoven’s Fifth" ) );

        c2.add( s1 );
        c2.add( s2 );
        c2.add( s3 );

        s1.add( new DefaultMutableTreeNode( "Gimmie Shelter" ) );
        s1.add( new DefaultMutableTreeNode( "Some Girls" ) );
        s1.add( new DefaultMutableTreeNode( "Emotional Rescue" ) );
s2.add( new DefaultMutableTreeNode( "White Album" ) );
        s2.add( new DefaultMutableTreeNode( "Abby Road" ) );
        s2.add( new DefaultMutableTreeNode( "Let it be" ) );

        s3.add( new DefaultMutableTreeNode( "Tommy" ) );
        s3.add( new DefaultMutableTreeNode( "The Who" ) );

        c3.add( new DefaultMutableTreeNode( "Saturday Night Fever" ) );
        c3.add( new DefaultMutableTreeNode( "Earth Wind and Fire" ) );

        c4.add( new DefaultMutableTreeNode( "Cats Soundtrack" ) );
        c5.add( new DefaultMutableTreeNode( "Unknown" ) );

        return( new DefaultTreeModel( root ) );

    } // createTreeModel

    /**
     * actionEvent, from ActionListener.
     * <p>
     * The expand button was pressed. Expand the selected paths
     * in the tree.
     * <p>
     * @param event The actionEvent causing this method call.
     **/
    public void actionPerformed( ActionEvent event ) {
        TreePath[] paths = tree.getSelectionPaths();
        if( paths != null ) {
            for( int i = 0; i < paths.length; i++ ) {
                expandPath( paths[i] );
            }
        }
    }

    /**
     * valueChanged, from TreeSelectionListener.
     * <p>
     * The selected state in the tree changed. Show the
     * selected path in the text area.
     * <p>
     * @param event The event causing this method to be called.
     **/
    public void valueChanged( TreeSelectionEvent event ) {

        TreePath[] paths = event.getPaths();

        for( int i = 0; i < paths.length; i++ ) {
            //
            // Display the path and state.
            //
            Object[] path = paths[i].getPath();
            textArea.append( event.isAddedPath( paths[i] ) ?
                                "ADDED: " : "REMOVED: " );
            textArea.append( paths[i] + "\n" );
            for( int j = 0; j < path.length; j++ ) {
                textArea.append( "\t" + path[j] + "\n" );
            }
            if( event.isAddedPath( paths[i] ) ) {
                Object pathObject = paths[i].getLastPathComponent();

                //
                // This test is unfortunate. The MutableTreeNode
                // interface does not have a getUserObject method, so
                // we must test for a specific implementation.
                //
                if( pathObject instanceof DefaultMutableTreeNode ) {
                    Object userObject =
               ( ( DefaultMutableTreeNode )pathObject ).getUserObject();
                    textArea.append("User Object: " + userObject + "\n");
                }
            }
        }
        textArea.append( "-------------------------------------\n" );

    }

    /**
     * Expand the node at the end of the given path.
     * This requires expanding all children nodes of the
     * path recursively until the entire subtree has been
     * expanded.
     **/
    private void expandPath( TreePath path ) {
        Object o = path.getLastPathComponent();
        if( o instanceof TreeNode ) {
            for( Enumeration e = ( ( TreeNode )o ).children();
           e.hasMoreElements(); ) {
                TreeNode node = ( TreeNode )e.nextElement();
                expandChildren( node );
            }
        }
    }
    /**
     * Expand all the children of the given node.
     * <p>
     * @param expandNode The root of the subtree to expand.
     **/
    private void expandChildren( TreeNode expandNode ) {

        if( expandNode.isLeaf() ) {

            Stack nodes = new Stack();

            //
            // Push the parents of the current node
            // until the root of the tree is reached.
            //
            TreeNode node = expandNode;
            nodes.push( node );
            while( ( node = node.getParent() ) != null )
                nodes.push( node );

            //
            // Create a path to the node passed into this
            // method by popping each element from the stack.
            //
            TreeNode[] path = new TreeNode[ nodes.size() ];
            for( int i = 0; i < path.length; i++ )
                path[i] = ( TreeNode )nodes.pop();
            TreePath treePath = new TreePath( path );

            //
            // Expand the path.
            //
            tree.makeVisible( treePath );

        } else {

            //
            // Expand the children of the
            // node passed to the method.
            //
            for( Enumeration e = expandNode.children();
           e.hasMoreElements(); ) {
                expandChildren(
          ( DefaultMutableTreeNode )e.nextElement() );
            }

        } // else

    } // expandChildren

    /**
     * Application entry point.
     * Create the frame, and place a tree into it.
     *
     * @param args Command line parameter. Not used.
     **/
    public static void main( String args[] ) {

        TreeTest treeTest = new TreeTest();
        JFrame frame = new ApplicationFrame( "Tree Test" );
        frame.getContentPane().add( treeTest.createTreePanel(),
                                    BorderLayout.CENTER );
        frame.pack();
        frame.setVisible( true );

    } // main

} // TreeTest


Previous Table of Contents Next
HomeAbout UsSearchSubscribeAdvertising InfoContact UsFAQs
Use of this site is subject to certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.