I have a JTree with a DefaultTreeModel and some DefaultMutableTreeNodes attached to it.
I'm searching for a way to change the node's displayName, but I don't want to change the userObject because I need it to be exactly what it was set to.
Furthermore I can't simply override the toString-method for my userObject because I'm using the toString elsewhere in my code where the respective changes to this method would be inappropriate.
So the question is if it is possible to achieve a rename of a node with the above conditions?
Thanks in advance
Raven
EDIT: A small code example:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultMutableTreeNode;
public class TreeNodeRenameExample extends JFrame {
private JPanel contentPane;
private JTree tree;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TreeNodeRenameExample frame = new TreeNodeRenameExample();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TreeNodeRenameExample() {
initGUI();
}
private void initGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
this.contentPane = new JPanel();
this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
this.contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(this.contentPane);
{
this.tree = new JTree();
this.tree.setModel(new DefaultTreeModel(
new DefaultMutableTreeNode("JTree") {
{
add(new DefaultMutableTreeNode(new testObj("Peter")));
add(new DefaultMutableTreeNode(new testObj("Stephen")));
}
}
));
this.contentPane.add(this.tree, BorderLayout.CENTER);
}
}
public class testObj {
private String name;
public testObj(String name) {
this.name = name;
}
public String toString() {
return "Name: " + this.name;
}
}
}
The thing I want to do is do change the text on the TreeNodes to something different. For example to "MyTreeNode1" and "MyTreeNode2" but I want to remain the userObject of these two nodes my testObj and the toString mehtod can't be changed either...
If you want to use the TestObj
class for the tree user objects and you do not want to change the toString
method, you could use a custom TreeNode
class (instead of the DefaultMutableTreeNode
class). Using this custom class, the toString
method could be overridden to not (always) use the user object, but to use an alternative name instead.
The custom TreeNode
class could for example be called AliasTreeNode
and can receive an alias (= an alternative node name) when the node is created or later when some event occurs. The AliasTreeNode.toString
method checks whether an alias is set; if there is an alias this is returned and else DefaultMutableTreeNode.toString()
is returned.
This modified version of your code demonstrates the approach. The nodes get an alias when they are constructed and a different alias when a button is pressed:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.tree.*;
public class TreeNodeRenameExample extends JFrame {
private JPanel contentPane;
private JTree tree;
private AliasTreeNode peterNode = new AliasTreeNode(new TestObj("Peter"),
"Alias 1");
private AliasTreeNode stephenNode = new AliasTreeNode(new TestObj("Stephen"),
"Alias 2");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TreeNodeRenameExample frame = new TreeNodeRenameExample();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TreeNodeRenameExample() {
initGUI();
}
private void initGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
this.contentPane = new JPanel();
this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
this.contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(this.contentPane);
{
this.tree = new JTree();
this.tree.setModel(new DefaultTreeModel(
new DefaultMutableTreeNode("JTree") {
{
add(peterNode);
add(stephenNode);
}
}
));
this.contentPane.add(this.tree, BorderLayout.CENTER);
JButton changeNamesButton = new JButton("Change node names");
this.contentPane.add(changeNamesButton, BorderLayout.SOUTH);
changeNamesButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
peterNode.setAlias("MyTreeNode1");
stephenNode.setAlias("MyTreeNode2");
}
});
}
}
public class TestObj {
private String name;
public TestObj(String name) {
this.name = name;
}
public String toString() {
return "Name: " + this.name;
}
}
public class AliasTreeNode extends DefaultMutableTreeNode {
private String alias;
public AliasTreeNode(Object userObject, String alias) {
super(userObject);
this.alias = alias;
}
public void setAlias(String alias) {
this.alias = alias;
// Notify the tree model of the changed node
// (see http://stackoverflow.com/a/10375802/1694043).
((DefaultTreeModel) tree.getModel()).nodeChanged(this);
}
@Override
public String toString() {
return (alias != null) ? alias : super.toString();
}
}
}