Robin Robin -4 years ago 68
Java Question

Why does node selection not work properly after TreeModel reload?

I have a Swing application that uses a

. I want some of the nodes of the tree to be hidden, so I have implemented two
s, one with every node and a filtered one with only the ones that should be displayed. The latter is set as the actual model.

At some points I must change the filtered nodes, and when I do, the items in the tree update properly, but their behavior is wrong. Nodes do not get highlighted when they are selected (even though they are indeed selected) and the user can no longer double-click to expand a node, they must click the little '+' button.

Below is a generalization of my code, two methods from my custom class that extends

gets called when the filter needs to be updated.
recursively populates the root node of my filtered model. For simplicity,
is a class member variable (of type
) and is the root of the filtered model.
are of type

public void updateFilter() {
// Get current expansion state
ArrayList<Integer> expansionState = getExpansionState();

DefaultMutableTreeNode fullModelRoot = fullModel.getRoot();

// Remove existing nodes in the filtered model
while(filteredRoot.getChildCount() > 0) {

populateFilteredNode(fullModelRoot, filteredRoot);

// Repaint tree and restore expansion state

private void populateFilteredNode(DefaultMutableTreeNode fullNode, DefaultMutableTreeNode filteredNode) {

int index = 0;

for(int n = 0; n < fullNode.getChildCount(); n++) {
DefaultMutableTreeNode fullChildNode = fullNode.getChildAt(n);

// Show the item and its children if one of many cases is true
if(shouldShowItem(fullChildNode.getItem())) {
DefaultMutableTreeNode filteredChildNode = fullChildNode.clone();

filteredModel.insertNodeInto(filteredChildNode, filteredNode, index++);

populateFilteredNode(fullChildNode, filteredChildNode);

If anyone has a similar experience or knows why the selected node will not appear highlighted, please let me know. Or if there is a better way to accomplish filtering. Or if more code would help provide an answer.

Answer Source

I found something that works for my case, although it's quick and dirty and I don't necessarily understand why it works. This 12-year-old post on Code Ranch somehow got me headed in the right direction. I'm just posting it here in case anyone has a similar problem and it might be of help.

I save the selection path before making any changes to the table model, and then call this new function findNewSelectionPath after the changes were made. Below is a generalized version of the function (I use several custom classes so I did my best to make it look generically usable).

private TreePath findNewSelectionPath(TreePath oldSelectionPath) {
    TreePath newSelectionPath = null;

    if(oldSelectionPath != null) {
        Object[] oldPathComponents = oldSelectionPath.getPath();
        Object[] newPathComponents = new Object[oldPathComponents.length];

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) filteredModel.getRoot();

        // Set the root
        if(oldPathComponents[0].equals(node)) {
            newPathComponents[0] = node;

        // Set the rest of the path components
        for(int n = 1; n < oldPathComponents.length; n++) {
            for(int k = 0; k < node.getChildCount(); k++) {
                if(oldPathComponents[n].equals(node.getChildAt(k))) {
                    newPathComponents[n] = node.getChildAt(k);
                    node = node.getChildAt(k);

        // Make sure that the last path component exists
        if(newPathComponents[newPathComponents.length - 1] != null) {
            newSelectionPath = new TreePath(newPathComponents);
    return newSelectionPath;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download