Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / December 2007

Tip: Looking for answers? Try searching our database.

Struggling with Swingx TreeTableModel

Thread view: 
Rogan Dawes - 11 Dec 2007 16:15 GMT
Hi folks,

I am struggling to figure out what I am doing wrong in this TreeModel
implementation. It seems like certain nodes are not being rendered, even
though I can see that the (custom) renderer *is* actually being called
for all the rows. Which is just weird!

I am trying to show a JSON Object hierarchy in a JTree (actually a
SwingX JXTreeTable, which is where this first manifested).

The example shows a broken example, and a working example (if you
uncomment the code in main() at the bottom). As can be seen from the
println statements in the TreeCellRenderer, it *is* being called for
each row, but the row is not actually being rendered at all.

The obvious difference between the two examples is that the non-rendered
nodes now have a child, but I'd hope that that shouldn't make any real
difference!

Any ideas?

Rogan

===== Snip TreeTableDemo.java =====

package jtreetable;

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class TreeTableDemo extends JFrame {

    public TreeTableDemo(String title, Object data) {
        super("TreeTableDemo - " + title);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JsonTreeModel model = new JsonTreeModel(data);
        JTree tree = new JTree(model);
        tree.setRootVisible(true);
        tree.setCellRenderer(new JsonTreeTableCellRenderer());
        getRootPane().setLayout(new BorderLayout());
        getRootPane().add(new JScrollPane(tree), BorderLayout.CENTER);
        setSize(300, 200);
    }

    private class JsonTreeModel implements TreeModel {

        private Object json;

        public JsonTreeModel(Object json) {
            this.json = json;
        }

        // Empty, since the tree is static in this example
        public void addTreeModelListener(TreeModelListener l) {}

        public boolean isLeaf(Object node) {
            return false;
        }

        // Empty, since the tree is static in this example
        public void removeTreeModelListener(TreeModelListener l) {}

        // Empty, since the tree is static in this example
        public void valueForPathChanged(TreePath path, Object newValue) {}

        public Object getRoot() {
            return json;
        }

        public Object getChild(Object parent, int index) {
            if (parent instanceof Map) {
                Map map = (Map) parent;
                Iterator it = map.keySet().iterator();
                for (int i=0; i<index; i++) it.next();
                return map.get(it.next());
            } else if (parent instanceof Collection) {
                Iterator it = ((Collection) parent).iterator();
                for (int i=0; i<index; i++) it.next();
                return it.next();
            }
            throw new IndexOutOfBoundsException("'" + parent + "'
cannot have children!");
        }

        public int getChildCount(Object parent) {
            int count = 0;
            if (parent instanceof Map) {
                count = ((Map) parent).size();
            } else if (parent instanceof Collection) {
                count = ((Collection) parent).size();
            }
            return count;
        }

        public int getIndexOfChild(Object parent, Object child) {
            if (parent instanceof Map) {
                Iterator it = ((Map) parent).entrySet().iterator();
                for (int i=0; it.hasNext(); i++)
                    if (it.next() == child)
                        return i;
            } else if (parent instanceof Collection) {
                Iterator it = ((Collection) parent).iterator();
                for (int i=0; it.hasNext(); i++)
                    if (it.next() == child)
                        return i;
            }
            throw new IndexOutOfBoundsException("'" + parent + "'
cannot have children!");
        }

    }

    public class JsonTreeTableCellRenderer extends
DefaultTreeCellRenderer {
        public JsonTreeTableCellRenderer() {
        }

        public Component getTreeCellRendererComponent(JTree tree,
Object node,
                boolean sel, boolean expanded, boolean leaf, int row,
                boolean hasFocus) {
            node = row + ": '" + node.toString() + "'";
            System.out.println(node);
            super.getTreeCellRendererComponent(tree, node, sel, expanded,
                    leaf, row, hasFocus);
            return this;
        }
    }

    public static void main(String[] args) {
        ArrayList data = new ArrayList();
        for (int i=0; i< 3; i++) {
            data.add(new HashMap());
        }

        final TreeTableDemo broken = new TreeTableDemo("broken", data);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                broken.setVisible(true);
            }
        });

        data = new ArrayList();
        for (int i=0; i< 3 ; i++) {
            HashMap map = new HashMap();
            map.put("" + i, "Value " + i);
            data.add(map);
        }

//        final TreeTableDemo works = new TreeTableDemo("works", data);
//        SwingUtilities.invokeLater(new Runnable() {
//            public void run() {
//                works.setVisible(true);
//            }
//        });

    }
}
Rogan Dawes - 11 Dec 2007 19:42 GMT
> Hi folks,
>
[quoted text clipped - 18 lines]
>
> Rogan

Gah!

Replying to myself! :-(

So, it turns out that the problem is in the TreePath code, since it
doesn't use == for equality checks, but rather .equals().

Since the empty maps are equivalent, the TreePaths constructed are
equals(). Which means that the JTree gets confused :-(

See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4257782

So much for that!

Rogan


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.