草庐IT

java - 更改 JTree 中的节点名称

coder 2024-03-21 原文

我正在尝试更改 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);
}

这段代码工作正常。假设我想将下图中的节点 b 重命名为 c。如图所示,代码正确执行。

但是,如果我随后拖动该节点并将其放置在树中的其他位置,它的名称将恢复为 b 的原始名称。

很明显我没有在这里正确地改变某些东西。我要如何或更改什么才能使节点值保持更改?

谢谢

编辑:

我有一个扩展 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);
        }
    }


}


在上面的示例中,您看到的实际节点是 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;
    }



}



最佳答案

我想通了。如果您在 BCStructure 中注意到,它有一个名为 name 的值。每当我更改节点名称时,我都不会更新此值。然后,如果您注意到 Page 类的 copy() 中,它使用了这个名称变量。复制在拖放过程中使用。如果名称未更新,它将使用旧值,这就是我看到我所做的行为的原因。看起来很简单,但很难解释。感谢你的帮助。

关于java - 更改 JTree 中的节点名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5121122/

有关java - 更改 JTree 中的节点名称的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

    如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

  5. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  9. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  10. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

    我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

随机推荐