Taking the New Swing Tree Table for a Spin
Usage is incredibly easy - you just provide a standard Swing TreeModel of whatever sort you like, and an additional RowModel that can be queried for the other columns contents, editability and so forth.
I found an example from some time ago, by Tim, and have been playing with it to get used to this new development. The result is as follows:
To get started, I simply download the latest NetBeans IDE development build from netbeans.org and then attached the platform8/org-netbeans-swing-outline.jar to my Java SE project. For the rest, I wasn't required to do anything with NetBeans, necessarily. I could have attached the JAR to a project in Eclipse or anywhere else. Then I created a JFrame.
To work with this Swing tree table, you need to provide the new "org.netbeans.swing.outline.Outline" class with the new "org.netbeans.swing.outline.OutlineModel" which, in turn, is built from a plain old javax.swing.tree.TreeModel, together with the new "org.netbeans.swing.outline.RowModel". Optionally, to change the default rendering, you can use the new "org.netbeans.swing.outline.RenderDataProvider".
Let's first create a TreeModel for accessing files on disk. We will receive the root of the file system as a starting point:
private static class FileTreeModel implements TreeModel {
private File root;
public FileTreeModel(File root) {
this.root = root;
}
@Override
public void addTreeModelListener(javax.swing.event.TreeModelListener l) {
//do nothing
}
@Override
public Object getChild(Object parent, int index) {
File f = (File) parent;
return f.listFiles()[index];
}
@Override
public int getChildCount(Object parent) {
File f = (File) parent;
if (!f.isDirectory()) {
return 0;
} else {
return f.list().length;
}
}
@Override
public int getIndexOfChild(Object parent, Object child) {
File par = (File) parent;
File ch = (File) child;
return Arrays.asList(par.listFiles()).indexOf(ch);
}
@Override
public Object getRoot() {
return root;
}
@Override
public boolean isLeaf(Object node) {
File f = (File) node;
return !f.isDirectory();
}
@Override
public void removeTreeModelListener(javax.swing.event.TreeModelListener l) {
//do nothing
}
@Override
public void valueForPathChanged(javax.swing.tree.TreePath path, Object newValue) {
//do nothing
}
}
The above could simply be set as a JTree's model and then you'd have a plain old standard JTree. It would work, no problems, it would be a normal JTree. However, it wouldn't be a tree table since you'd only have a tree, without a table. Therefore, let's now add two extra columns, via the new "org.netbeans.swing.outline.RowModel" class, which will enable the creation of a tree table instead of a tree:
private class FileRowModel implements RowModel {
@Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return Date.class;
case 1:
return Long.class;
default:
assert false;
}
return null;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int column) {
return column == 0 ? "Date" : "Size";
}
@Override
public Object getValueFor(Object node, int column) {
File f = (File) node;
switch (column) {
case 0:
return new Date(f.lastModified());
case 1:
return new Long(f.length());
default:
assert false;
}
return null;
}
@Override
public boolean isCellEditable(Object node, int column) {
return false;
}
@Override
public void setValueFor(Object node, int column, Object value) {
//do nothing for now
}
}
Now, after dragging-and-dropping an Outline object onto your JFrame (which is possible after adding the beans from the JAR to the NetBeans IDE Palette Manager) which, in turn, automatically creates a JScrollPane as well, this is how you could code the JFrame's constructor:
public NewJFrame() {
//Initialize the ui generated by the Matisse GUI Builder, which,
//for example, adds the JScrollPane to the JFrame ContentPane:
initComponents();
//Here I am assuming we are not on Windows,
//otherwise use Utilities.isWindows() ? 1 : 0
//from the NetBeans Utilities API:
TreeModel treeMdl = new FileTreeModel(File.listRoots()[0]);
//Create the Outline's model, consisting of the TreeModel and the RowModel,
//together with two optional values: a boolean for something or other,
//and the display name for the first column:
OutlineModel mdl = DefaultOutlineModel.createOutlineModel(
treeMdl, new FileRowModel(), true, "File System");
//Initialize the Outline object:
outline1 = new Outline();
//By default, the root is shown, while here that isn't necessary:
outline1.setRootVisible(false);
//Assign the model to the Outline object:
outline1.setModel(mdl);
//Add the Outline object to the JScrollPane:
jScrollPane1.setViewportView(outline1);
}
Alternatively, without the NetBeans Matisse GUI Builder and NetBeans Palette Manager, i.e., simply using a standard Java class, you could do something like this:
private Outline outline;
public NewJFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
TreeModel treeMdl = new FileTreeModel(File.listRoots()[0]);
OutlineModel mdl = DefaultOutlineModel.createOutlineModel(
treeMdl, new FileRowModel(), true);
outline = new Outline();
outline.setRootVisible(false);
outline.setModel(mdl);
getContentPane().add(new JScrollPane(outline),BorderLayout.CENTER);
setBounds(20, 20, 700, 400);
}
At this point, you can run the JFrame, with this result:
So, we see a lot of superfluous info that doesn't look very nice. Let's implement "org.netbeans.swing.outline.RenderDataProvider", as follows:
private class RenderData implements RenderDataProvider {
@Override
public java.awt.Color getBackground(Object o) {
return null;
}
@Override
public String getDisplayName(Object o) {
return ((File) o).getName();
}
@Override
public java.awt.Color getForeground(Object o) {
File f = (File) o;
if (!f.isDirectory() && !f.canWrite()) {
return UIManager.getColor("controlShadow");
}
return null;
}
@Override
public javax.swing.Icon getIcon(Object o) {
return null;
}
@Override
public String getTooltipText(Object o) {
File f = (File) o;
return f.getAbsolutePath();
}
@Override
public boolean isHtmlDisplayName(Object o) {
return false;
}
}
Now, back in the constructor, add the renderer to the outline:
outline1.setRenderDataProvider(new RenderData());
Run the JFrame again and the result should be the same as in the first screenshot above. Look again at the rendering code and note that, for example, you have tooltips:
- Login or register to post comments
- 20300 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)










