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 不是线程安全的,因此除了查看它之外的任何其他操作都会导致各种时髦的问题。

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 回答