更改JTree中节点的名称。

时间:2022-07-27 12:37:24

I am trying to change the name of a node in my JTree. I use the following code to do so:

我正在尝试更改JTree中的一个节点的名称。我使用下面的代码来这样做:


    /**
     * Change the name of the currently selected node
     * @param newName Name to change the node too
     */
    public void changeNodeName(String newName) {
        //get the path to the selected nod
        TreePath selectedPath = mainWindow.getStructureTree().getSelectionPath() ;
        //make sure there is no other node with this name
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPath.getLastPathComponent();
        //change its name
        node.setUserObject(newName);
}

This code works ok. So say I want to rename node b in the picture below to c. The code does it correctly as the pictures illustrate.

这段代码工作好。所以说,我想将图中的节点b重命名为c。

更改JTree中节点的名称。更改JTree中节点的名称。

However, if I then drag the node and place it somewhere else in the tree, its name returns to the original name of b.

但是,如果我拖拽节点并将其放置在树的其他位置,它的名称将返回到b的原始名称。

更改JTree中节点的名称。更改JTree中节点的名称。

So obviously I am not changing something correctly here. How do I or what do I change so the nodes value stays changed?

很明显,我在这里没有改变什么。如何改变节点值不变?

Thanks

谢谢

EDIT:

编辑:

I have a class which extends DefaultMutableTreeNode. Here is the source

我有一个扩展DefaultMutableTreeNode的类。这是源


package Structure;

import GUI.Window;
import Logging.LogRunner;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

/**
 * This class provides the basic functionality that all subclass of the structre
 * will need such as a pop up menu, and adding new nodes.
 * @author dvargo
 */
public abstract class BCStructure extends DefaultMutableTreeNode
{
    /**
     * The root node to which this class belongs
     */
    DefaultMutableTreeNode root;
    /**
     * Reference to the main window
     */
    Window mainWindow;
    /**
     * Name of this node
     */
    String name;
    /**
     * The pop up menu
     */
    JPopupMenu Pmenu;
    /**
     * The pop up menu intems
     */
    JMenuItem deleteMenuItem,renameMenuItem,newSectionMenuItem,newPageMenuItem;

    /**
     * What type of node this is
     */
    String type;

    /**
     * Basic constructor that adds a pop up menu, sets the name, and initalizes values
     * @param newName - Name for this node
     * @param inWindow - Reference to the main window.
     */
    public BCStructure(String newName,Window inWindow)
    {
        this(newName,inWindow,true);      
    }

    /**
     * Returns the type of node this is
     * @return Page if the node is a page, Module if the node is a module, Section
     * if the node is a section
     */
    public String getType()
    {
        return type;
    }


    /**
     * Returns a copy of this node
     * @return
     */
    public abstract BCStructure copy();

    /**
     * If this is a page, this constructor should be called, it will not allof a page to
     *have any children
     * @param newName - Name for the page
     * @param inWindow - Refernce to the main window
     * @param letChildren - False to disallow this node from having children
     */
    public BCStructure(String newName,Window inWindow,boolean letChildren)
    {
        super(newName,letChildren);
        mainWindow = inWindow;
        name = newName;
        //add the popup menu
        addPopUp();
    }



