I\'m a total newbee regarding GUI programming and maybe my problem has a quite simple solution. I\'m trying to implement a Java Swing GUI that serves as an editor for a tree
Not exactly sure, but I think you're looking for something like this
public class RenameNode extends AbstractAction
implements TreeSelectionListener, CellEditorListener {
// Replace with whatever you're storing your text fields with
private FieldStorage fields;
private JTree tree;
public RenameNode(FieldStorage fields, JTree tree) {
this.fields = fields;
this.tree = tree;
}
public void actionPerformed(ActionEvent ev) {
// "mouseOverPath" is the Treepath were the mouse was placed on
// when the popup menu was opened
if (tree.existsMouseOverPath()) {
tree.startEditingAtPath(tree.mouseOverPath);
} else if (tree.getSelectionCount() != 0) {
tree.startEditingAtPath(tree.getSelectionPath());
}
}
public void valueChanged(TreeSelectionEvent e) {
tree.startEditingAtPath(tree.getSelectionPath());
setFieldText();
}
public void editingCanceled(ChangeEvent e) {
// empty
}
public void editingStopped(ChangeEvent e) {
setFieldText();
}
private void setFieldText() {
MyTreeNode node = (MyTreeNode) tree.getSelectionPath()
.getLastPathComponent();
String text = node.getUserObject().toString();
fields.getFieldFor(node).setText(text);
}
}
Then when you're initializing your tree add
RenameNode renameNodeAction = new RenameNode(fields, tree);
tree.addTreeSelectionListener(renameNodeAction);
// editor is your TreeCellEditor. Can be the DefaultTreeCellEditor
// if you haven't already made your own
editor.addCellEditorListener(renameNodeAction);
tree.setCellEditor(editor);
tree.setEditable(true);
This will synchronize your tree edits with your fields.
BTW, I like that you're adhering to MVC really well. But also, your design sounds really complicated. You might want to rethink some of the features to something more streamlined.
Wow, that's a lot of detail! Thanks!
Okay, I do something similar with JTable
's (insert/delete rows).
Essentially you want an Action
that can take a reference to a JTree
. This Action
can then be supplied to your File menus, Popup Menus and event assigned to key strokes. If you write the code super efficiently, the same action can be shared, but this is not an essential requirement.
What you want to do, is to let the view and model do what they are designed to do, you action is simply the catalyst for getting the process started.
So basically you could do something like:
public class RenameNodeAction extends AbstractAction {
private JTree tree;
public RenameNodeAction(JTree tree) {
this.tree = tree;
// Initialise action as you require...
}
// Access to the tree, provide mostly so you can extend the action
public JTree getTree() {
return tree;
}
public void actionPerformed(ActionEvent evt) {
JTree tree = getTree();
TreePath path = tree.getSelectionPath();
if (path != null && tree.isPathEditable(path)) {
tree.startEditingAtPath(path);
}
}
}
To make it a little more advanced, you could attach a TreeSelectionListener
to the supplied tree and change the enabled
state of the action based on the selection.
So when nothing is selected, you would disable the action, if the selected wasn't editable, you would disable the selection, etc.
What this means (as you have correctly trying to achieve) is that the code to achieve this is centralised and reusable. You can apply the same action (the same instance or multiple instances) to File menus, tool bar buttons, JButtons
, popup menus and key strokes and be assured that the same code is executing for each.
A complete guide to application design in beyond the scope of Stackoverflow. Instead, start with the example TreeIconDemo
shown in How to Use Trees. Notice how it adds a TreeSelectionListener
to the tree
in order to update a nearby JEditorPane
. Now, add another TreeSelectionListener
to a different view to see how you could update the new view, too. You might also get some insight from this related answer.
Addendum: Starting from this example, you can do something like the following. Changing the selection updates the textField
to show the selected node's name. Editing either the node (typically F2) or the textField
changes the selected node's name.
private JTextField textField = new JTextField(10);
...
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath path = e.getNewLeadSelectionPath();
if (path != null) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
Resource user = (Resource) node.getUserObject();
textField.setText(user.toString());
} else {
textField.setText("");
}
}
}
});
textField.addActionListener(new AbstractAction("edit") {
@Override
public void actionPerformed(ActionEvent e) {
TreePath path = tree.getSelectionPath();
if (path != null) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
String s = textField.getText();
Resource user = (Resource) node.getUserObject();
user.setName(s);
treeModel.reload(node);
}
}
}
});