Comments
Steven replied on Wed, 2008/06/04 - 12:35am
very nice article.
i can see many uses for this new tool.
David Qiao replied on Wed, 2008/06/04 - 12:56am
Hi Geertjan,
JIDE also has a TreeTable which supports filtering and multiple column sorting. You can run the webstart demo at http://www.jidesoft.com/products/download.htm to see it in action. There is a TreeTable (File System) demo on the left tree. It is the same file system demo as you did. You can also view the source code (there is a view source code button) of the demo. You will find it interesting to compare the two implementations.
Thanks for the article.
-David
gustav replied on Sun, 2008/06/08 - 10:51am
Francis Perreault replied on Fri, 2008/06/13 - 8:26am
Hi Geertjan,
Echoing a question from Tom Wheeler in Tim's article:
"Is there an easy way to use this with nodes and an ExplorerManager, or is org.openide.explorer.view.TreeTableView still the way to go?"
Thanks!
Francis
KevinJaques replied on Sun, 2008/11/30 - 12:20am
It's great you wrote this. I can't find any other material explaining how to use the outline. That said, while the writing might have been fine for an experienced programmer, it's not so good for a newbie. I have spent HOURS on it.
It says to create a "Java SE project". That wasn't the name of any of the templates in Netbeans 6.5. I chose Java:Application, but got no "Design" environment. So then I tried Java:Desktop Application, both as a 'basic' and a 'database'. In neither case was there a JFrame. Instead, there was a FrameView. I gather this automatically creates a JFrame as needed?
It says to add the jar to the project. That was especially aggravating in the MacOS, because the jar comes WITHIN the netbeans application, which turns out to be a folder which appears to be a file, called a 'package'. Unfortunately, the Netbeans file browser can't penetrate the package. I had to invent a work-around, making an alias (like a link) to a folder within the package.
It says to create a JFrame. Does that mean create a class that is a JFrame, or create an object which is a JFrame, or just rely on the FrameView to create it as needed?
It says to add the TreeModel and the RowModel. When I created classes for them, it said I couldn't make them 'private static'. Research suggested that you must have meant for them to be member classes, but of what? I tried adding them to the FrameView.
It says to add code to the JFrame constructor. There isn't one! I have no idea where to put it.
It's 11:30 pm, so I'm going to bed. Maybe I'll wake up with answers.
Geertjan Wielenga replied on Sun, 2008/11/30 - 5:31am
KevinJaques replied on Sun, 2008/11/30 - 10:32am
Geertjan wrote me overnight! How great is that! So, for newbies using Netbeans.
1. New project using the "Java:Java Application" Template
2. New class using the "Swing:JFrame" template
3. Add Outline JAR to your Application
a. Control Click "Libraries" in "Projects" pane (under "Window" menu if not showing). Add JAR file.
b. If Mac User, if you have not already done so, create alias so NetBeans can penetrate itself - In Dock, right click Netbeans, choose "Show in Finder". Right-click NetBeans, 'Show Package Contents'. Create alias to 'Contents' Directory (option drag to suitable location). Use that alias when you return to Netbeans
c. Navigate to /[your path to Netbeans application]/NetBeans/NetBeans 6.5.app/Contents/Resources/NetBeans/platform9/modules/org-netbeans-swing-outline.jar. Add it.
4. Add Outline object to your Palette - If you have not already done so, under Tools menu, Palette, choose "Swing/AWT Components", then add the outline.jar, as in 3.c, to the category of your choice.
5. Add Outline object to the JFrame - Show your frame class in the editor pane. Choose 'design' mode. Drag 'outline' from Palette onto the JFrame.
6. Paste the treeModel code into the JFrame Class. Right-click Fix Imports. Right click Format.
7. Paste the rowModel code into the JFrame Class. Right-click Fix Imports. Right click Format.
8. Paste the constructor code into the JFrame Class. Right-click Fix Imports. Right click Format. NOTE, this must replace the old constructor. Also, the constructor name must match the name of your JFrame class.
9. in main(), create the JFrame class and show it. For me, that was:
FileTreeJFrame myFileTreeJFrame = new FileTreeJFrame();
myFileTreeJFrame.setVisible(true);
10. Run. Isn't that awesome!? Check out how you can re-order & re-size columns and select which to show. You can click column headings to sort! Admire, then quit.
11. Add Rendering object. Paste the code into the JFrame Class. Right-click Fix Imports. Right click Format.
12. In the JFrame constructor, add the Renderer to the outline, exactly as Geertjan described.
13. Run. Be even more amazed. Context-dependent colours! Tool tips! Although not shown, it can also do custom icons and show special display names!
14. Note that if you want a cell to be editable, you return true in your rowModel's isCellEditable method.
15. When you figure out how to make it so the outline resizes when you resize the frame, or what the outlineView is for and how it is used, let me know.
varman replied on Tue, 2008/12/02 - 4:40am
Hi Geertjan,
I have some doubts in using rowmodel for my custom treetable. I am having a checkbox column in 2nd column of treetable and a mouse listener for the outline(treetable). I want to select those checkboxes and I dont know how to do it.
one idea is getting rowmodel from which calling setValuefor() method in mouselistener method. even in this way how to set value for a particular cell in checkbox column.
eagarly waiting for answers.
Pierre Sugar replied on Sat, 2009/01/10 - 12:59am
Hi Geertjan,
thank you for this article. I have been playing around with outline and found this is providing real good functions. But one function I am missing. When adding a new row how can I make outline select the new inserted row?
Thanks and regards
Pierre
Tim Boudreau replied on Mon, 2009/01/19 - 10:34pm
Pierre Sugar replied on Fri, 2009/01/23 - 5:40pm
Hi,
Is there an interface like RowModel that has an effect on the tree nodes in an outline. When I setFullyEditable(true) I can edit the tree nodes but I do not realize when the value has been changed or edited.
Thank you
Pierre
jaffi replied on Mon, 2009/03/16 - 8:08am
had a small thing with runnin the tree model: isLeaf could get null nodes...
added:
public boolean isLeaf(Object node) {
if (node == null) return true;
thanks, asaf :-)
sagi7 replied on Wed, 2009/03/25 - 8:17am
Hello,
thanks for TreeTable - that's missing in JFC Core.
I miss 1 thing in it.
How can i rename nodes?
In a JTree i can set an editor where i can control, if a node is editable or not.
Is there a possibility with Outline?
best regards
jaffi replied on Sun, 2009/04/05 - 2:31am
the whole selection query is really not that "Usage is incredibly easy - you just provide a standard Swing"...
Outline is a JTable, but the key model is the TreeModel (e.g. look at RowModel's getValueFor(Object node, int column) - it expects a node...).
As such, the current implementation is missing ways to easily convert rows to nodes.
Keep in mind that usually most of the operations on a tree will need a the node's path, so i've expected to see more TreePath query methods.
the way i go about it now, is look at the layout cache (outline.getLayoutCache().getPathForRow(row)).
did i miss something here?
i use Outline out of NetBeans. does the framework have a ready-to-use selection management?
anyway, i'm using this feature in my new app and i like it a lot - thank you for doing this!
asaf :-)
Wine_dude replied on Wed, 2009/05/13 - 3:54pm
1. How do I change the sort symbol to simply be the up or down arrow, getting rid of the "1" next to it. I do not allow more than a single column to be sorted.
2. Is there a way to specify the default sort order on a column? I'd like to start with descending rather than ascending.
3. The version in NetBeans 6.5.1 -- will it be changing significantly in the future? (the javadocs say under development)
Once again, thank you, thank you, thank you!
hookfi replied on Sun, 2009/05/31 - 7:42am
jiji530 replied on Mon, 2009/06/29 - 9:47pm
robertjohn47 replied on Sat, 2009/07/04 - 10:38pm