3

I'm learning my way around Java JTree's but I have this little problem I can't figure out. Using a tutorial I found on Oracle's site, I've mimicked a tree structure they demonstrate. The problem is, I want the Folder "websites" to be an empty folder, but JTree is displaying it as though it is a file. How can I tell the JTree that "websites" is in fact an empty folder?

UPDATE

I've started working on a simple 'contact manager'. What I want to do basically it make the name look like folders (since I want to add info to each of them), but without adding stuff. i.e. Some might not have any info in them, but I would still like them to look like folders.

enter image description here

Code for the Browser class:

import java.awt.Component;
import java.io.File;
import java.util.Iterator;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;


public class Browser extends JFrame implements javax.swing.tree.TreeModel {


    private JTree tree;
    ManagerOfContacts mngrOfContacts;

    public Browser() {

        //Generates the ManagerOfContacts and associated Contacts
        Driver driver = new Driver();
        mngrOfContacts = driver.getManagerOfContacts();
        //---------------------------\\


        DefaultMutableTreeNode contacts = new DefaultMutableTreeNode("Contacts");
        createNodes(contacts);
        tree = new JTree(contacts);

        JScrollPane treeView = new JScrollPane(tree);

        add(treeView);

        setSize(400,400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    public void createNodes(DefaultMutableTreeNode top){
        DefaultMutableTreeNode contactName;

        Iterator<Contact> contactItr = mngrOfContacts.getIterator();
        while(contactItr.hasNext()){
            contactName = new DefaultMutableTreeNode(contactItr.next());
            top.add(contactName);
        }
    }

    public static void main(String[] args) {
        Browser browsr = new Browser();
    }

}
CodyBugstein
  • 21,984
  • 61
  • 207
  • 363
  • You have to "play" with the TreeCellRenderer. Would be cool if you could post some code so that we could guide you correctly. – Guillaume Polet Dec 06 '12 at 16:27
  • 2
    have a look at `allowsChildren` – kleopatra Dec 06 '12 at 17:17
  • Where should I look for "allowsChildren"? – CodyBugstein Dec 06 '12 at 19:30
  • Is the goal to create a hierarchical folder/document type tree as quickly and easily as possible using any programming language, including Java, or is it to do it specifically using Java JTree? – Arun Taylor Dec 06 '12 at 20:05
  • @ArunTaylor The goal is to be using a JTree, but in general, can you suggest a better method? – CodyBugstein Dec 07 '12 at 15:17
  • 1
    Initially, I also started out with Java and later decided that if the tree could be displayed in a browser in realtime without any browser add-ons, plug-ins or extensions, then it could be used on a smartphone, tablet or desktop and be a lot more useful. At the same time, I thought making it usable from any programming language that supported sockets would make it even more useful. And, The end result is here and now we are using hierarchical structure to create web/cloud based realtime apps. Disclosure: I work for Accord Software, Inc. (accord.com) – Arun Taylor Dec 07 '12 at 17:05
  • @Imray I forgot the link -- it is ActiveML.com. Disclosure: I work for Accord Software, Inc. (accord.com) – Arun Taylor Dec 07 '12 at 17:22

2 Answers2

9

This is how you create your own TreeCellRenderer which tells your JTree whatever you want. Since you are using a default tree model with DefaultMutableTreeNode as nodes you have to extract their user object and decide what to paint based on that. Note that the default renderer is just an extended JLabel, which is why you can use setIcon(...), setText(...), etc. inside it.

The reason why your leaf nodes are painted with file icons is probably that the default renderer chooses the icon based on DefaultMutableTreeNode.getAllowsChildren() similarily to how I use Contact.isSomeProperty().

import java.awt.Component;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;


public class Browser extends JFrame {


    private JTree tree;
    //ManagerOfContacts mngrOfContacts;

    public Browser() {

        //Generates the ManagerOfContacts and associated Contacts
        //Driver driver = new Driver();
        //mngrOfContacts = driver.getManagerOfContacts();
        //---------------------------\\


        DefaultMutableTreeNode contacts = new DefaultMutableTreeNode("Contacts");
        createNodes(contacts);
        tree = new JTree(contacts);

        // use your own renderer (!)
        tree.setCellRenderer(new MyTreeCellRenderer());

        JScrollPane treeView = new JScrollPane(tree);

        add(treeView);

        setSize(400,400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    public final void createNodes(DefaultMutableTreeNode top){
        DefaultMutableTreeNode contactName;

        // dummies
        List<Contact> contacts = new ArrayList<Contact>();
        contacts.add(new Contact("Me", true));
        contacts.add(new Contact("You"));

        Iterator<Contact> contactItr = contacts.iterator();
        while(contactItr.hasNext()){
            contactName = new DefaultMutableTreeNode(contactItr.next());
            top.add(contactName);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Browser browsr = new Browser();
            }
        });

    }

    // dummy
    private static class Contact {

        private boolean someProperty;
        private String name;

        public Contact(String name) {
            this(name, false);
        }

        public Contact(String name, boolean property) {
            this.someProperty = property;
            this.name = name;
        }

        public boolean isSomeProperty() {
            return someProperty;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    // this is what you want
    private static class MyTreeCellRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

            // decide what icons you want by examining the node
            if (value instanceof DefaultMutableTreeNode) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
                if (node.getUserObject() instanceof String) {
                    // your root node, since you just put a String as a user obj                    
                    setIcon(UIManager.getIcon("FileView.computerIcon"));
                } else if (node.getUserObject() instanceof Contact) {
                    // decide based on some property of your Contact obj
                    Contact contact = (Contact)  node.getUserObject();
                    if (contact.isSomeProperty()) {
                        setIcon(UIManager.getIcon("FileView.hardDriveIcon"));
                    } else {
                        setIcon(UIManager.getIcon("FileChooser.homeFolderIcon"));
                    }
                }
            }

            return this;
        }

    }
}

This should get you started. You should read more about this in a JTree tutorial.

predi
  • 5,528
  • 32
  • 60
  • Awesome answer - thanks! Can you explain your main method `SwingUtilities.invokeLater(new Runnable() { public void run() { Browser browsr = new Browser();` – CodyBugstein Dec 07 '12 at 15:22
  • Is the class `MyTreeCellRenderer` supposed to be inside the main class? – CodyBugstein Dec 07 '12 at 16:53
  • @Imray Check this [question](http://stackoverflow.com/questions/3018165/why-do-people-run-java-guis-on-the-event-queue) for an answer to your first question. You can put the renderer class anywhere you want like any other class. – predi Dec 08 '12 at 11:04
  • 1
    Works great ! Thank you :) By the way, to get the list of available icons : System.out.println("Default icons : "+UIManager.getDefaults()); – Kalzem Feb 20 '13 at 11:01
8

Configure the treeModel to query the askAllowsChildren property of its node to decide whether it should regarded as a folder (even without having children)

DefaultMutableTreeNode root = new DefaultMutableTreeNode("I'm the root");
// node allowsChildren - that's the default 
root.add(new DefaultMutableTreeNode("folder always"));
// node doesn't accept children
root.add(new DefaultMutableTreeNode("folder never", false));
// model configured to query the node's allowsChildren property
DefaultTreeModel model = new DefaultTreeModel(root, true);
kleopatra
  • 51,061
  • 28
  • 99
  • 211