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