Trees
Using a JTree can be as simple as saying:
add(new JTree(new Object[] {"this", "that", "other"}));
This displays a primitive tree. The API for trees is vast, however—certainly one of the largest in Swing. It appears that you can do just about anything with trees, but more sophisticated tasks might require quite a bit of research and experimentation.
Fortunately, there is a middle ground provided in the library: the “default” tree components, which generally do what you need. So most of the time you can use these components, and only in special cases will you need to delve in and understand trees more deeply.
The following example uses the “default” tree components to display a tree in an applet. When you press the button, a new subtree is added under the currently selected node (if no node is selected, the root node is used):
//: c14:Trees.java
// Simple Swing tree. Trees can be vastly more complex.
// <applet code=Trees width=250 height=250></applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.tree.*;
import com.bruceeckel.swing.*;
// Takes an array of Strings and makes the first
// element a node and the rest leaves:
class Branch {
private DefaultMutableTreeNode r;
public Branch(String[] data) {
r = new DefaultMutableTreeNode(data[0]);
for(int i = 1; i < data.length; i++)
r.add(new DefaultMutableTreeNode(data[i]));
}
public DefaultMutableTreeNode node() { return r; }
}
public class Trees extends JApplet {
private String[][] data = {
{ "Colors", "Red", "Blue", "Green" },
{ "Flavors", "Tart", "Sweet", "Bland" },
{ "Length", "Short", "Medium", "Long" },
{ "Volume", "High", "Medium", "Low" },
{ "Temperature", "High", "Medium", "Low" },
{ "Intensity", "High", "Medium", "Low" },
};
private static int i = 0;
private DefaultMutableTreeNode root, child, chosen;
private JTree tree;
private DefaultTreeModel model;
public void init() {
Container cp = getContentPane();
root = new DefaultMutableTreeNode("root");
tree = new JTree(root);
// Add it and make it take care of scrolling:
cp.add(new JScrollPane(tree), BorderLayout.CENTER);
// Capture the tree's model:
model =(DefaultTreeModel)tree.getModel();
JButton test = new JButton("Press me");
test.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(i < data.length) {
child = new Branch(data[i++]).node();
// What's the last one you clicked?
chosen = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();
if(chosen == null)
chosen = root;
// The model will create the appropriate event.
// In response, the tree will update itself:
model.insertNodeInto(child, chosen, 0);
// Puts the new node on the chosen node.
}
}
});
// Change the button's colors:
test.setBackground(Color.BLUE);
test.setForeground(Color.WHITE);
JPanel p = new JPanel();
p.add(test);
cp.add(p, BorderLayout.SOUTH);
}
public static void main(String[] args) {
Console.run(new Trees(), 250, 250);
}
} ///:~
The first class, Branch, is a tool to take an array of String and build a DefaultMutableTreeNode with the first String as the root and the rest of the Strings in the array as leaves. Then node( ) can be called to produce the root of this “branch.”
The Trees class contains a two-dimensional array of Strings, from which Branches can be made, and a static int i to count through this array. The DefaultMutableTreeNode objects hold the nodes, but the physical representation on screen is controlled by the JTree and its associated model, the DefaultTreeModel. Note that when the JTree is added to the applet, it is wrapped in a JScrollPane—this is all it takes to provide automatic scrolling.
The JTree is controlled through its model. When you make a change to the model, the model generates an event that causes the JTree to perform any necessary updates to the visible representation of the tree. In init( ), the model is captured by calling getModel( ). When the button is pressed, a new “branch” is created. Then the currently selected component is found (or the root is used if nothing is selected) and the model’s insertNodeInto( ) method does all the work of changing the tree and causing it to be updated.
An example like the preceding one may give you what you need in a tree. However, trees have the power to do just about anything you can imagine—everywhere you see the word “default” in the preceding example, you can substitute your own class to get different behavior. But beware: Almost all of these classes have a large interface, so you could spend a lot of time struggling to understand the intricacies of trees. Despite this, it’s a good design, and the alternatives are usually much worse.