JTree setSelectionPaths需要很长时间才能扩展

时间:2012-10-11 05:34:05

标签: java swing jtree

我正在使用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分钟。有没有办法优化它?

2 个答案:

答案 0 :(得分:-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上)。当然,你必须非常小心,没有任何东西试图与树进行交互 - 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);
    }

}

答案 1 :(得分:-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);
    }

}