    /**
     * Updates a specific node
     * @param parentNode The parent node to update
     */
    public void update(DefaultMutableTreeNode parentNode)
    {
        ((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
        mainWindow.getStructureTree().repaint();

    }

    /**
     * Returns the node that is currently selected (by being clicked on) in the tree
     * @return Node that is selected in the tree
     */
    public DefaultMutableTreeNode getSelectedNode()
    {
        return (DefaultMutableTreeNode)mainWindow.getStructureTree().getLastSelectedPathComponent();
    }

    /**
     * Returns the TreePath to this node
     * @return The TreePath to this node
     */
    public TreePath getTreePath()
    {
        return new TreePath(this.getPath());
    }

    /**
     * Sets the selected node in the tree
     * @param node The node to set selected in the tree
     */
    public void setSelectedNode(BCStructure node)
    {
        mainWindow.getStructureTree().setSelectionPath(new TreePath(node.getPath()));
        update(node);
    }

    /**
     * Change the name of the currently selected node
     * @param newName Name to change the node too
     */
    public void changeNodeName(String newName) {
        //get the path to the selected nod
        TreePath selectedPath = mainWindow.getStructureTree().getSelectionPath() ;
        //make sure there is no other node with this name
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPath.getLastPathComponent();
        DefaultMutableTreeNode nodeParent = (DefaultMutableTreeNode) node.getParent();
        if(nodeParent != null)
        {
            for(int i = 0; i lt nodeParent.getChildCount(); i++)
            {
                DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) nodeParent.getChildAt(i);
                if(currNode.getUserObject().equals(newName))
                {
                    JOptionPane.showMessageDialog(mainWindow,"Another page or section already has this name in this level. Please select another.");
                    return;
                }
            }
        }
        //change its name
        node.setUserObject(newName);
        //mainWindow.getStructureTree().getModel().valueForPathChanged(selectedPath, newName);



        update(getSelectedNode());
    }

    /**
     * Adds a new section node to the tree
     * @param newName Name for this node
     */
    public void addNewSectionNode(String newName) {


        DefaultMutableTreeNode temp = getSelectedNode();
        Section newNode = null;
        if(temp == null)
        {
            LogRunner.dialogMessage(this.getClass(),"Please select a node to add this section to.");
        }

        else
        {
            newNode = new Section(newName,mainWindow);
            try
            {
                temp.add(newNode);
            }
            catch(java.lang.IllegalStateException e)
            {
                LogRunner.getLogger().warning("You can not add a section to a page");
                temp = (DefaultMutableTreeNode) temp.getParent();
                temp.add(newNode);
            }
        }
        //set the selected node to the previously selected node

        update(temp);

        if(newNode != null)
        {
            mainWindow.getStructureTree().setSelectionPath(new TreePath(newNode.getPath()));

        }
    }

    /**
     * Adds a new page to this tree
     * @param newName Name for the node
     * @return The newly created page
     */
    public Page addNewPageNode(String newName)
    {

        TreePath oldPath = mainWindow.getStructureTree().getSelectionPath();
        //Section newSection = new Section(newSectionName);
        DefaultMutableTreeNode temp = getSelectedNode();
        Page newPage = null;
        if(temp == null)
        {
            LogRunner.dialogMessage(this.getClass(),"Please select a module or section to add this section to.");
        }

        else
        {
            newPage = new Page(newName,mainWindow);
            try
            {
                temp.add(newPage);

            }
            catch(java.lang.IllegalStateException e)
            {
                LogRunner.getLogger().warning("You can not add any more nodes to a page.");
                temp = (DefaultMutableTreeNode) temp.getParent();
                temp.add(newPage);

            }
        }
        update(temp);
        mainWindow.getStructureTree().setSelectionPath(oldPath);
        return newPage;
    }


    /**
     * Propmpts the user to entere a new name for a node that is selected
     */
    private void rename()
    {
        String newname = JOptionPane.showInputDialog("New name?");
        changeNodeName(newname);
    }
    /**
     * Deletes the selected node from the tree
     */
    private void delete()
    {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)mainWindow.getStructureTree().getLastSelectedPathComponent();
        if(node == null) return;

        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)(node.getParent());
        if(parentNode == null) return;

        //remove node
        parentNode.remove(node);
        ((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
    }

    /**
     * Deletes a specific node from the tree
     * @param node The node to delete
     */
    protected void delete(DefaultMutableTreeNode node)
    {
         if(node == null) return;

        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)(node.getParent());
        if(parentNode == null) return;

        //remove node
        parentNode.remove(node);
        ((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
    }


    /**
     * Adds the popup menu functionality to the tree
     */
    private void addPopUp()
    {

        Pmenu = new JPopupMenu();
        newSectionMenuItem = new JMenuItem("Add New Section");
        Pmenu.add(newSectionMenuItem);
        newPageMenuItem = new JMenuItem("Add New Page");
        Pmenu.add(newPageMenuItem);
        Pmenu.add(new JSeparator());
        deleteMenuItem = new JMenuItem("Delete");
        Pmenu.add(deleteMenuItem);
        renameMenuItem = new JMenuItem("Rename");
        Pmenu.add(renameMenuItem);


        //add actionlisteners to the menu items
        deleteMenuItem.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                delete();}
            }
        );

