[an error occurred while processing this directive]

Page One
Page Two
The Databank
What Is Swing?
Special Report
IDE Roundup
Swing and the Web
Swing Text
Tech Topics
Friends
Tips and Tricks
The PLAF Papers
Call 911
The Archive
JFC Home
Download Swing
Swing API Docs
Download JDK
JDK Docs
Java Tutorial
 
The Swing Connection Tech Topics

Creating TreeTables: Part 2
Completing the Example Program


This article builds on the JTreeTable example that was introduced in "Creating TreeTables in Swing,"  the previous article in this section. Before reading this article, please read the previous one.


By Scott Violet and Kathy Walrath

tree_table_thumb_wideFor the sake of simplicity, the example program presented in "Creating TreeTables in Swing" was a bare-bones program with a few shortcomings. This article presents an expanded and enhanced example program, renamed TreeTable II,  that fixes the shortcomings of the original example and adds a few new features of its own.

In the Source Code section of this article, you´ll get a chance to view the rest of the program´s code. You´ll also get an opportunity to download a zipped version of the complete program and its resources.

This article has three major sections:

What´s New in TreeTable II

In last month´s issue of The Swing Connection, the "Creating TreeTables in Swing" article showed how to create a combination of a Tree and a Table -- a component capable of both expanding and contracting rows, as well as showing multiple columns of data. The article concluded with a example application, named TreeTableExample0, which displayed a working TreeTable browser that you can use to browse a local file system

As you can see by examining the JTreeTable.java file, this article´s version of the JTreeTable class is much improved over the version of the same class presented in "Creating TreeTables in Swing." Before, colors and row heights weren't consistent between the tree and the table. Also, keyboard navigation was awkward. Two other shortcomings, which weren't noticeable due to the previous example's simplicity, were that the tree's selection model didn't track changes properly and the GUI wouldn't be updated if the tree data changed.

We substantially changed the behavior of the example to show off the capabilities of new, improved JTreeTable. TreeTable II behaves rather like the UNIX command du, or the NEXTSTEP example DarkForest. The basic functionality changes are that the size of a directory is now the total size of all its children, and you can update the size data and inspect multiple directory hierarchies. We also added the ability to change the look and feel while TreeTable II is running.

Another difference from the previous source code is that we now use the new Swing package structure (javax.swing, rather than com.sun.java.swing). You can run the example with either JDK 1.2 (RC1 or a compatible release) or with JDK 1.1 + JFC 1.1 (Swing 1.1 Beta 3 or a compatible version).

Here are the fixes we added to overcome shortcomings of the previous example:

Here are the features we added to implement new functionality:



Coordinating colors and row height

To coordinate colors and row height, we overrode two methods (updateUI and setRowHeight) in both the JTree subclass (JTreeTable.TreeTableCellRenderer) and the JTable subclass (JTreeTable). The code in the updateUI methods makes the table use the tree's default foreground and background colors, and the tree use the table's selection colors. The setRowHeight methods ensure that when the row height of the tree or table is changed, the row height of the other object (table or tree) is changed to be exactly the same.



Improving keyboard navigation

In the previous version, the tree could get the keyboard focus. Once it did, the tree handled all key events. This gave an odd feeling in that you could not tab out of the tree to select other cells in the table, nor use the left/right arrow keys as you normally could in a table.

In the new version, the TableCellEditor's isCellEditable method always returns false, so the tree never gets the focus. If the argument to isCellEditable is a MouseEvent, then isCellEditable forwards the mouse event to the tree. This lets the tree handle the mouse event as it normally would, without ever having focus. This change fixes the focus problem, and as a side effect enables autoscrolling to the new selection.



Updating the table in response to tree events

