|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 4
The JTree class encompasses all the moving parts that make up Swing trees. Figure 4 displays a partial class diagram for JTree.
Figure 4. JTree class diagram. Click on thumbnail to view full-size image.
You can easily adapt existing tree structures to JTrees because, like all Swing components, JTree is built on a Model-View-Controller (MVC) architecture. That architecture separates the tree's data from the methods that
manipulate and display the data. As Figure 4's class diagram shows, JTree instances access tree data through a TreeModel interface.
To adapt an existing tree structure to a JTree, you can implement the TreeModel interface and pass an instance of that model to JTree.setModel() like this:
public class MyTreeModel implements javax.swing.tree.TreeModel {
// Map whatever tree structure you want to the TreeModel interface.
}
...
JTree tree = new JTree(new MyTreeModel()); // Create a tree with your new model.
If you look at Figure 4's TreeModel, implementing that interface seems easy. It is for static trees; however, if you want dynamic trees you must support tree
model listeners and fire events at the proper time when the model changes. Neither of those tasks are trivial, so Swing provides
a default tree model—DefaultTreeModel—that takes care of that bookkeeping by maintaining a tree of TreeNodes.
Examine Figure 4 again. Notice that TreeModels deal exclusively in Objects, but DefaultTreeModel deals in TreeNodes. This means that instead of implementing TreeModel directly, you can extend DefaultTreeModel and implement a tree node adapter like this:
public class MyTreeNode extends DefaultMutableTreeNode {
// Map whatever tree strucure you want to the TreeModel interface
}
...
JTree tree = new JTree(new DefaultTreeModel(new MyTreeNode()));
Tree node adapters typically extend DefaultMutableTreeNode because that class implements the grunt work of adding and removing children from a node (methods specified by the MutableTreeNode interface). An instance of that tree node adapter is installed as the root node for the default tree model. Now you just
need to implement MyTreeNode.
The rest of this article discusses the implementation of two tree node adapters, similar to MyTreeNode discussed above: one for Swing components and another for a file browser.
Figure 1's user interface (UI) builder prototype is shown once again in Figure 5 for a single panel containing five buttons.
The buttons are laid out by BorderLayout.
Figure 5. UI builder at startup. Click on thumbnail to view full-size image.
Figure 6. The builder reveals the component tree. Click on thumbnail to view full-size image.
Figure 5 shows the application at startup; Figure 6 shows the application after a user clicks on the show component tree button.
This application's main attraction is the SwingComponentNode class—an adapter that lets Swing components masquerade as tree nodes. That class is listed in Example 1.
import java.awt.Component;
import java.awt.Container;
import javax.swing.JComponent;
import javax.swing.tree.*;
class SwingComponentNode extends DefaultMutableTreeNode
implements ExplorableTreeNode {
private boolean explored = false;
public SwingComponentNode(JComponent swingComponent) {
setUserObject(swingComponent);
}
public boolean getAllowsChildren() { return isContainer(); }
public boolean isLeaf() { return !isContainer(); }
public JComponent getComponent() { return (JComponent)getUserObject(); }
public boolean isContainer() {
return getComponent().getComponentCount() > 0;
}
public String toString() {
return getComponent().toString();
}
public boolean isExplored() {
return explored;
}
public void explore() {
if(!isContainer())
return;
if(!isExplored()) {
Component[] children = getComponent().getComponents();
for(int i=0; i < children.length; ++i)
add(new SwingComponentNode((JComponent)children[i]));
explored = true;
}
}
}
Notice the mapping between Swing components (JComponents) and Swing tree nodes (DefaultMutableTreeNodes). A Swing component has no notion of whether it is a leaf, so JComponent doesn't have an isLeaf() method like DefaultMutableTreeNode. As a result, the SwingComponentNode.isLeaf() method uses JComponent.getComponentCount() to determine if a Swing component is a leaf.
Archived Discussions (Read only)