約 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;
}
};
すべてのアクションを展開するのにかかる時間は 25 秒から 5 秒に短縮されました。現在もパフォーマンスの改善に取り組んでいます。
私は解決策を試しました、あなたも使用します。
私の意見の後、そこに提示されたコードは最適ではありません:-最も深い非リーフノードに対してのみ呼び出すのではなく、すべてのノードに対して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 つの子のすべての子孫を調べる) のいずれかの表示戦略を考える必要があると思います。100,000 は画面に表示するにはノードが多すぎるため、パンとズームについて考える必要があります。必要な子孫のサブセットを選択できるフィルターを考える必要があります。
1 つの戦略は、最上位の子を表示し、マウスが子に入ったときにそのすべての子孫を表示し、離れるときにそれらを折りたたむことです。このようにして、関心のある現在のサブツリーを表示するツリーをナビゲートできます。
ええ、UI 要素を再考してください。JTree は、100,000 個のノードを表示するために探しているものではありません。テーブルが表示され、アイテムをクリックしてテーブル要素にドリルダウンできるものを使用します。次に、ユーザーが階層を上に移動できるように、パンくずリストのような履歴を作成します。
JTree を使用することに固執している場合は、再描画する方法を引き継ぐ方法がありますが、それが展開の問題に役立つかどうかはわかりません。