As the previous article explained, TreeTableModelAdapter is used to share the TreeTableModel (the table's data model) between the JTree and JTable. The previous version of TreeTableModelAdapter did not implement TreeModelListener, which meant that changes in the TreeTableModel would not be propagated to the UI. This didn't matter in the previous example, since the tree's contents didn't change after the tree was visible.

The current version of TreeTableModelAdapter registers a TreeModelListener on the TreeTableModel. The listener's methods fire TableModelEvents so that the UI will update when the tree is updated. This enables TreeTable II's Reload feature.



Making the tree track the visible selection

In the previous version, the JTable referenced the ListSelectionModel from the DefaultTreeSelectionModel. As DefaultTreeSelectionModel does not listen for changes in its ListSelectionModel, this could result in an inconsistent state. The ListSelectionModel would have one thing selected and the TreeSelectionModel would reference another set of paths as being selected.

This version defines a new subclass of DefaultTreeSelectionModel, called JTreeTable.ListToTreeSelectionModelWrapper, that listens for changes in its ListSelectionModel. When the ListSelectionModel changes, JTreeTable.ListToTreeSelectionModelWrapper updates its paths so that the two models remain in sync. This didn't matter in the previous example, since no code queried the tree for its selection state. Implementing this feature enables detecting the selected tree paths, which is necessary for commands such as Reload that work on the current selection.



Reloading data

By selecting a directory and then choosing the File > Reload menu item, you cause that directory to be rechecked.

Links, by default, aren't initially descended. To load the contents of a link, select the link and then choose the Reload menu item.



Inspecting a new root directory

With the File > Open command, you bring up a file chooser from which you can choose a directory. A new frame appears that shows a tree-table that has the specified directory as its root.



Dynamically changing the look and feel

By choosing any of the menu items in the Options menu, you can dynamically change the look and feel. You have the choice of three look-and-feel options: Metal (the Java Look and Feel), CDE/Motif Look and Feel, and Windows Look and Feel (which works only on computers that normally use the corresonding look and feel).

Note that if you're using Swing with JDK 1.1, you must be sure that the appropriate look-and-feel archive files are in the class path. For example, if you might use the CDE/Motif Look and Feel, then the class path must include motif.jar. For the Windows Look and Feel, the class path must include windows.jar. The Java Look and Feel (Metal) is already included in swing.jar.



Dynamically sorting rows

When all the children of the topmost directory have been loaded, they are sorted again by total size. This sorting generates a TreeStructureChange event, which has the effect of causing any expanded children of the topmost directory to collapse.



Using a background thread

To avoid freezing the UI, calculating the total size is done in a background thread. Because Swing is not thread safe, data-ready notifications (accomplished by firing TreeModelEvents) can't be done in the background thread. Instead, TreeTable II uses the SwingUtilities.invokeLater() method to make the event-firing code be executed in the event dispatch thread.

A new background thread is used for each data-loading cycle. First, all of the children of the tree's root are loaded and made available. Then a new thread is spawned that recursively loads the descendants of each child of the tree's root directory. Each time all the descendants of one of the tree root's children have been loaded, a TreeModelEvent is generated.



Source Code

The list of files for TreeTable II is almost the same as for the old example. The differences are that FileSystemModel.java has been renamed to FileSystemModel2.java to reflect its drastically different implementation, and TreeTableExample0.java has been renamed to TreeTableExample2.java. Here are the source files for the new example:

src.zip

    Contains all of the TreeTable II source files.

AbstractCellEditor.java

    No significant changes. A subclass of CellEditorapi that handles the list of listeners, providing a base class for cell editors.

AbstractTreeTableModel.java

    No significant changes. Provides a base class for TreeTableModels; handles the list of listeners.

FileSystemModel2.java

    Now implements sorting, getting total size of directories, and background thread. FileSystemModel2 extends AbstractTreeTableModel.

JTreeTable.java

    Changed to improve selection coordination between tree and table, use a better row height, use better colors, support switching the look and feel, and improve navigability. Includes these classes:

    • JTreeTable (extends JTableapi)
       
    • JTreeTable.TreeTableCellRenderer (extends JTreeapi)
       
    • JTreeTable.TreeTableCellEditor (extends AbstractCellEditor implements TableCellEditorapi)
       
    • JTreeTable.ListToTreeSelectionModelWrapper (extends DefaultTreeSelectionModelapi)

MergeSort.java

No significant changes. Implements a sorting algorithm.

TreeTableExample2.java

Modified as necessary to create the new GUI and hook everything together. Contains the main method that creates and runs the TreeTable II example.

TreeTableModel.java

No significant changes. A TreeModelapi subinterface that describes the kind of data that can be drawn by a TreeTable.

TreeTableModelAdapter.java

Now installs a TreeModelListenerapi to fire events to the table after the tree has been updated. TreeTableModelAdapter implements the TableModelapi interface, given both a TreeTableModel and a JTree.
 

 

Compiling and Running the Example

You can compile and run TreeTable II using either JDK 1.2 or JDK 1.1 plus JFC 1.1 (with Swing 1.1 Beta 3 or a compatible release). As long as the release uses the javax.swing names for the Swing packages (as opposed to com.sun.java.swing), it should work with this example.

When running the TreeTable II, you can provide a single command-line argument. This argument specifies the topmost directory for which size calculations should be generated. This directory is the root of the tree displayed by TreeTable II. If you don't specify an argument, then TreeTable II uses the user's home directory as the root of the tree.

The following examples show how to run TreeTable II, both with JDK 1.1 and JDK 1.2, and on UNIX and Win32 platforms.

JDK 1.1 + JFC 1.1 (Swing 1.1 Beta 3 or a compatible version):

/java/jdk1.1.7/bin/java 
   -classpath.:/java/jdk1.1.7/lib/classes.zip:/java/
   swing-1.1beta3/swing.jar:/java/swing-1.1beta3/motif.jar
   TreeTableExample2 /somedir                            (UNIX)
c:\java\jdk1.1.7\bin\java -classpath
   .;c:\java\jdk1.1.7\lib\classes.zip;
   c:\java\swing-1.1beta3\swing.jar;
   c:\java\swing-1.1beta3\motif.jar
   TreeTableExample2 c:\somedir                          (Win32)

JDK 1.2 (RC1 or a compatible release):

java TreeTableExample2 /somedir                          (UNIX)
java TreeTableExample2 c:\somedir                        (Win32)
[an error occurred while processing this directive]