Ускорить развернуть / свернуть все узлы JTree - PullRequest
7 голосов
/ 15 декабря 2009

У меня есть JTree с 100000 узлами или более. Теперь я хочу расширить все дерево. Для этого я использую решение, которое я нашел здесь .

Моя проблема в том, что расширение такого большого дерева занимает около 60 секунд или более, что не очень удобно. У кого-нибудь есть предложения, как мне ускорить расширение?

Ответы [ 6 ]

3 голосов
/ 28 марта 2014

Быстрый способ:

JTree jTree;
for (int i = 0; i < jTree.getRowCount(); i++) {
         jTree.expandRow(i);
}
2 голосов
/ 25 октября 2013

У меня была такая же проблема с деревом, содержащим 150 000 узлов (с более чем 19 000 открываемых узлов). И я разделил на 5 продолжительность расширения, просто переопределив метод getExpandedDescendants:

JTree tree = new javax.swing.JTree()
{
    @Override
    public Enumeration<TreePath> getExpandedDescendants(TreePath parent)
    {
        if (!isExpanded(parent))
        {
            return null;
        }
        return java.util.Collections.enumeration(getOpenedChild(parent, new javolution.util.FastList<TreePath>()));
    }

    /**
     * Search oppened childs recursively
     */
    private List<TreePath> getOpenedChild(TreePath paramTreeNode, List<TreePath> list)
    {
        final Object parent = paramTreeNode.getLastPathComponent();
        final javax.swing.tree.TreeModel model = getModel();
        int nbChild = model.getChildCount(parent);
        for (int i = 0; i < nbChild; i++)
        {
            Object child = model.getChild(parent, i);
            final TreePath childPath = paramTreeNode.pathByAddingChild(child);
            if (!model.isLeaf(child) && isExpanded(childPath))
            {
                //Add child if oppened
                list.add(childPath);
                getOpenedChild(childPath, list);
            }
        }
        return list;
    }
};

Действие «развернуть все» теперь занимает 5 секунд вместо 25, и я все еще работаю над повышением производительности.

1 голос
/ 16 октября 2010

Я попробовал решение, вы тоже используете.

После моего мнения представленный код не является оптимальным: - он вызывает tree.expandPath для всех узлов, вместо того, чтобы вызывать его только для самых глубоких неконечных узлов (вызов метода expandPath для конечных узлов не имеет никакого эффекта, см. JDK)

Вот исправленная версия, которая должна быть быстрее:

// If expand is true, expands all nodes in the tree.
    // Otherwise, collapses all nodes in the tree.
    public void expandAll(JTree tree, boolean expand) {
        TreeNode root = (TreeNode)tree.getModel().getRoot();
        if (root!=null) {   
            // Traverse tree from root
            expandAll(tree, new TreePath(root), expand);
        }
    }

    /**
     * @return Whether an expandPath was called for the last node in the parent path
     */
    private boolean expandAll(JTree tree, TreePath parent, boolean expand) {
        // Traverse children
        TreeNode node = (TreeNode)parent.getLastPathComponent();
        if (node.getChildCount() > 0) {
            boolean childExpandCalled = false;
            for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode)e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                childExpandCalled = expandAll(tree, path, expand) || childExpandCalled; // the OR order is important here, don't let childExpand first. func calls will be optimized out !
            }

            if (!childExpandCalled) { // only if one of the children hasn't called already expand
                // Expansion or collapse must be done bottom-up, BUT only for non-leaf nodes
                if (expand) {
                    tree.expandPath(parent);
                } else {
                    tree.collapsePath(parent);
                }
            }
            return true;
        } else {
            return false;
        }
    }
1 голос
/ 15 декабря 2009

Я думаю, что вам нужно подумать о стратегии отображения, либо в ширину (посмотрите на всех прямых потомков), либо в глубину (посмотрите на всех потомков только одного потомка). 100 000 - это слишком много узлов для просмотра на экране, и вам нужно подумать о панорамировании и масштабировании. Вам следует подумать о фильтрах, которые могут выбирать нужные вам подмножества.

Одной из стратегий может быть отображение верхних дочерних элементов, а когда указатель мыши входит в дочерний элемент, отображать всех его потомков, а при выходе свернуть их. Таким образом, вы можете перемещаться по дереву, отображая текущее поддерево, представляющее интерес.

0 голосов
/ 10 сентября 2016

У меня был некоторый успех по следующей схеме:

tree = new JTree(...)
tree.setLargeModel(true);

Это уже привело к некоторым большим расширениям (150 000 узлов дерева) по сравнению с 12 с -> 3,5 с

Затем быстрее расширяться навалом:

TreeUI treeUI = tree.getUI();
tree.setUI(null);
try {
  // perform bulk expansion logic, like in other answers
} finally {
  tree.setUI(treeUI);
}

Это привело к снижению до 1,0 с.

0 голосов
/ 15 декабря 2009

Да, переосмыслите свой элемент интерфейса. JTree - это не то, что вы ищете, чтобы показать 100 000 узлов. Используйте что-нибудь, чтобы увидеть таблицу и щелкнуть элементы, чтобы перейти к элементу таблицы. Затем создайте историю, похожую на крошку, чтобы пользователь мог перемещаться вверх по иерархии.

Если вы настаиваете на том, чтобы у вас было JTree, есть способ переназначить его так, как оно перекрашивается, но я не знаю, поможет ли это вам с проблемой расширения.

...