4

私は使用してJTreeおり、ツリー内のすべてのノードを選択しています (Ctrl-A)。私のツリーには 14000 の親があり、各親には子があるため、合計でツリーには 28000 のノードが含まれています。以下はコード スニペットです。

@Override public final void setSelectionPaths(TreePath[] aPaths)
  {
    if (aPaths != null)
   {

   for (TreePath path : aPaths)
   {
       TreePath parentPath = path.getParentPath();
       if (parentPath != null)
        {
          expandPath(path.getParentPath());
        }
      }
    }
    super.setSelectionPaths(aPaths);
  }

ツリーを展開するのに 20 分かかります。それを最適化する方法はありますか?

4

2 に答える 2

-1

自分自身と@kleopatraを満足させるために、より良い実装を考え出しました(私のマシンでは、前の回答よりも最大8秒節約できます)。JTree基本的に、選択したパスを拡張するため の別のメソッドを追加します。

このメソッドは、選択したノードを拡張する際に不要なオーバーヘッドの一部を削減し、すべての内部状態が設定された後にUI更新を起動します。このメソッドは、のネイティブ実装に基づいていJTable.setExpandedStateます。また、マシンのパフォーマンスの違いを確認できるように、コードを残しました。

何よりも、EDTをいじることはもうありません(14kノードの場合は3.5秒であるため...なぜそうするのでしょうか)。

import java.awt.event.*;
import java.util.*;

import javax.swing.*;
import javax.swing.tree.*;

public class JTreeExpanding extends Box{

    public JTreeExpanding(){
        super(BoxLayout.Y_AXIS);

        //Populating a sample tree
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        for(int i = 0; i < 14000; i++){
            DefaultMutableTreeNode node = new DefaultMutableTreeNode("Root" + i);
            node.add(new DefaultMutableTreeNode("Child" + i));
            root.add(node);
        }   

        //Create a custom tree
        final CustomTree tree = new CustomTree(root);
        //final JTree tree = new JTree(root);
        tree.setRootVisible(false);
        final JScrollPane pane = new JScrollPane(tree);
        add(pane);

        //Create a button to expand the selected nodes
        JButton button = new JButton("Expand");
        button.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                long start = System.currentTimeMillis();
                //New way using Custom JTree
                tree.expandSelectedPaths();

                //Old way using classic JTree
                /*TreePath[] paths = tree.getSelectionPaths();
                tree.setSelectionPath(paths[0]);
                for(TreePath path : paths)
                    tree.expandPath(path);*/
                System.out.println(System.currentTimeMillis() - start);
            }});
        add(button);

    }

    public static class CustomTree extends JTree{

        HashMap<TreePath, Boolean> expandedState = new HashMap<TreePath, Boolean>();
        Stack<TreePath> customExpandedStack = new Stack<TreePath>();

        public CustomTree(DefaultMutableTreeNode root) {
            super(root);
        }

        public void expandSelectedPaths(){

            final TreePath[] paths = getSelectionPaths();
            setSelectionPath(paths[0]);

            for(TreePath path: paths){
                TreePath parentPath = path.getParentPath();

                while(parentPath != null) {
                    if(isExpanded(parentPath)) {
                        parentPath = null;
                    }
                    else {
                        customExpandedStack.push(parentPath);
                        parentPath = parentPath.getParentPath();
                    }
                }

                for(int counter = customExpandedStack.size() - 1; counter >= 0; counter--) {
                    parentPath = customExpandedStack.pop();
                    if(!isExpanded(parentPath)) {
                        expandedState.put(parentPath, Boolean.TRUE);
                    }
                }
            }

            if (accessibleContext != null) {
                ((AccessibleJTree)accessibleContext).
                fireVisibleDataPropertyChange();
            }

            for(TreePath path : paths){
                fireTreeExpanded(path);
                try {
                    fireTreeWillExpand(path);
                } catch (ExpandVetoException eve) {
                    // Expand vetoed!
                    return;
                }
            }
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new JTreeExpanding());
        frame.validate();
        frame.pack();
        frame.setVisible(true);
    }

}
于 2012-10-12T15:16:59.610 に答える
-1

選択したパスを記録した後、展開する前に選択をリセットすると、信じられないほど高速になることがわかりました。

final TreePath[] paths = tree.getSelectionPaths();
//Modifying the selection makes it run a whole lot faster
tree.setSelectionPath(paths[0]);
for(int i = 0; i < paths.length; i++){
    tree.expandPath(paths[i]);
}

これは、選択に関してそれほど多くの魔法を行う必要がなくなったためだと思います。

殴られて死んでしまうことへの恐怖から、私はこの提案をします. このプロセス中に GUI をロック解除したままにしたい場合は、それを (EDT ではなく) 新しいスレッドに投げることができます。もちろん、Tree とまったく対話しようとするものがないことに十分注意する必要があります。Swing はスレッドセーフではないため、Swing を見る以外のことをすると、あらゆる種類のファンキーな問題が発生します。

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.tree.*;

public class JTreeExpanding extends Box{

    //Just to make sure no user interactions happen during expansion
    JPanel glassPane = new JPanel(){
        public void paintComponent(Graphics g){
            g.setColor(new Color(0,0,0,80));
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(Color.white);
            g.setFont(g.getFont().deriveFont(18f).deriveFont(Font.BOLD));
            g.drawString("Processing...", getWidth()-100, getHeight()-10);
        }
    };

    public JTreeExpanding(){
        super(BoxLayout.Y_AXIS);

        glassPane.setOpaque(false);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        for(int i = 0; i < 14000; i++){
            DefaultMutableTreeNode node = new DefaultMutableTreeNode("Root" + i);
            node.add(new DefaultMutableTreeNode("Child" + i));
            root.add(node);
        }   

        final JTree tree = new JTree(root);
        tree.setRootVisible(false);
        final JScrollPane pane = new JScrollPane(tree);
        add(pane);

        JButton button = new JButton("Expand");
        button.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                //Taking the expand off the EDT frees up GUI 
                Thread t = new Thread(new Runnable(){
                    @Override
                    public void run() {
                        final TreePath[] paths = tree.getSelectionPaths();
                        //Modifying the selection makes it run a whole lot faster
                        tree.setSelectionPath(paths[0]);
                        for(int i = 0; i < paths.length; i++){
                            tree.expandPath(paths[i]);
                        }
                        glassPane.setVisible(false);
                    }});

                getRootPane().setGlassPane(glassPane);
                glassPane.setVisible(true);
                t.start();
            }});
        add(button);

        //Allow Scrolling in scroll pane while Tree is expanding
        glassPane.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                for(MouseWheelListener mwl : pane.getMouseWheelListeners()){
                    mwl.mouseWheelMoved(e);
                }
            }
        });

    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new JTreeExpanding());
        frame.validate();
        frame.pack();
        frame.setVisible(true);
    }

}
于 2012-10-11T22:40:19.853 に答える