简体   繁体   中英

After re-assign the JTree,getLastSelectedPathComponent() returns null

I have a JTree in my JFrame and use getLastSelectedPathComponent() to modify the value of select node. After I re-assign the JTree, the getLastSelectedPathComponent() returns null. The code that I re-assign the JTree as follows:

protected void refreshTree(JScrollPane jsptree) {
    DefaultMutableTreeNode rootNode;
    File rootSaveFile = new File(System.getProperty("user.dir") + "\\doc");
    if (rootSaveFile.exists()) {
        rootNode = new DefaultMutableTreeNode(rootSaveFile.getName());
        createFiles(rootNode, rootSaveFile.listFiles());
    } else {
        rootNode = new DefaultMutableTreeNode("error");
    }
    this.jtree = new JTree(rootNode);

    this.jsptree.updateUI();
    jsptree.setViewportView(jtree);
    jtree.setEditable(true);

}

You should not build a new JTree. You should update it's model instead.

Also it's possible you need an algorithm to restore expansion/selected state.

I am working on something similar, I'll post some code, but careful, IT'S NOT TESTED. This code is inside a TreeModel implementation.

public void refresh() {
    final TreePath[] selectionPaths = files.getSelectionPaths();
    final Enumeration<TreePath> expandedDescendants = files.getExpandedDescendants(new TreePath(root));
    SwingWorker sw = new SwingWorker() {

        @Override
        protected Object doInBackground() throws Exception {
            //HttpUtils.fetchSrc() returns a TreeNode
            syncModel(root, HttpUtils.fetchSrc()); 
            return null;
        }

        @Override
        public void done() {
            //Expand old paths

            //Select old paths

            files.repaint();
        }
    };
    sw.execute();
}

/**
 * Sync two tree nodes. This should be used when refreshing the files tree model.
 * @param localNode Local node
 * @param remoteNode Remote node
 */
private void syncModel(DirOrFile localNode, DirOrFile remoteNode) {
    // Remove deleted nodes
    for (int i = 0; i < localNode.getChildCount(); i++) {
        DirOrFile currentChild = (DirOrFile) localNode.getChildAt(i);
        // Search the 2nd tree for this child
        DirOrFile corespondent = null;
        for (int j = 0; j < remoteNode.getChildCount(); j++) {
            DirOrFile current = (DirOrFile) remoteNode.getChildAt(j);
            if (current.getUserObject().equals(currentChild.getUserObject())) {
                corespondent = current;
            }
        }
        // Corespondent not found, we need to remove this node from local tree
        if (corespondent == null) {
            localNode.remove(currentChild);
            notifyListeners(localNode); // Fire tree model change event
        } else if (corespondent.isDirectory()){
            // Recurively sync
            syncModel (currentChild, corespondent);
        }
    }

    // Add missing nodes
    for (int i=0; i < remoteNode.getChildCount(); i++) {
        DirOrFile remoteCurrent = (DirOrFile) remoteNode.getChildAt(i);
        // Search the 1st tree node to see if this node should be added.
        DirOrFile corespondent = null;
        for (int j=0; j < localNode.getChildCount(); j++) {
            DirOrFile localCurrent = (DirOrFile) localNode.getChildAt(j);
            if (localCurrent.getUserObject().equals(remoteCurrent.getUserObject())) {
                corespondent = remoteCurrent;
            }
        }
        // If no corespondent was found in local tree, add remote node
        if (corespondent == null) {
            localNode.insert(remoteCurrent, i);
            notifyListeners(localNode); // Fire tree model change event
        }
    }
}

I just encountered this problem, and reading you encountering the same issue helped me fix it. Here's what I think is happening. When you "rebuild" the tree by reassigning the tree variable to a new tree, you're swapping the original tree for an entirely different tree, including the listeners . So the getLastSelectedComponent() you call after destroying the old tree and replacing it with the old one is either A) calling the old version, still pointing to the old tree, which basically doesn't exist anymore(returning null), or B) calling the new version, which is not being visually represented, and is sitting, invisible somewhere, with nothing selected(returning null). EDIT: If you can visually confirm that the new node that you added is there, then it's definitely A rather than B (assuming one of the two is correct). Were the new tree invisible, you wouldn't see the new node added to the new tree(unless you added it to the old tree, and then created a new one with the same root)

I'm not sure which of these is more correct, maybe neither represents what's actually going on, but when I update my tree by using model = (DefaultTreeModel) tree.getModel(); model.insertNodeInto(newNode, (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(), 0); model = (DefaultTreeModel) tree.getModel(); model.insertNodeInto(newNode, (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(), 0); WITHOUT assigning the tree variable to a new tree, it starts working as expected, and I'm sure that the same will happen for you.

只需repaint()revalidate() JTree

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM