JTreeTable problem

Hi,
I am trying to modify the JTreeTable example available on java.sun.com in 3 parts at
http://java.sun.com/products/jfc/tsc/articles/treetable1/index.html
http://java.sun.com/products/jfc/tsc/articles/treetable2/index.html
http://java.sun.com/products/jfc/tsc/articles/bookmarks/
to display hierarchical data. At present, the JTree nodes are displayed in the first column of the JTable. I would like to remove this restriction and display the root node at location (0,0) of the JTable and each subsequent node indented by one row and one column.
For eaxmple, for the markup
<employee>
<name></name>
<address>
<work></work>
</address>
The JTable should look like
Employee
|
|________ Name
|
|________address
|
|_______work
Iam able to get the tree as I expect but there are any problems. When a node is not expanded, its children are getting painted often with incorrect icon or label. When I double click to edit it shows different text than the one that gets displayed. I also have problems with viewing the complete tree even though I have scrollbars. Also, the address node isn;t displayed until I expand the 'name' node though that is not the behavior with the example sun has provided.
I would like to furnish the code here but it is quite big ( some 4 or 5 classes).
Any help would be very much appreicated.
cheers,
vidyut

Hi Thomas,
Thanks for the reply. Let me make it clear to you what Iam trying to do. Iam working on developing a grid in which to edit XML data. The root node of the xml should appear at the top left corner of the JTable (which I had mentioned as 0,0 in my earlier posting). This could be anywhere as long as it is the top-leftmost node. The children of root node should be indented 1 table cell to the left and downward direction. The children of the first child of root should be indented 2 table cells and so on. This is to provide the user a cue about the parent-child relationships of the nodes and also allow easy editing of the node content.
Now to the technical part.
I saw your example where the tree is set as the row header. This will not work in my case as I expect for any column of the JTable there could be treenodes as well as plain text nodes. So the JTreeTable approach adopted by the example at java.sun.com is more apt I think.
Like you have said, it is a highly complex example and I just about managed to get the grid. But Iam facing few (!!!) problems.
You are right about point 3 you have mentioned. When a node isn't expanded the child nodes should'nt be visible. But it is in my case.
Here's a simplified diagram which should hopefully explain the other problem Iam facing.
At start
        |
        v ---- slideshow
           |    
           |_________ --> slide 
                                            |
                                            |_______ [ ]
                                                               |
                                                               |______wake up and smell the ...
pic 2 (slide opened)
        |
        v ---- slideshow
           |    
           |_________ |  
                                 V  -------slide
                                                   |
                                                   | _______
                                                                      --> -- title
                                                                                 |
                                                                                 |______wake up  ...
                                                   |
                                                   |
pic 3 (title opened)
        |
        v ---- slideshow
           |    
           |_________ |  
                                 V  -------slide
                                                   |
                                                   | _______ |
                                                                      V -- title
                                                                                 |
                                                                                 |______wake up  ...
                                                   |
                                                   |
                                                   --> slide
Legend:
    --> collapsed node
       |
      V  -- expanded node
     [] - leaf node
     My xml snippet is:
<slideshow>
<slide>
<title>Wake up and smell the coffee</title>
</slide>
<slide>
<title></title>
</slide>
</slideshow>
I will leave the point no 4 for later as this posting has already become too long. I would be glad to post the source code if you think that would help.
cheers,
vidyut

