Почему выбор узла не работает должным образом после перезагрузки TreeModel?

У меня есть приложение Swing, которое использует JTree, Я хочу, чтобы некоторые узлы дерева были скрыты, поэтому я реализовал два DefaultTreeModels, один с каждым узлом и фильтрованный только с теми, которые должны отображаться. Последний устанавливается как актуальная модель.

В некоторых моментах я должен изменить отфильтрованные узлы, и когда я это сделаю, элементы в дереве обновляются должным образом, но их поведение является неправильным. Узлы не подсвечиваются, когда они выбраны (даже если они действительно выбраны), и пользователь больше не может дважды щелкнуть, чтобы развернуть узел, он должен нажать маленькую кнопку "+".

Ниже приведено обобщение моего кода, два метода из моего пользовательского класса, который расширяет JTree,

updateFilter вызывается, когда фильтр должен быть обновлен.populateFilteredNode рекурсивно заполняет корневой узел моей отфильтрованной модели. Для простоты, filteredRoot переменная члена класса (типа DefaultMutableTreeNode) и является корнем отфильтрованной модели. fullModel а также filteredModel имеют тип DefaultTreeModel

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) {
        filteredModel.removeNodeFromParent(filteredRoot.getFirstChild());
    }

    populateFilteredNode(fullModelRoot, filteredRoot);

    // Repaint tree and restore expansion state
    repaint();
    setExpansionState(expansionState);
}

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);
        }
    }
}

Если кто-то имеет подобный опыт или знает, почему выбранный узел не будет выделен, пожалуйста, дайте мне знать. Или, если есть лучший способ выполнить фильтрацию. Или, если больше кода поможет дать ответ.

1 ответ

Решение

Я нашел кое-что, что работает для моего случая, хотя это быстро и грязно, и я не обязательно понимаю, почему это работает. Этот 12-летний пост на "Ранчо кодов" каким-то образом направил меня в правильном направлении. Я просто выкладываю это здесь на тот случай, если у кого-то возникнут похожие проблемы, и это может помочь.

Я сохраняю путь выбора перед внесением каких-либо изменений в модель таблицы, а затем вызываю эту новую функцию findNewSelectionPath после внесения изменений. Ниже приведена обобщенная версия функции (я использую несколько пользовательских классов, поэтому я приложил все усилия, чтобы она выглядела как универсальная).

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);
                    break;
                }
            }
        }

        // Make sure that the last path component exists
        if(newPathComponents[newPathComponents.length - 1] != null) {
            newSelectionPath = new TreePath(newPathComponents);
        }
    }
    return newSelectionPath;
}
Другие вопросы по тегам