        renameMenuItem.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                rename();}
            }
        );

        newSectionMenuItem.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                mainWindow.createNewSectionPublicCall();}
            }
        );

        newPageMenuItem.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                mainWindow.createNewPagePublicCall();}
            }
        );

        //add action listener to the tree
        mainWindow.getStructureTree().addMouseListener(new MouseAdapter()
        {
            public void mouseReleased(MouseEvent Me)
            {
                if(Me.isPopupTrigger())
                {
                    Pmenu.show(Me.getComponent(), Me.getX(), Me.getY());
                }
            }
        });

        if(getClass().equals(Page.class))
        {
            newSectionMenuItem.setEnabled(false);
        }
    }


    /**
     * Returns all the nodes in this tree from doing a left heavy recursive
     * traversal of the tree from the given root
     * @param root The root from which to start the search
     * @return A list of the nodes
     */
    public ArrayList getAllNodesInOrder(BCStructure root)
    {
        ArrayList nodes = new ArrayList();
        getAllNodesInOrderRec(root, nodes);
        return nodes;
    }

    /**
     * Recursive function that gets the nodes in the tree
     * @param currNode
     * @param theNodes
     */
    private void getAllNodesInOrderRec(BCStructure currNode, ArrayList theNodes)
    {
        theNodes.add(currNode);
        for(int i = 0; i lt currNode.getChildCount(); i++)
        {
            currNode.getAllNodesInOrderRec((BCStructure) currNode.getChildAt(i), theNodes);
        }
    }


}


And in the example above, the actual nodes you are seeing are a subclass of BCStructure called Page. This is the actual class that I am renaming.

在上面的例子中,您看到的实际节点是BCStructure的一个子类,名为Page。这是我重新命名的实际类。


package Structure;

import Components.BCFrame;
import Components.Basic.BackGroundImage;
import GUI.Window;
import Logging.LogRunner;
import XMLProcessing.XMLWriter;
import java.awt.Color;
import java.awt.Dimension;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.tree.DefaultTreeCellRenderer;

/**
 * This class is responcible for holding the components the make up a page and
 * is accessible through the tree structure. In other words, this class is what
 * actually makes up a page. It holds the componenets in an array, and since it
 * node in a tree, it can be notified when it has been clicked, and load the
 * compoenents it is holding.
 * @author dvargo
 */
public class Page extends BCStructure
{
    /**
     * Holds all the componenets in the content pane so an action can be done on
     * all componenets. Also sets the added component to the current component.
     */
    private ArrayList theComponents = new ArrayList()
    {
        @Override
        public boolean add(BCFrame e)
        {
            e.setPage(selfReference);
            return super.add(e);
        }
    };


    /**
     * Self reference to this page
     */
    private Page selfReference = this;

    /**
     * The dimensions of this page. It defualts to a medium page size
     */
    private Dimension pageSize = Window.NORMAL;

    /**
     * This bages background;
     */
    private BackGroundImage background;

    /**
     * Constructor that sets the node up in the tree and inializes values.
     * @param newName - Name for this node
     * @param inWindow - Reference to the main window
     * @param inRoot - The section or module that is the root for this page.
     */
    public Page(String newName, Window inWindow)
    {
        super(newName, inWindow,false);
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
        ImageIcon theImage = new ImageIcon(new JFrame().getToolkit().getImage(getClass().getResource("/GUI/fileIcon.png")));
        renderer.setLeafIcon(theImage);
        //set the background color to white, there will always be a background
        background = new BackGroundImage(0,0,pageSize.width,pageSize.height,mainWindow);
        background.setColor(Color.WHITE);
        theComponents.add(background);
        //you must add this to the content pane to keep indexes correct. it will not display anything though
        mainWindow.getComponentContentPane().add(background,0);
        mainWindow.getContentPanePanel().repaint();
    }


