Next: Practical Usage of Tress Up: Trees JTree Previous: Trees JTree List v. Trees Lists are good for displaying simple lists of information from which the user can make single or multiple selections. A list is inadequate for more complex selections, for example: Selecting items in a structured hierarchy, If you were writing a program containing several general selection topics Each of these topics could be subdivided into many specific subtopics, You would require a list of subtopics for each general topic. These numerous list boxes consume vast amounts of GUI space and would be hard to read and assimilate. Huge amount of code you would be needed to support this also -- For four or five separate lists, you could still manage a scenario like this, but what if you had a hundred general topics? A better solution to this problem is to implement a single control containing all of the lists: Simplified Interface Reduced amount code YOU write.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Next: Practical Usage of Tress Up: Trees JTree Previous: Trees JTree
List v. Trees
Lists are good for displaying simple lists of information from which the user can make single or multiple selections.
A list is inadequate for more complex selections, for example:
Selecting items in a structured hierarchy, If you were writing a program containing several general selection topics Each of these topics could be subdivided into many specific subtopics, You would require a list of subtopics for each general topic. These numerous list boxes consume vast amounts of GUI space and would be
hard to read and assimilate. Huge amount of code you would be needed to support this also -- For four or five
separate lists, you could still manage a scenario like this, but what if you had a hundred general topics?
A better solution to this problem is to implement a single control containing all of the lists:
Simplified Interface Reduced amount code YOU write.
It can nest lists of lists to any depth required. Tree control via a series of collapsible/ expandable branches it can contain. Each of the tree's branches can be divided into successively more specific
branches There is no practical limit to the number of items that each branch can hold, nor to
the nesting of subbranches.
The JTree class is the Swing component that provides these facilities.
Next: Practical Usage of Tress Up: Trees JTree Previous: Trees JTree Dave Marshall 4/14/1999
Next: A basic JTree example Up: Trees JTree Previous: List v. Trees
Novice software users may experience problems working with hierarchical data structures:
If you are designing for a more sophisticated user, this is not an issue. For the average user, try to avoid using a tree control that doesn't already strongly
conform to an existing UI metaphor, Windows/Motif users should be familiar with Trees for managing file directories:
o This may mean using a tree in combination with a list to display lowest level tree nodes (for example, Windows Explorer).
Trees have the unfortunate side effect of encouraging the creation of deep nested structures that become difficult for the user to navigate and manage.
Dave Marshall 4/14/1999
Next: Adding new tree items Up: Trees JTree Previous: Practical Usage of Tress
A basic JTree example
Let us demonstrate a simple creation of a Tree application, TreeExample.java:
we will create a simple tree (Fig ) containing only a few items and having no ability to add or remove items.
we will include a scrollable pane, which will become more important as we add features to our application.
The icons shown in this example are defaults provided by Swing. We do not actually insert an items in the tree. When no specific data model has
been specified, JTree reverts to a default example model which is impractical but useful for this demonstration.
When the program is executed, notice that the tree is initially collapsed down to the root level.
Opening the root expands it, showing the next level of indentation -- Notice the change in icon for the lowest element of the tree.
This is the default operation for the simple tree.
The full code listing for TreeExample.java is as follows:
// Instance attributes used in this exampleprivate JPanel topPanel;private JTree tree;private JScrollPane scrollPane;
// Constructor of main framepublic TreeExample(){
// Set the frame characteristicssetTitle( "Simple Tree Application" );setSize( 300, 100 );setBackground( Color.gray );
// Create a panel to hold all other componentstopPanel = new JPanel();topPanel.setLayout( new BorderLayout() );getContentPane().add( topPanel );
// Create a new tree controltree = new JTree();
// Add the listbox to a scrolling panescrollPane = new JScrollPane();scrollPane.getViewport().add( tree );topPanel.add( scrollPane, BorderLayout.CENTER );
}
// Main entry point for this examplepublic static void main( String args[] ){
// Create an instance of the test applicationTreeExample mainFrame = new TreeExample();mainFrame.setVisible( true );
}}
Dave Marshall 4/14/1999
Next: Custom data models Up: Trees JTree Previous: A basic JTree example
Adding new tree items
Let us now look at some code, AddTreeExample.java that creates our own Tree items:
Adding branches and items to a tree instance involves a bit of additional code.
AddTreeExample.java generates a JTree instance containing all of the cards in a deck of playing cards:
AddTreeExample.java Program Output
The key feature in this application is the use of the DefaultMutableTreeNode class.
The DefaultMutableTreeNode is a general-purpose node item compatible with the Swing graphical tree component.
Each child node is inserted into its parent node using the add() method any child node can itself act as a parent for subsequent child nodes. The root is a special node because it is the ultimate parent of all of the other tree
nodes -- inserted into the tree's data model, an instance of the DefaultTreeModel class.
This is the model that a JTree instance should use, unless a custom data model is used.
The full code listing for AddTreeExample.java is as follows:
// Create a new tree controlDefaultTreeModel treeModel = new
DefaultTreeModel( root );tree = new JTree( treeModel );
// Add the listbox to a scrolling panescrollPane = new JScrollPane();scrollPane.getViewport().add( tree );topPanel.add( scrollPane, BorderLayout.CENTER );
}
// Helper method to write an enitre suit of cards to the// current tree node
public void addAllCard( DefaultMutableTreeNode suit ){
suit.add( new DefaultMutableTreeNode( "Ace" ) );suit.add( new DefaultMutableTreeNode( "Two" ) );suit.add( new DefaultMutableTreeNode( "Three" ) );suit.add( new DefaultMutableTreeNode( "Four" ) );suit.add( new DefaultMutableTreeNode( "Five" ) );suit.add( new DefaultMutableTreeNode( "Six" ) );suit.add( new DefaultMutableTreeNode( "Seven" ) );suit.add( new DefaultMutableTreeNode( "Eight" ) );suit.add( new DefaultMutableTreeNode( "Nine" ) );suit.add( new DefaultMutableTreeNode( "Ten" ) );suit.add( new DefaultMutableTreeNode( "Jack" ) );suit.add( new DefaultMutableTreeNode( "Queen" ) );suit.add( new DefaultMutableTreeNode( "King" ) );
}
// Main entry point for this examplepublic static void main( String args[] ){
// Create an instance of the test applicationAddTreeExample mainFrame = new AddTreeExample();mainFrame.setVisible( true );
}}
Dave Marshall 4/14/1999
Next: Custom rendering Up: Trees JTree Previous: Adding new tree items
Custom data models
The JTree class (like Jlist) supports custom data modeling:
slightly more complex here due to hierarchical nature of a tree
The CustomTreeExample.java example, we will recreate the tree containing the deck of cards. However,
a custom data model is used to manufacture the cards within each suit. The result is an application consisting of approximately the same number of code
lines, but with much better performance, particularly for large data sets. Graphical Appearance to User is the same.
// Create a new tree controlMyDataModel treeModel = new MyDataModel( root );tree = new JTree( treeModel );
// Add the listbox to a scrolling panescrollPane = new JScrollPane();scrollPane.getViewport().add( tree );topPanel.add( scrollPane, BorderLayout.CENTER );
}
public void CreateSuit( DefaultMutableTreeNode root, String suitName )
{DefaultMutableTreeNode itemSuit
= new DefaultMutableTreeNode( suitName );
for( int iCtr = 0; iCtr < 13; iCtr++ )itemSuit.add( new DefaultMutableTreeNode(
"" ) );
root.add( itemSuit );}
// Main entry point for this examplepublic static void main( String args[] ){
// Create an instance of the test applicationCustomTreeExample mainFrame = new CustomTreeExample();mainFrame.setVisible( true );
As in the JList rendering example we have two classes:
RenderTreeExample is almost identical to the main Tree classes shown in previous examples -- it t creates a tree instance and inserts all of the pertinent data. It has one additional line to notify the tree that we will provide a custom renderer.
CustomCellRenderer -- contains the rendering code for this application. o To save time during execution, the class implements a constructor to load
the graphics. o The getTreeCellRendererComponent() method must be provided as a
requirement of the TreeCellRender implementation used by this class is responsible for the actual drawing of tree cells.
In this example, getTreeCellRendererComponent()
determines what it is drawing (based on the text in the specified tree node) and then assigns the correct image to the displayed items.
then sets the correct foreground color, depending on the selection state of the item.
A paint() method is required within the custom rendering class to work around a peculiar feature (yes a BUG) in Swing to set the item background.
// Create a new tree controlDefaultTreeModel treeModel = new
DefaultTreeModel( root );tree = new JTree( treeModel );
// Tell the tree it is being rendered by our application tree.setCellRenderer( new CustomCellRenderer() );
// Add the listbox to a scrolling panescrollPane = new JScrollPane();scrollPane.getViewport().add( tree );topPanel.add( scrollPane, BorderLayout.CENTER );
}
// Helper method to write an enitre suit of cards to the// current tree nodepublic void addAllCard( DefaultMutableTreeNode suit ){
suit.add( new DefaultMutableTreeNode( "Ace" ) );suit.add( new DefaultMutableTreeNode( "Two" ) );suit.add( new DefaultMutableTreeNode( "Three" ) );suit.add( new DefaultMutableTreeNode( "Four" ) );suit.add( new DefaultMutableTreeNode( "Five" ) );suit.add( new DefaultMutableTreeNode( "Six" ) );suit.add( new DefaultMutableTreeNode( "Seven" ) );suit.add( new DefaultMutableTreeNode( "Eight" ) );
suit.add( new DefaultMutableTreeNode( "Nine" ) );suit.add( new DefaultMutableTreeNode( "Ten" ) );suit.add( new DefaultMutableTreeNode( "Jack" ) );suit.add( new DefaultMutableTreeNode( "Queen" ) );suit.add( new DefaultMutableTreeNode( "King" ) );
}
// Main entry point for this examplepublic static void main( String args[] ){
// Create an instance of the test applicationRenderTreeExample mainFrame = new RenderTreeExample();mainFrame.setVisible( true );
// Load the imagesdeckImage = new ImageIcon( "deck.gif" );
suitImages = new ImageIcon[4];suitImages[0] = new ImageIcon( "clubs.gif" );suitImages[1] = new ImageIcon( "diamonds.gif" );suitImages[2] = new ImageIcon( "spades.gif" );suitImages[3] = new ImageIcon( "hearts.gif" );
cardImages = new ImageIcon[13];cardImages[0] = new ImageIcon( "ace.gif" );cardImages[1] = new ImageIcon( "two.gif" );cardImages[2] = new ImageIcon( "three.gif" );cardImages[3] = new ImageIcon( "four.gif" );cardImages[4] = new ImageIcon( "five.gif" );cardImages[5] = new ImageIcon( "six.gif" );cardImages[6] = new ImageIcon( "seven.gif" );cardImages[7] = new ImageIcon( "eight.gif" );cardImages[8] = new ImageIcon( "nine.gif" );cardImages[9] = new ImageIcon( "ten.gif" );cardImages[10] = new ImageIcon( "jack.gif" );
cardImages[11] = new ImageIcon( "queen.gif" );cardImages[12] = new ImageIcon( "king.gif" );
}
public Component getTreeCellRendererComponent( JTree tree,Object value, boolean bSelected,
boolean bExpanded,boolean bLeaf, int
iRow, boolean bHasFocus ){
// Find out which node we are rendering and get its textDefaultMutableTreeNode node =
// This is a hack to paint the background. Normally a JLabel can
// paint its own background, but due to an apparent bug or// limitation in the TreeCellRenderer, the paint method is// required to handle this.public void paint( Graphics g ){
Color bColor;Icon currentI = getIcon();
// Set the correct background colorbColor = bSelected ? SystemColor.textHighlight :
Color.white;g.setColor( bColor );
// Draw a rectangle in the background of the cellg.fillRect( 0, 0, getWidth() - 1, getHeight() - 1 );
super.paint( g );}
}
Next: Editing tree nodes Up: Trees JTree Previous: Custom data models Dave Marshall 4/14/1999
Next: Listening for tree actions Up: Trees JTree Previous: Custom rendering
Editing tree nodes
In a manner similar to custom rendering, we can also perform custom editing of any item in a tree control. JTree supports three techniques for editing tree nodes.
The easiest is to simply call the setEditable(value) method and set the value to be true
In this mode, the tree values are editable using a simple text editor.
The second technique is to create a real custom editor for the tree, and this is what we will do in the EditTreeExample.java example below.
The third technique for tree editing is to replace the DefaultCellEditor() reference in EditTreeExample.java with a class that implements CellEditor. Refer to the online Swing documentation for details about the CellEditor implementation.
Let us now look at the EditTreeExample.java example where we create a tree instance and set the default cell editor to point to a combo box which allows node changes only from the list of selections as shown below:
EditTreeExample.java Output
The full code listing for EditTreeExample.java is given below:
{// Instance attributes used in this exampleprivate JPanel topPanel;private JTree tree;private JScrollPane scrollPane;
// Constructor of main framepublic EditTreeExample(){
// Set the frame characteristicssetTitle( "Editable Tree Application" );setSize( 300, 100 );setBackground( Color.gray );
// Create a panel to hold all other componentstopPanel = new JPanel();topPanel.setLayout( new BorderLayout() );getContentPane().add( topPanel );
// Create a new tree controltree = new JTree();tree.setEditable( true );tree.setShowsRootHandles( false );
// Create a combo box of editing optionsJComboBox box = new JComboBox();box.setMinimumSize( new Dimension( 100, 40 ) );box.addItem( "Swing" );box.addItem( "Java" );box.addItem( "neat" );box.addItem( "funky" );box.addItem( "life" );box.addItem( "awesome" );box.addItem( "cool!" );
// Add a cell editor to the tree tree.setCellEditor( new DefaultCellEditor( box ) );
// Add the listbox to a scrolling panescrollPane = new JScrollPane();scrollPane.getViewport().add( tree );topPanel.add( scrollPane, BorderLayout.CENTER );
}
// Main entry point for this examplepublic static void main( String args[] ){
// Create an instance of the test applicationEditTreeExample mainFrame = new EditTreeExample();mainFrame.setVisible( true );
}}
Dave Marshall 4/14/1999
Next: Listening for tree selections Up: Trees JTree Previous: Editing tree nodes
The program handles user selection events through the provision of the valueChanged() method -- the application extracts the current selection from the user and displays this information in the Java console display
The valueChanged() method contains another Swing class named TreePath. The TreePath class is used to contain and describe all aspects of a path, including
the string it contains and details about its parent and child relationships. For details on the TreePath class, see the Swing online documentation.
class ActionTreeExampleextends JFrameimplements TreeSelectionListener
{// Instance attributes used in this exampleprivate JPanel topPanel;private JTree tree;private JScrollPane scrollPane;
// Constructor of main framepublic ActionTreeExample(){
// Set the frame characteristicssetTitle( "TreeSelectionListener Application" );setSize( 300, 300 );setBackground( Color.gray );
// Create a panel to hold all other componentstopPanel = new JPanel();topPanel.setLayout( new BorderLayout() );getContentPane().add( topPanel );
// Create a new tree controltree = new JTree();
// Add a selection listenertree.addTreeSelectionListener( this );
// Add the listbox to a scrolling panescrollPane = new JScrollPane();scrollPane.getViewport().add( tree );topPanel.add( scrollPane, BorderLayout.CENTER );
}
// Handle tree item selectionspublic void valueChanged( TreeSelectionEvent event ){
if( event.getSource() == tree ){
// Display the full selection pathTreePath path = tree.getSelectionPath();System.out.println( "Selection path=" +
path.toString() );
// Get the text for the last componentSystem.out.println( "Selection="
+ path.getLastPathComponent() );
}}
// Main entry point for this examplepublic static void main( String args[] ){
// Create an instance of the test applicationActionTreeExample mainFrame = new ActionTreeExample();mainFrame.setVisible( true );
}}
Dave Marshall 4/14/1999
Next: Practical Programming of JTrees Up: Listening for tree actions Previous: Listening for tree selections
Listening for tree expansions
Events caused by the user expanding or collapsing a node can be intercepted in a tree object.
The ExpandTreeExample.java example:
implements the same default tree object as in the previous example with an attached expansion listener.
When the user expands a tree branch, the treeExpanded() method is called, which displays the full path of the expanded node.
In a similar fashion, when a node is collapsed, the treeCollapsed() method handles the event.
The full code listing for ExpandTreeExample.java is as follows:
class ExpandTreeExampleextends JFrameimplements TreeExpansionListener
{// Instance attributes used in this exampleprivate JPanel topPanel;private JTree tree;private JScrollPane scrollPane;
// Constructor of main framepublic ExpandTreeExample(){
// Set the frame charac
Next: Hiding the root node Up: Trees JTree Previous: Listening for tree expansions
Practical Programming of JTrees
There are many, more subtle aspects of the JTree component that we have not yet discussed.
These features involve adding simple, one line or two line extensions to your code to effect changes (in some cases, dramatic changes) in the character of the tree control.
Hiding the root node Expanding and collapsing the tree Selecting and deselecting nodes
Dave Marshall 4/14/1999 http://www.cs.cf.ac.uk/Dave/HCI/HCI_Handout_CALLER/node160.html