I have a JTree with a custom TreeModel and a custom TreeRenderer. The Tree Model contains a bunch of objects of different types. One of these types is displayed differently
A custom editor is required. MyTreeCellEditor
, illustrated here, shows one approach. It updates an arbitrary attribute of a userObject
, which is named Resource
and held in a DefaultMutableTreeNode
. As the attribute is text, it also uses the DefaultTreeCellRenderer
. Your custom TreeModel
probably manages a similar userObject
that is the parent of your "objects of different types."
There is no way around a custom editor and it is the shortest solution possible :-) Additionally, you'll need some means in the data realm that can interpret the editing value as appropriate and update itself, f.i. a custom node.
F.i (will comment it later, my lame firefox on this machine is driving me up the walls)
/**
* Basic code stolen from @trashgod at
* @see http://stackoverflow.com/a/11113648/230513
*/
public class TreeEditDemo extends JPanel {
private JTree tree;
private DefaultMutableTreeNode root;
private DefaultTreeCellEditor editor;
public TreeEditDemo() {
super.setLayout(new GridLayout());
root = new DefaultMutableTreeNode("Nodes");
root.add(new MyResourceNode(new Resource("one", "first")));
root.add(new MyResourceNode(new Resource("two", "first")));
tree = new JTree(root);
tree.setEditable(true);
editor = new MyTreeCellEditor(tree,
(DefaultTreeCellRenderer) tree.getCellRenderer());
tree.setCellEditor(editor);
this.add(new JScrollPane(tree));
}
private static class MyTreeCellEditor extends DefaultTreeCellEditor {
public MyTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
super(tree, renderer);
}
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean isSelected, boolean expanded, boolean leaf, int row) {
if (value instanceof MyResourceNode) {
value = ((MyResourceNode) value).getName();
}
return super.getTreeCellEditorComponent(tree, value, isSelected, expanded,
leaf, row);
}
@Override
public boolean isCellEditable(EventObject e) {
return super.isCellEditable(e)
&& ((TreeNode) lastPath.getLastPathComponent()).isLeaf();
}
}
public static class MyResourceNode extends DefaultMutableTreeNode {
/**
* @param resource
*/
public MyResourceNode(Resource resource) {
super(resource);
}
@Override
public void setUserObject(Object userObject) {
if (userObject instanceof String) {
setName((String) userObject);
} else if (userObject instanceof Resource) {
super.setUserObject(userObject);
}
}
public void setName(String name) {
if (getUserObject() != null) {
getUserObject().setName(name);
}
}
public String getName() {
if (getUserObject() != null) {
return getUserObject().getName();
}
return null;
}
@Override
public Resource getUserObject() {
return (Resource) super.getUserObject();
}
}
private static class Resource {
String name;
private String category;
public Resource(String name, String category) {
this.name = name;
this.category = category;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
// BEWARE: don't do this in production code!
return name + " (" + category + ")";
}
}
private void display() {
JFrame f = new JFrame("TreeEditorDemo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TreeEditDemo().display();
}
});
}
}