Similar Messages

  • JTreeTable problem editing tree node

    Hi,
    Iam using the swing JTreeTable component and facing a problem. Iam displaying hierarchical data in the JTreeTable. Now I would like to provide the facility to edit a tree node. I have a TreeSelectionListener registered on the tree and a TreeModelListener registered on the DefaultTreeModel. Wheneve, I start editing a node by double clicking it the valueChanged method is called but I do not see the new value the user types in this method. I have another method setValueAt which is where I can see the new value the user has entered.
    I can set this new value to the treenode using
        node.setUserObject(newValue);However, if I do this, the next time I try to edit the same node, the editor component is painted over the tree node thus displaying an empty textfield that occupies the entire cell.
    How can I make the editor appear above the tree node with the contents loaded in it always.
    Any help is appreciated.
    cheers,
    vidyut

    You bind a mouselistener to the tree, so it has to be handled there.
    When clicking once (method should be "mouseReleased" or something, treenodes name (toString) should be .setText("");
    regards
    marco

  • Problem when printing JTreeTable

    Hi,
    I've datas wich i display in a JTable or in a JTreeTable (see http://java.sun.com/products/jfc/tsc/articles/treetable1/ ).
    Now, i'd like to print the JTable or the JTreeTable, i use the code i've found here : http://developer.java.sun.com/developer/onlineTraining/Programming/JDCBook/advprint.html .
    There was a bug ( see http://forum.java.sun.com/thread.jsp?forum=57&thread=263303 ).
    The JTable prints itself very fine but i've two problems with the JTreeTable :
    1) I've always some last rows on a page and on the next page, even if i include the table.getRowMargin() or not.
    2) Almost all the node are printed with "...", for instance : TRES -> TR... although they are well displayed on screen.
    It doesn't depend on the width of the column and i can't know how Swing decide or not to display the "..." (for instance, i've "C..." and "CR..." but they are at the same x-location with the same icons, the same font and the same font's size; just not the same number of caracters)
    I don't post any code because it's long, it's just a mix between the links.
    Any help would be great before i kill hundreds of tree.
    Thanks in adavance.
    Fade.

    Hi Fade,
    I am having the same problem in printing a JTreeTable. The nodes of the JTree are getting clipped and are followed by ellipsis(...). A similar problem occurs for the other table columns, if the column separators(borders) are closely aligned with the text. It seems that the space required for rendering the components within the table, is more while printing. The problem is more prominent in case of the tree nodes. In case you have found a solution for the same, it would be nice if u could help me with it. Or if there's any one out there who could be of help, pls. reply.
    Thanx.

  • JTreeTable rendering problems

    Hi all!
    I have used some clesses to create a JTable containing a JTree, basing on the example in the sun's site. The costructor is:
    JFrame frame = new JFrame("TITLE");
    JTreeTable table = createTable(); //Creates the treetable
    JScrollPane scrollPane = new JScrollPane(table); //it puts the newly created table in a scrollPane
    frame.getContentPane().add(scrollPane,BorderLayout.CENTER);
    frame.pack();
    frame.show();
    I have the following problems:
    1. If I have not many nodes in the tree, I have a bad renderer effect: the table doesn't fit the whole window but just the upper part of that, at the bottom it's all gray (the JFrame color, I think).Even if I set the JFrame background color to white, I still have that problem.
    2. If I don't add the table to the scrollbar, I can't see the headers, but I don't have the problem of the gray panel.
    Does anyone know how I can work out this? Has anybody examples of JTreeTables that don't have this rendering problem (with the table fitting the whole window even though they don't have many nodes)?
    Feedbacks are welcome, this is really showstopper for me...
    Thanks a lot!

    Hi there.
    Try setting the viewport color of your scrollpane. I don't have my API's on hand but you go something like myScrollPane.getViewport().setBackgroundColor(Color.white);
    How does that go for you?
    Cheers,
    Rachel

  • JTreeTable - Dynamic Child Loading - Selection problem

    Hi,
    I'm using JTreeTable Example 3 for my application.
    I've hidded the root and I am loading the child nodes for the second level nodes(parent) dynamically using the treeWillExpand() method . So my Model will be updated dynamically during runtime.
    The problem is, the selection of the TreeTable is not working properly after the expansion. Please throw some light on this issue.
    Thanks in advance
    Your
    Arun

    try to invoke reload(); on your treeModel ...
    i had this problem too only if the root is hided ...

  • Editing non-tree cells problem in JTreeTable

    Hello all,
    I've been playing around with the JTreeTable for quite a while and have a fairly good grip on it. However, I've run into a problem that involves the display of cell data in the non-tree cells.
    Assume I have a JTreeTable with one node below the root (and the root node is not displayed). Also assume I've edited some information in one of the other cells in a 5-celled JTreeTable. The JTreeTable behaves normally with regard to editing/setting the values of the table cells.
    Now, with the click of a separate button, I programmatically create a new node in the JTree. I update the JTree model with a call to nodeChanged() and nodeStructureChanged() (or I could call reload() - both seem to work).
    This successfully adds a node, but in the process clears the entire remainder of the table's cell values. If I call fireTableDataChanged(), then the display of the JTree gets all screwed up (basically what happens to the display if you add/remove nodes, but don't update the display in a JTree). Not only that, but the fireTableDataChanged() method still does not redisplay my cell information for the remainder of the table.
    I'm at a loss to figure out what's responsible for this. The tableCellRenderer seems to work just fine until I add node. Even then, the tableCellRenderer for the JTree still works until I call fireTableDataChanged().
    Any ideas?
    Thank you,
    Brion Swanson

    I use a JTreeTable and in looking at my code, I've
    noticed that I make use of treeTable.repaint() fairly
    frequently (as whenever I update my stuff).Did the treeTable.updateUI do funky things to your JTree? It does on mine if I do a programmatic node addition or removal (basically any change to the tree structure will cause treeTable.updateUI() to completely destroy the display of the tree). This is a separate issue, but I thought I'd ask anyway since you seem to have run into at least a few of the same problems I'm experiencing.
    I don't fully understand your problem<snip/>
    do you mean
    it drops all edits you have done?Yes, it drops all the edits except the one currently being "edited" (that is, the selected editable cell will not lose it's value).
    I had a problem about it dropping the edits I had
    done and I resolved them by adding key listeners
    and played with the TableCellEditor.Could you elaborate on what you did to the TableCellEditor and which object you had listening to the keys (the table? or the tree? or something else?).
    You help is greatly appreciated!
    Brion Swanson

  • Problem with JTreeTable

    I am using the JTreeTable example provided in the Swing Connection : The swing HTML Parser (Part 3 of the JTreeTable articles) (http://java.sun.com/products/jfc/tsc/articles/bookmarks/index.html). I create my hirerarchical structure and pass it to the model. It displays the root and children of the root just fine; however when I try to open the children they do not drop down and do not show the rest of the data. I stop the IDE to check the variable "children" of my DefaultMutableTreeNode class and the data is there.
    Any ideas what I'm doing wrong?

    Never mind, I found the problem. I had made column 0 not editable.

  • A very difficult problem of JTreeTable

    I am now creating a xml editor by the use of swing. I have drafted an interface and uploaded to this http://fungho.uhome.net/temp/SAMPLE.jpg
    This interface has the tree with the following xml schema:
    <book version="2" language="English">
    <content number="1">How are you?</content>
    </book>
    In my application, there are 2 enpandedIcons for each element, the first one is for the expansion and contraction of the tree structure, while the second one is for the expansion and the contraction of the attributes of the element. For the words between <content> and </content>, "How are you?" in this example, are displayed in the white area benenth the 'content' area. At the same time, there are 2 columns which are not used in the interface, this columns are used for other purpose.
    In view of this, I know JTreeTable is used. However, I don't know how to add one more tree in each node. Moreover, the background color seems to be very difficult to implement... Hope you can have some suggestions! Thanks!
    Stephen

    Vampire,
    Welcome to Apple discussions.
    It sounds like you either have a conflict with a keystroke expander or with Pages built-in auto-correction feature. To test this, try shutting off the auto-correction by clicking on Pages > Preferences > Auto-Correction > then UNcheck Symbol & Text Substitution. Let us know if that works.
    -Dennis

  • JTreeTable selection problem

    hi
    1.I am using the JSort treetable from the site:http://cal007300.student.utwente.nl/treetables/
    (example3) and i found that there is a bug of row selection in the table:
    not all the cells in the row are marked - evetu time i click on a certain cell several cells are marked (sometimes cells that r not connected to each other).
    Does anyone can give me a key to solving this problem?
    2.I want to add a pop up menu to the tree (opened on right click)- is it possible to add the table another mouse listener (i guess there is one that pass the mouse events to the tree)?
    thabks in advance
    liat

    try to invoke reload(); on your treeModel ...
    i had this problem too only if the root is hided ...

  • JTreeTable customization problem

    Hi,
    Iam trying to customize the JTreeTable example available in 3 parts in java.sun.com to my needs. I see that there is a method
    Class getColumnClass(int columnNumber)  in the interface TreeTableModel which my Model implements.
    Does this mean that the table column can have only tree nodes or some other type like String. What Iam trying to achieve is a mixed content model where in a table column, some columns may contain text while others can contain tree nodes.
    Can someone tell me how to achieve this.
    Cheers,
    vidyut

    Hi,
    Iam trying to customize the JTreeTable example available in 3 parts in java.sun.com to my needs. I see that there is a method
    Class getColumnClass(int columnNumber)  in the interface TreeTableModel which my Model implements.
    Does this mean that the table column can have only tree nodes or some other type like String. What Iam trying to achieve is a mixed content model where in a table column, some columns may contain text while others can contain tree nodes.
    Can someone tell me how to achieve this.
    Cheers,
    vidyut

  • Problems with JTreeTable

    Hi, i'm pretty new to java, and i'm trying to make the JTreeTable from Part III of sun's TreeTable example dynamic. I mean i'm trying to add/ remove items to the TreeTable.
    I'm using the same model from the example for the table; when the JTreeTable is created, the nodes and columns are added fine.
    But when i try to add new objects to the treeTable at runtime, the node is added to the model, but is not visible.
    If i make
    Bookmarks newObj = new Bookmarks();
    //add node ....
    System.out.println(newObj.getRoot().getLastChild().toString));
    It outputs the new node's name, but it isn't visible on the treeTable.
    I think i must tell the treeTable to refresh to render the changes made in its model, but i'm not able to do it.
    Can anybody help with this, please??
    Thanks in advance

    OK, i got it.
    It seems i was dealing with the wrong data model.

  • JTree custom renderer setting selection background color problem

    Hi,
    I have a JTree with a custom icon renderer that displays an icon. The JTree is part of a TreeTable component. Iam having a problem setting the selection background uniformly for the entire row. There is no problem when there is no row selected in the JTable.
    My present code looks like this:
    Iam overriding paint in my renderer which extends DefaultCellRenderer.
           super.paint(g);
            Color bColor = null;
            if(!m_selected) {
                 if(currRow % 2 == 0) {
                      bColor = Color.WHITE;
                 } else {
                                                    bColor = backColor;
            } else {
                 bColor = table.getSelectionBackground();                  bColor = getRowSelectionColor();
         if(bColor != null) {
                           g.setColor(bColor);
             if(!m_selected) {
                   g.setXORMode(new Color(0xFF, 0xFF, 0xFF));
             } else {
                 g.setXORMode(new Color(0x00, 0x00, 0x00));
                  I have a color I arrive at using some algorithm that I want using method getRowSelectionColor(). The other cells in the row have this color. But the cell containing the tree node shows different color. Iam not able to arrive at the right combination of the color to set and the xor color so my tree node also looks like the other cells in the row.
    It is not a problem really as the table still looks good. Its just that the tree node looks like it has been highlighted and this might cause a problem when a table cell is highlighed later on in the application ( two cells in the row would be highlighted causing confusion).
    Any help would be appreciated.
    Regards,
    vidyut

    Hi Camickr,
    Thanks for the reply. Iam sorry I didn't include the sources the first time around. There were too many of them. I have created a small, self-contained, compilable program that demonstrates the problem and including it herewith. Still there's quite many files but they are all needed Iam afraid. The only one you will have to concern yourself fior this problem is the file IconRenderer.java. The treenode background and the other cells background are not in sync when table row is not selected in this example though. But they are in my real program. I just need them to be in sync i.e have the same background color when the row is selected.
    Your help would be very much appreciated.
    These are the files that are included below:
    1. AbstractTreeTableModel.java
    2. Bookmarks.java
    3. BookmarksModel.java
    4. DynamicTreeTableModel.java
    5. IconRenderer.java
    6. IndicatorRenderer.java
    7. JTreeTable.java
    8. TreeTableExample3.java (contains main)
    9. TreeTableModel.java
    10. TreeTableModelAdapter.java
    The copyright and javadocs information has been stripped for clarity.
    cheers,
    vidyut
    // AbstractTreeTableModel.java BEGIN
    import javax.swing.tree.*;
    import javax.swing.event.*;
    public abstract class AbstractTreeTableModel implements TreeTableModel {
        protected Object root;    
        protected EventListenerList listenerList = new EventListenerList();
        public AbstractTreeTableModel(Object root) {
            this.root = root;
        // Default implementations for methods in the TreeModel interface.
        public Object getRoot() {
            return root;
        public boolean isLeaf(Object node) {
            return getChildCount(node) == 0;
        public void valueForPathChanged(TreePath path, Object newValue) {}
        // This is not called in the JTree's default mode:
        // use a naive implementation.
        public int getIndexOfChild(Object parent, Object child) {
            for (int i = 0; i < getChildCount(parent); i++) {
             if (getChild(parent, i).equals(child)) {
                 return i;
         return -1;
        public void addTreeModelListener(TreeModelListener l) {
            listenerList.add(TreeModelListener.class, l);
        public void removeTreeModelListener(TreeModelListener l) {
            listenerList.remove(TreeModelListener.class, l);
        protected void fireTreeNodesChanged(Object source, Object[] path,
                                            int[] childIndices,
                                            Object[] children) {
            // Guaranteed to return a non-null array
            Object[] listeners = listenerList.getListenerList();
            TreeModelEvent e = null;
            // Process the listeners last to first, notifying
            // those that are interested in this event
            for (int i = listeners.length-2; i>=0; i-=2) {
                if (listeners==TreeModelListener.class) {
    // Lazily create the event:
    if (e == null)
    e = new TreeModelEvent(source, path,
    childIndices, children);
    ((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
    protected void fireTreeNodesInserted(Object source, Object[] path,
    int[] childIndices,
    Object[] children) {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    TreeModelEvent e = null;
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length-2; i>=0; i-=2) {
    if (listeners[i]==TreeModelListener.class) {
    // Lazily create the event:
    if (e == null)
    e = new TreeModelEvent(source, path,
    childIndices, children);
    ((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
    protected void fireTreeNodesRemoved(Object source, Object[] path,
    int[] childIndices,
    Object[] children) {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    TreeModelEvent e = null;
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length-2; i>=0; i-=2) {
    if (listeners[i]==TreeModelListener.class) {
    // Lazily create the event:
    if (e == null)
    e = new TreeModelEvent(source, path,
    childIndices, children);
    ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
    protected void fireTreeStructureChanged(Object source, Object[] path,
    int[] childIndices,
    Object[] children) {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    TreeModelEvent e = null;
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length-2; i>=0; i-=2) {
    if (listeners[i]==TreeModelListener.class) {
    // Lazily create the event:
    if (e == null)
    e = new TreeModelEvent(source, path,
    childIndices, children);
    ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
    // Default impelmentations for methods in the TreeTableModel interface.
    public Class getColumnClass(int column) { return Object.class; }
    public boolean isCellEditable(Object node, int column) {
    return getColumnClass(column) == TreeTableModel.class;
    public void setValueAt(Object aValue, Object node, int column) {}
    // Left to be implemented in the subclass:
    * public Object getChild(Object parent, int index)
    * public int getChildCount(Object parent)
    * public int getColumnCount()
    * public String getColumnName(Object node, int column)
    * public Object getValueAt(Object node, int column)
    // AbstractTreeTableModel.java END
    // Bookmarks.java BEGIN
    import java.io.*;
    import java.net.*;
    import java.util.*;
    import javax.swing.*;
    import javax.swing.tree.*;
    import javax.swing.text.*;
    import javax.swing.text.html.*;
    import javax.swing.text.html.parser.*;
    public class Bookmarks {
    /** The root node the bookmarks are added to. */
    private BookmarkDirectory root;
    * Creates a new Bookmarks object, with the entries coming from
    * <code>path</code>.
    public Bookmarks(String path) {
         root = new BookmarkDirectory("Bookmarks");
         if (path != null) {
         parse(path);
    * Returns the root of the bookmarks.
    public BookmarkDirectory getRoot() {
         return root;
    protected void parse(String path) {
         try {
         BufferedReader reader = new BufferedReader(new FileReader
                                       (path));
         new ParserDelegator().parse(reader, new CallbackHandler(), true);
         catch (IOException ioe) {
         System.out.println("IOE: " + ioe);
         JOptionPane.showMessageDialog(null, "Load Bookmarks",
                             "Unable to load bookmarks",
                             JOptionPane.ERROR_MESSAGE);
    private static final short NO_ENTRY = 0;
    private static final short BOOKMARK_ENTRY = 2;
    private static final short DIRECTORY_ENTRY = 3;
    private class CallbackHandler extends HTMLEditorKit.ParserCallback {
         /** Parent node that new entries are added to. */
         private BookmarkDirectory parent;
         /** The most recently parsed tag. */
         private HTML.Tag tag;
         /** The last tag encountered. */
         private HTML.Tag lastTag;
         * The state, will be one of NO_ENTRY, DIRECTORY_ENTRY,
    * or BOOKMARK_ENTRY.
         private short state;
         * Date for the next BookmarkDirectory node.
         private Date parentDate;
         * The values from the attributes are placed in here. When the
         * text is encountered this is added to the node hierarchy and a
    * new instance is created.
         private BookmarkEntry lastBookmark;
         * Creates the CallbackHandler.
         public CallbackHandler() {
         parent = root;
         lastBookmark = new BookmarkEntry();
         // HTMLEditorKit.ParserCallback methods
         * Invoked when text in the html document is encountered. Based on
         * the current state, this will either: do nothing
    * (state == NO_ENTRY),
         * create a new BookmarkEntry (state == BOOKMARK_ENTRY) or
    * create a new
         * BookmarkDirectory (state == DIRECTORY_ENTRY). If state is
    * != NO_ENTRY, it is reset to NO_ENTRY after this is
    * invoked.
    public void handleText(char[] data, int pos) {
         switch (state) {
         case NO_ENTRY:
              break;
         case BOOKMARK_ENTRY:
              // URL.
              lastBookmark.setName(new String(data));
    parent.add(lastBookmark);
    lastBookmark = new BookmarkEntry();
              break;
         case DIRECTORY_ENTRY:
              // directory.
              BookmarkDirectory newParent = new
                   BookmarkDirectory(new String(data));
              newParent.setCreated(parentDate);
              parent.add(newParent);
              parent = newParent;
              break;
         default:
              break;
    state = NO_ENTRY;
         * Invoked when a start tag is encountered. Based on the tag
         * this may update the BookmarkEntry and state, or update the
         * parentDate.
         public void handleStartTag(HTML.Tag t, MutableAttributeSet a,
                        int pos) {
         lastTag = tag;
         tag = t;
         if (t == HTML.Tag.A && lastTag == HTML.Tag.DT) {
    long lDate;
              // URL
              URL url;
              try {
              url = new URL((String)a.getAttribute(HTML.Attribute.HREF));
              } catch (MalformedURLException murle) {
              url = null;
              lastBookmark.setLocation(url);
              // created
              Date date;
              try {
    lDate = Long.parseLong((String)a.getAttribute("add_date"));
    if (lDate != 0l) {
    date = new Date(1000l * lDate);
    else {
    date = null;
              } catch (Exception ex) {
              date = null;
              lastBookmark.setCreated(date);
              // last visited
              try {
    lDate = Long.parseLong((String)a.
    getAttribute("last_visit"));
    if (lDate != 0l) {
    date = new Date(1000l * lDate);
    else {
    date = null;
              } catch (Exception ex) {
              date = null;
              lastBookmark.setLastVisited(date);
              state = BOOKMARK_ENTRY;
         else if (t == HTML.Tag.H3 && lastTag == HTML.Tag.DT) {
              // new node.
              try {
              parentDate = new Date(1000l * Long.parseLong((String)a.
                                  getAttribute("add_date")));
              } catch (Exception ex) {
              parentDate = null;
              state = DIRECTORY_ENTRY;
         * Invoked when the end of a tag is encountered. If the tag is
         * a DL, this will set the node that parents are added to the current
         * nodes parent.
         public void handleEndTag(HTML.Tag t, int pos) {
         if (t == HTML.Tag.DL && parent != null) {
              parent = (BookmarkDirectory)parent.getParent();
    public static class BookmarkDirectory extends DefaultMutableTreeNode {
         /** Dates created. */
         private Date created;
         public BookmarkDirectory(String name) {
         super(name);
         public void setName(String name) {
         setUserObject(name);
         public String getName() {
         return (String)getUserObject();
         public void setCreated(Date date) {
         this.created = date;
         public Date getCreated() {
         return created;
    public static class BookmarkEntry extends DefaultMutableTreeNode {
         /** User description of the string. */
         private String name;
         /** The URL the bookmark represents. */
         private URL location;
         /** Dates the URL was last visited. */
         private Date lastVisited;
         /** Date the URL was created. */
         private Date created;
         public void setName(String name) {
         this.name = name;
         public String getName() {
         return name;
         public void setLocation(URL location) {
         this.location = location;
         public URL getLocation() {
         return location;
         public void setLastVisited(Date date) {
         lastVisited = date;
         public Date getLastVisited() {
         return lastVisited;
         public void setCreated(Date date) {
         this.created = date;
         public Date getCreated() {
         return created;
         public String toString() {
         return getName();
    // Bookmarks.java END
    // BookmarksModel.java BEGIN
    import java.util.Date;
    public class BookmarksModel extends DynamicTreeTableModel {
    * Names of the columns.
    private static final String[] columnNames =
    { "Name", "Location", "Last Visited", "Created" };
    * Method names used to access the data to display.
    private static final String[] methodNames =
    { "getName", "getLocation", "getLastVisited","getCreated" };
    * Method names used to set the data.
    private static final String[] setterMethodNames =
    { "setName", "setLocation", "setLastVisited","setCreated" };
    private static final Class[] classes =
    { TreeTableModel.class, String.class, Date.class, Date.class };
    public BookmarksModel(Bookmarks.BookmarkDirectory root) {
         super(root, columnNames, methodNames, setterMethodNames, classes);
    public boolean isCellEditable(Object node, int column) {
         switch (column) {
         case 0:
         // Allow editing of the name, as long as not the root.
         return (node != getRoot());
         case 1:
         // Allow editing of the location, as long as not a
         // directory
         return (node instanceof Bookmarks.BookmarkEntry);
         default:
         // Don't allow editing of the date fields.
         return false;
    // BookmarksModel.java END
    // DynamicTreeTableModel.java BEGIN
    import java.lang.reflect.*;
    import javax.swing.tree.*;
    public class DynamicTreeTableModel extends AbstractTreeTableModel {
    /** Names of the columns, used for the TableModel getColumnName method. */
    private String[] columnNames;
    private String[] methodNames;
    private String[] setterMethodNames;
    /** Column classes, used for the TableModel method getColumnClass. */
    private Class[] cTypes;
    public DynamicTreeTableModel(TreeNode root, String[] columnNames,
                        String[] getterMethodNames,
                        String[] setterMethodNames,
                        Class[] cTypes) {
         super(root);
         this.columnNames = columnNames;
         this.methodNames = getterMethodNames;
         this.setterMethodNames = setterMethodNames;
         this.cTypes = cTypes;
    public int getChildCount(Object node) {
         return ((TreeNode)node).getChildCount();
    public Object getChild(Object node, int i) {
         return ((TreeNode)node).getChildAt(i);
    public boolean isLeaf(Object node) {
         return ((TreeNode)node).isLeaf();
    public int getColumnCount() {
         return columnNames.length;
    public String getColumnName(int column) {
         if (cTypes == null || column < 0 || column >= cTypes.length) {
         return null;
         return columnNames[column];
    public Class getColumnClass(int column) {
         if (cTypes == null || column < 0 || column >= cTypes.length) {
         return null;
         return cTypes[column];
    public Object getValueAt(Object node, int column) {
         try {
         Method method = node.getClass().getMethod(methodNames[column],
                                  null);
         if (method != null) {
              return method.invoke(node, null);
         catch (Throwable th) {}
         return null;
    * Returns true if there is a setter method name for column
    * <code>column</code>. This is set in the constructor.
    public boolean isCellEditable(Object node, int column) {
    return (setterMethodNames != null &&
         setterMethodNames[column] != null);
    // Note: This looks up the methods each time! This is rather inefficient;
    // it should really be changed to cache matching
    // methods/constructors
    // based on <code>node</code>'s class, and code>aValue</code>'s
    //class.
    public void setValueAt(Object aValue, Object node, int column) {
         boolean found = false;
         try {
         // We have to search through all the methods since the
         // types may not match up.
         Method[] methods = node.getClass().getMethods();
         for (int counter = methods.length - 1; counter >= 0; counter--) {
              if (methods[counter].getName().equals
              (setterMethodNames[column]) && methods[counter].
              getParameterTypes() != null && methods[counter].
              getParameterTypes().length == 1) {
              // We found a matching method
              Class param = methods[counter].getParameterTypes()[0];
              if (!param.isInstance(aValue)) {
                   // Yes, we can use the value passed in directly,
                   // no coercision is necessary!
                   if (aValue instanceof String &&
                   ((String)aValue).length() == 0) {
                   // Assume an empty string is null, this is
                   // probably bogus for here.
                   aValue = null;
                   else {
                   // Have to attempt some sort of coercision.
                   // See if the expected parameter type has
                   // a constructor that takes a String.
                   Constructor cs = param.getConstructor
                   (new Class[] { String.class });
                   if (cs != null) {
                        aValue = cs.newInstance(new Object[]
                                       { aValue });
                   else {
                        aValue = null;
              // null either means it was an empty string, or there
              // was no translation. Could potentially deal with these
              // differently.
              methods[counter].invoke(node, new Object[] { aValue });
              found = true;
              break;
         } catch (Throwable th) {
         System.out.println("exception: " + th);
         if (found) {
         // The value changed, fire an event to notify listeners.
         TreeNode parent = ((TreeNode)node).getParent();
         fireTreeNodesChanged(this, getPathToRoot(parent),
                        new int[] { getIndexOfChild(parent, node) },
                        new Object[] { node });
    public TreeNode[] getPathToRoot(TreeNode aNode) {
    return getPathToRoot(aNode, 0);
    private TreeNode[] getPathToRoot(TreeNode aNode, int depth) {
    TreeNode[] retNodes;
         // This method recurses, traversing towards the root in order
         // size the array. On the way back, it fills in the nodes,
         // starting from the root and working back to the original node.
    /* Check for null, in case someone passed in a null node, or
    they passed in an element that isn't rooted at root. */
    if(aNode == null) {
    if(depth == 0)
    return null;
    else
    retNodes = new TreeNode[depth];
    else {
    depth++;
    if(aNode == root)
    retNodes = new TreeNode[depth];
    else
    retNodes = getPathToRoot(aNode.getParent(), depth);
    retNodes[retNodes.length - depth] = aNode;
    return retNodes;
    // DynamicTreeTableModel.java END
    // IconRenderer.java BEGIN
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.tree.*;
    import javax.swing.plaf.basic.BasicTreeUI;
    class IconRenderer extends DefaultTreeCellRenderer
    // Color backColor = new Color(0xD0, 0xCC, 0xFF);
    Color backColor = new Color(0xF0, 0xF0, 0xE0);
    String tipText = "";
    JTree tree;
    int currRow = 0;
    boolean m_selected;
    JTable table;
    public IconRenderer(JTree tree, JTable table) {
    this.table = table;
    // setBackground(backColor);
    setBackground(Color.GREEN);
    setForeground(Color.black);
         this.tree = tree;
    public Component getTreeCellRendererComponent(JTree tree, Object value,
    boolean selected,
    boolean expanded, boolean leaf,
    int row, boolean hasFocus) {
         Object node = null;
         super.getTreeCellRendererComponent(
    tree, value, selected,
    expanded, leaf, row,
    hasFocus);
         TreePath treePath = tree.getPathForRow(row);
    if(treePath != null)
              node = treePath.getLastPathComponent();
    currRow = row;
    m_selected = selected;
    DefaultMutableTreeNode itc = null;
    if (node instanceof DefaultMutableTreeNode) {
    itc = (DefaultMutableTreeNode)node;
         setClosedIcon(closedIcon);
    setOpenIcon(openIcon);
    return this;
    /* Override the default to send back different strings for folders and leaves. */
    public String getToolTipText() {
    return tipText;
    * Paints the value. The background is filled based on selected.
    public void paint(Graphics g) {
         super.paint(g);
         Color bColor = null;
         if(!m_selected) {
              System.out.println(" iconren not sel currRow " + currRow);
              if(currRow % 2 == 0) {
                   bColor = Color.WHITE;
              } else {
              bColor = backColor;
         } else {
              bColor = table.getSelectionBackground();
              System.out.println("in else selbg = " + bColor);           
              bColor = new Color(0xF0, 0xCC, 0x92);
              System.out.println(" bColor aft = " + bColor);           
         int imageOffset = -1;
         if(bColor != null) {
         imageOffset = getLabelStart();
         g.setColor(bColor);
         if(!m_selected) {
              System.out.println(" not sel setting white ");
              g.setXORMode(new Color(0xFF, 0xFF, 0xFF));
         } else {
    //          g.setXORMode(new Color(0xCC, 0xCC, 0x9F));
              g.setXORMode(new Color(0x00, 0x00, 0x00));
              System.out.println(" using color = " + g.getColor());           
         if(getComponentOrientation().isLeftToRight()) {
         g.fillRect(imageOffset, 0, getWidth() - 1 - imageOffset,
                   getHeight());
         } else {
         g.fillRect(0, 0, getWidth() - 1 - imageOffset,
                   getHeight());
    private int getLabelStart() {
         Icon currentI = getIcon();
         if(currentI != null && getText() != null) {
         return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
         return 0;
    // IconRenderer.java END
    // IndicatorRenderer.java BEGIN
    // import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.event.*;
    import javax.swing.tree.*;
    import javax.swing.table.*;
    import javax.swing.table.*;
    import javax.swing.plaf.basic.*;
    import java.awt.event.*;
    import java.util.EventObject;
    import java.text.NumberFormat;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.StringTokenizer;
    import java.util.Arrays;
    class IndicatorRenderer extends DefaultTableCellRenderer {
    /** Makes sure the number of displayed in an internationalized
    * manner. */
    protected NumberFormat formatter;
    /** Row that is currently being painted. */
    protected int lastRow;
    protected int reloadRow;
    protected int reloadCounter;
    protected TreeTableModel treeTableModel;
    protected TreeTableModelAdapter treeTblAdapter;
    protected JTable table;
    Component renderer = null;
    Color backColor = new Color(0xF0, 0xF0, 0xE0);
    IndicatorRenderer(TreeTableModelAdapter treeTblAdapter, TreeTableModel treeTableModel) {
         setHorizontalAlignment(JLabel.RIGHT);
         setFont(new Font("serif", Font.BOLD, 12));
         this.treeTableModel = treeTableModel;
         this.treeTblAdapter = treeTblAdapter;
    * Invoked as part of DefaultTableCellRenderers implemention. Sets
    * the text of the label.
    public void setValue(Object value) {
    /* setText((value == null) ? "---" : formatter.format(value)); */
         setText((value == null) ? "---" : (String) value.toString());
    * Returns this.
    public Component getTableCellRendererComponent(JTable table,
    Object value, boolean isSelected, boolean hasFocus,
    int row, int column) {
         renderer = super.getTableCellRendererComponent(table, value, isSelected,
    hasFocus, row, column);
         lastRow = row;
         this.table = table;
              if(isSelected) {
                   doMask(hasFocus, isSelected);
              } else
              setBackground(table.getBackground());
    return renderer;
    * If the row being painted is also being reloaded this will draw
    * a little indicator.
    public void paint(Graphics g) {
         super.paint(g);
    private void doMask(boolean hasFocus, boolean selected) {
              maskBackground(hasFocus, selected);
    private void maskBackground(boolean hasFocus, boolean selected) {
              Color seed = null;
              seed = table.getSelectionBackground();
              Color color = seed;
              if (color != null) {
                   setBackground(
    new Color(0xF0, 0xCC, 0x92));
    // IndicatorRenderer.java END
    // JTreeTable.java BEGIN
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.event.*;
    import javax.swing.tree.*;
    import javax.swing.table.*;
    import java.awt.event.*;
    import java.util.EventObject;
    public class JTreeTable extends JTable {
    /** A subclass of JTree. */
    protected TreeTableCellRenderer tree;
    protected IndicatorRenderer indicatorRenderer = null;
    public JTreeTable(TreeTableModel treeTableModel) {
         super();
         // Creates the tree. It will be used as a renderer and editor.
         tree = new TreeTableCellRenderer(treeTableModel);
         TreeTableModelAdapter tdap = new TreeTableModelAdapter(treeTableModel, tree);
         // Installs a tableModel representing the visible rows in the tree.
         super.setModel(tdap);
         // Forces the JTable and JTree to share their row selection models.
         ListToTreeSelectionModelWrapper selectionWrapper = new
         ListToTreeSelectionModelWrapper();
         tree.setSelectionModel(selectionWrapper);
         setSelectionModel(selectionWrapper.getListSelectionModel());
         // Installs the tree editor renderer and editor.
         setDefaultRenderer(TreeTableModel.class, tree);
         setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
         indicatorRenderer = new IndicatorRenderer(tdap, treeTableModel);     
         // No grid.
         setShowGrid(false);
         // No intercell spacing
         setIntercellSpacing(new Dimension(0, 0));     
         // And update the height of the trees row to match that of
         // the table.
         //if (tree.getRowHeight() < 1) {
         // Metal looks better like this.
         setRowHeight(20);
    public TableCellRenderer getCellRenderer(int row, int col) {
              if(col == 0)
              return tree;
              else
              return indicatorRenderer;     
    public void updateUI() {
         super.updateUI();
         if(tree != null) {
         tree.updateUI();
         // Do this so that the editor is referencing the current renderer
         // from the tree. The renderer can potentially change each time
         // laf changes.
         setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
         // Use the tree's default foreground and background colors in the
         // table.
    LookAndFeel.installColorsAndFont(this, "Tree.background",
    "Tree.foreground", "Tree.font");
    public int getEditingRow() {
    return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
         editingRow;
    private int realEditingRow() {
         return editingRow;
    public void sizeColumnsToFit(int resizingColumn) {
         super.sizeColumnsToFit(resizingColumn);
         if (getEditingColumn() != -1 && getColumnClass(editingColumn) ==
         TreeTableModel.class) {
         Rectangle cellRect = getCellRect(realEditingRow(),
                             getEditingColumn(), false);
    Component component = getEditorComponent();
         component.setBounds(cellRect);
    component.validate();
    public void setRowHeight(int rowHeight) {
    super.setRowHeight(rowHeight);
         if (tree != null && tree.getRowHeight() != rowHeight) {
    tree.setRowHeight(getRowHeight());
    public JTree getTree() {
         return tree;
    public boolean editCellAt(int row, int column, EventObject e){
         boolean retValue = super.editCellAt(row, column, e);
         if (retValue && getColumnClass(column) == TreeTableModel.class) {
         repaint(getCellRect(row, column, false));
         return retValue;
    public class TreeTableCellRenderer extends JTree implements
         TableCellRenderer {
         /** Last table/tree row asked to renderer. */
         protected int visibleRow;
         /** Border to draw around the tree, if this is non-null, it will
         * be painted. */
         protected Border highlightBorder;
         public TreeTableCellRenderer(Tr

  • Using JTreeTable as a Bean

    Hi,
    I've been looking at the JTreeTable class available at:
    http://java.sun.com/products/jfc/tsc/articles/treetable1/
    This is not a standard Swing component but I'd like to use it as a Bean so that I can load it into my NetBeans IDE. Problem is there does not appear to be a means to set the model (for tree and table) other than using the constructor that takes a TreeTableModel parameter.
    Has this been done before? Any help is appreciated.
    Thanks,
    Derek.

    Mabe you also should rewrite the other constructor:
    public JTreeTable(TreeTableModel treeTableModel) {
         super();
            setTreeTableModel(treeTableModel);
            // Installs the tree editor.
            setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
         // No grid.
         setShowGrid(false);
         // No intercell spacing
         setIntercellSpacing(new Dimension(0, 0));     
    public void setTreeTableModel(TreeTableModel treeTableModel){
         // Creates the tree. It will be used as a renderer and editor.
         tree = new TreeTableCellRenderer(treeTableModel);
         // Installs a tableModel representing the visible rows in the tree.
         super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
         // Forces the JTable and JTree to share their row selection models.
         ListToTreeSelectionModelWrapper selectionWrapper = new
                                 ListToTreeSelectionModelWrapper();
         tree.setSelectionModel(selectionWrapper);
         setSelectionModel(selectionWrapper.getListSelectionModel());
         // Installs the tree renderer
         setDefaultRenderer(TreeTableModel.class, tree);
         // And update the height of the trees row to match that of
         // the table.
         if (tree.getRowHeight() < 1) {
             // Metal looks better like this.
             setRowHeight(20);
        public TreeTableModel getTreeTableModel(){
          return getModel();
        }Something like this. Didn't test it!
    -Puce

  • JTreeTable and LookandFeel

    Hi, All
    Currently I have some troubles with subj.The main problem -- painting time of the tree/table cells.Best perfomance in "standard" java L&F,after Win L&F and at least Motif. I'm not sure but think that is trouble of L&F.I amcorrect?
    and one more.May be somebody know examples of using JTreeTable classes.
    Thank to all.

    I have figured out why JTreeTable is not working with Motif L&F.
    The row hieght of the JTable has to be adjusted for Motif. You may use
    the following code in the JTreeTable contructor.
    // And update the height of the table row to match that of the tree.
    int rowHeight = UIManager.getInt("Tree.rowHeight");
    if (rowHeight > 0) {
    setRowHeight(rowHeight);
    } else {
    if (tree.getRowHeight() < 1) {
    // Metal looks better like this.
    setRowHeight(20);

  • ToolTip for each node of the Tree in JTreeTable?

    Hello! I have the problem that a ToolTip i have set in the TreeCellRenderer would not been displayed! Only one ToolTip will pop up over the JTreeTable with the ToolTipText that was set in the first CellRenderer. Does everybody have an idea?

    OK! Its done! The solution does not help exact, but it gives my the way! With the coordinates of the MouseEvent I can get the Value of the current table row and set the ToolTip text new. Teh ToolTipManager automatically repaints the ToolTip whit the new text and position.

Maybe you are looking for