    /**
     * Loads all the componenets held in the arraylist to to the screen.
     */
    public void loadPage()
    {
        //remove the background of the previous page
        mainWindow.getComponentContentPane().removeAll();
        mainWindow.setPageSizeComboSeleted(pageSize);
        background.setSize(pageSize);
        mainWindow.getComponentContentPane().setPreferredSize(pageSize);
        mainWindow.getComponentContentPane().setSize(pageSize);
        for(BCFrame currentComp : theComponents)
        {
            mainWindow.getComponentContentPane().add(currentComp);
            currentComp.setVisible(true);
            currentComp.revalidate();
            currentComp.repaint();
            currentComp.setPage(this);
       }

        mainWindow.getComponentContentPane().repaint();
        mainWindow.getComponentContentPane().revalidate();

    }

    /**
     * Writes the componenets to file in XML.
     * @param filePath - The path and name of the file to write.
     */
    public void save(String filePath)
    {
        XMLWriter theWriter = new XMLWriter();
        for(int i = 0; i  newComponents)
    {
        theComponents = newComponents;
        boolean backgroundExists = false;
        for(BCFrame curr : theComponents)
        {
            if(curr.getClass().equals(BackGroundImage.class))
            {
                background = (BackGroundImage) curr; //make sure background isnt null
                backgroundExists = true;
            }
            curr.setPage(this);
        }
        if(backgroundExists)
        {
            return;
        }
        LogRunner.getLogger().severe("Could not find a background while setting the components, adding a new dfualt white one");
        BackGroundImage bgi= new BackGroundImage();
        bgi.setSize(pageSize);
        bgi.setColor(Color.WHITE);
        theComponents.add(bgi);
        background = bgi;
    }

    public ArrayList getComponents()
    {
        return theComponents;
    }



}



2 个解决方案

#1


2  

I figured it out. If you notice in BCStructure, it has a value called name. Whenever I change the name of the node I did not update this value. Then if you notice in the copy() of the Page class, it uses this name variable. Copy gets used in the drag and drop process. If name was not updated, it would be using the old value which is why I saw the behavior I did. Kind of simple to see but hard to explain. Thanks all for your help.

我想出来。如果在BCStructure中注意到,它有一个名为name的值。每当我更改节点名时,我没有更新此值。如果您注意到页面类的copy(),它使用这个名称变量。复制在拖放过程中使用。如果名称没有更新,它将使用旧值,这就是为什么我看到了我的行为。有点简单,但很难解释。谢谢你的帮助。

#2


1  

I cannot see the code you are using to create the TreeModel, however i am guessing that you are not using mutable nodes:

我看不到您用来创建TreeModel的代码,但是我猜测您没有使用可变节点:

http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/tree/MutableTreeNode.html#setUserObject%28java.lang.Object%29

http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/tree/MutableTreeNode.html setUserObject % 28 java . lang . object % 29

#1


2  

I figured it out. If you notice in BCStructure, it has a value called name. Whenever I change the name of the node I did not update this value. Then if you notice in the copy() of the Page class, it uses this name variable. Copy gets used in the drag and drop process. If name was not updated, it would be using the old value which is why I saw the behavior I did. Kind of simple to see but hard to explain. Thanks all for your help.

我想出来。如果在BCStructure中注意到,它有一个名为name的值。每当我更改节点名时,我没有更新此值。如果您注意到页面类的copy(),它使用这个名称变量。复制在拖放过程中使用。如果名称没有更新,它将使用旧值,这就是为什么我看到了我的行为。有点简单,但很难解释。谢谢你的帮助。

#2


1  

I cannot see the code you are using to create the TreeModel, however i am guessing that you are not using mutable nodes:

我看不到您用来创建TreeModel的代码,但是我猜测您没有使用可变节点:

http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/tree/MutableTreeNode.html#setUserObject%28java.lang.Object%29

http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/tree/MutableTreeNode.html setUserObject % 28 java . lang . object % 29