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 like data structure. The GUI is divided into three
parts:
A tree viewer in the left quarter of the window displays the
tree structured data.
The large upper right area displays editors containing text fields,
tables and the like. Each different kind of object in the tree
structure has its own editor which is shown when it is selected in the
tree viewer.
The lower right area shows a console viewer. It is used to display
messages about specific actions.
I'm trying hard to obey a strict separation of the model from its
visualization in the tree viewers/editors in my program. Therefore I
created an instance of a sub-class of DefaultTreeModel (MyTreeModel)
which stores references to the business data and an instance of a
sub-class of JTree that provides the visual representation of the tree
structure.
I'm attempting to implement functionality that modifies the data using
Action classes. Any action (like CreateNode, RenameNode, DeleteNode)
is implemented in it's own action class (sub-class of AbstractAction).
The actions are used in the tree viewer's context menu and in the
applications "Edit" menu. But I also want to reuse some of them in
the editor parts of the GUI, e.g. the RenameNode action. And here I'm
currently stuck.
The tree viewer displays an icon along with the name for every node in
the tree. And the respective editor contains, among other
stuff, also a JTextField that shows the associated node's name.
I know that I can attach action objects to JMenu, JPopupMenu and
even to JTextField objects using the setAction method. I
did so and now I have a "Rename" menue entry in the program's "Edit"
menue, in the popup menue associated with the JTree that represents
the tree viewer and the JTextField showing the node name also has this
action attached to it.
To change the "Name" attribute of a tree node, I created the class
RenameNode as a sub-class of AbstractAction. As already mentioned the
name is displayed at each node in the tree viewer and the action
simply makes this text editable. The code doing this looks as follows
(in the class RenameNode):
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());
}
}
These if statements are needed to make the action work properly from:
-- the popup menu (first if statement; here the object which was under
the mouse when the popup menu is opened is made editable)
-- the application's menu (second if statement; here the tree node
that is currently selected -- if any -- is made editable).
Well, this works fine, in principle but in fact the renaming of the
node is not done through the code in the RenameAction class's
actionPerformed(ActionEvent ev) method. The real change of the node's
name is executed in the tree's MyTreeModel class in the method
valueForPathChanged() which is overridden as follows:
public class MyTreeModel extends DefaultTreeModel {
[...]
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
final MyTreeNode aNode = (MyTreeNode)path.getLastPathComponent();
if (newValue instanceof String) {
((MyNode) aNode.getUserObject()).setName((String) newValue);
} else {
aNode.setUserObject(newValue);
}
nodeChanged(aNode);
}
[...]
}
I have absolutely no clue how the concept of actions could properly be
applied here.
Even worse is the situation with the rename operation when it is
performed changing the text in the JTextField object. At the moment I
don't know how to implement that in a clean way. The JTextField should
get associated with a single node from the tree model structure as its
model and the attached action should modify that model and when this
model is changed the tree viewer would need to get notified to update
the respective node's name in the tree viewer.
I assume that the MyNode class (which is alrady a sub-class of
DefaultMutableTreeNode) would have to implement the interface Document
and the RenameAction class would have to modify it and then an event
would have to be issued to notify the tree viewer that displays the
changed node.
Bottom line: I must admit that I did not yet completely understand how
to properly implement an action that is to be used in multiple places
in a GUI and I don't completely understand how to implement a model
that can be used by multiple GUI objects (in my case a JTree and
a JTextField). Possibly all that is quite simple ...
Thanks in advance for any help!
Well the answers given were quite helpful in explaining how actions
can be used together with JTrees. But there is one more point I'd like to discuss.
In my GUI I have a tree representation of my business data combined
with editors for the data (the tree located in the left quarter of the window and aside of it a node type specific editor). All the nodes have names that can be changed. And, the editors contain a text field (implemented with a JTextField) in which the node's name is displayed and which can be edited too. My uncertainty here is as follows:
A JTextField allows to assign an action object as well as a
model to it. Actually the model would be a node object already viewed in the JTree. I think there should be a way to use the same model object used in the JTree also as a model for the JTextField in the editor and also reuse the Action class there. Regarding the reuse of the model I think my model class MyTreeNode will have to implement the Document interface too, correct? And when bringing up the node specific editor I'd have to associate the node currently selected in the JTree with the JTextField object using its setDocument() method.
Finally my RenameNodeAction would have to perform the change of the
JTextField's node's name.
So my central point is: making one model being displayd in multiple views and the reuse of just one RenameAction everywhere where a node is to be renamed. Does this make sense and is my idea how this must be accomplished feasible?
See Question&Answers more detail:
os