Uncertainties regarding Implementation of Actions and Usage of a single Model with multiple Views

前端 未结 3 887
死守一世寂寞
死守一世寂寞 2020-12-12 02:59

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

相关标签:
3条回答
  • 2020-12-12 03:16

    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.

    0 讨论(0)
  • 2020-12-12 03:19

    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.

    0 讨论(0)
  • 2020-12-12 03:34

    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);
                }
            }
        }
    });
    
    0 讨论(0)
提交回复
热议问题