我有一个具有大约 100000 个或更多节点的 JTree。现在我想扩展整棵树。为此,我使用我在这里找到的解决方案。
我的问题是扩展这么大的树需要 60 秒或更长时间,这不是很方便。有人对我如何加快扩展有任何建议吗?
我有一个具有大约 100000 个或更多节点的 JTree。现在我想扩展整棵树。为此,我使用我在这里找到的解决方案。
我的问题是扩展这么大的树需要 60 秒或更长时间,这不是很方便。有人对我如何加快扩展有任何建议吗?
对于包含 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 秒,我仍在努力提高性能。
快捷方式:
JTree jTree;
for (int i = 0; i < jTree.getRowCount(); i++) {
jTree.expandRow(i);
}
我尝试了解决方案,你也使用。
在我看来,那里提供的代码不是最优的: - 它为所有节点调用 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;
}
}
我认为您需要考虑一种显示策略,无论是广度优先(查看所有直系子代)还是深度优先(仅查看一个子代的所有后代)。100,000 个节点太多,无法在屏幕上查看,您需要考虑平移和缩放。您应该考虑可以选择所需后代子集的过滤器。
一种策略可能是显示最上面的孩子,当你的鼠标进入一个孩子时,显示它的所有后代,当你离开时折叠它们。通过这种方式,您可以浏览显示当前感兴趣的子树的树。
我在以下模式上取得了一些成功:
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 秒。
是的,重新考虑你的 UI 元素。JTree 不是您要显示的 100,000 个节点。使用可以看到表格的东西并单击项目以深入查看表格元素。然后有一个类似历史的面包屑,以便用户可以向上导航层次结构..
如果您坚持拥有一个 JTree,有一种方法可以接管它们重新绘制的方式,但我不知道这是否会帮助您解决扩展问题。