Is it proper to update a tree node using `nodeChanged`

…衆ロ難τιáo~ 提交于 2019-12-24 02:22:08

问题


I have a JTree and a JTextField. When I select a node on the tree, the text field will display the value of the node. I can then edit the text and save it to change the selected node's value. I use the DefaultTreeModel's nodeChanged method to update the tree.

Is this a proper way to tell the tree model to update its node? To me it looks ugly because I'm explicitly accessing the tree's model and telling it that something has happened.

Here's some code

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public class TextPaneTest extends JFrame {

    private JTextField textBox = null;
    private JTree tree = null;
    private JButton button = null;

    public static void main(String args[]) {
        new TextPaneTest();
    }

    public TextPaneTest() {

        // Main panel
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        // Panel holding tree
        JPanel treePanel = new JPanel();
        treePanel.setLayout(new BorderLayout());

        // Panel holding text field and button

        JPanel editPanel = new JPanel();
        editPanel.setLayout(new BorderLayout());

        // My textbox
        textBox = new JTextField();

        // button
        button = new JButton();
        button.setText("Save changes");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                String text = textBox.getText();
                node.setUserObject(text);
                DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
                model.nodeChanged(node);
            }
        });

        // My Tree
        DefaultMutableTreeNode top = new DefaultMutableTreeNode("Root");
        tree = new JTree(top);
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                textBox.setText(node.getUserObject().toString());
        }
        });

        JScrollPane scrollPane = new JScrollPane(tree);
        scrollPane.setHorizontalScrollBarPolicy(
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        // Add tree
        treePanel.add(scrollPane);
        panel.add(treePanel, BorderLayout.CENTER);

        // Add box and button to edit panel
        editPanel.add(textBox, BorderLayout.CENTER);
        editPanel.add(button, BorderLayout.SOUTH);

        // Add edit panel
        panel.add(editPanel, BorderLayout.SOUTH);

        // Add everything to the frame
        this.add(panel);
        this.setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }
}

回答1:


From poking around the JavaDoc and code for DefaultTreeModel and DefaultMutableTreeNode, I think what you are doing is ok. If you had changed the structure of the model (say by removing a node) then you would not need to call anything on the model, since the TreeModel would know that you did something to it. However, in this case, you are changing the contents of a node that the model references. So it seems reasonable that you would have to inform the TreeModel that the contents of one of its nodes is now different.

I may be missing something myself, but I think what you have is fine.




回答2:


Just for completeness: it might look slightly less ugly if you updated the node exclusively via model api

TreePath selected = tree.getSelectionPath();
tree.getModel().valueForPathChanged(selected, textBox.getText());



回答3:


Your example appears correct. Expanding on @matt's correct answer, this MVC illustration may offer some insight. Because the JTree view also allows editing, it may invoke methods of the model. The model in turn notifies all listeners, including the tree itself, by invoking fireTreeNodesChanged() on you behalf. To see the effect, add another listener:

tree.getModel().addTreeModelListener(new TreeModelListener() {
    @Override
    public void treeNodesChanged(TreeModelEvent e) {
        update(e);
    }

    @Override
    public void treeNodesInserted(TreeModelEvent e) {
        update(e);
    }

    @Override
    public void treeNodesRemoved(TreeModelEvent e) {
        update(e);
    }

    @Override
    public void treeStructureChanged(TreeModelEvent e) {
        update(e);
    }

    private void update(TreeModelEvent e) {
        System.out.println(e);
    }
});

Additional notes:

  • Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

  • Instead of using setSize(), override the tree panel's getPreferredSize() method and pack() the enclosing frame.

    JPanel treePanel = new JPanel(){
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 200);
        }
    };
    …
    this.pack();
    


来源:https://stackoverflow.com/questions/19432197/is-it-proper-to-update-a-tree-node-using-nodechanged

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!