要创建动态JTree,我正在阅读this website in chapter "4.2 OutlineNode.java"上有关动态JTree的教程。

现在,我已经实现了它,并且认识到在GUI线程中加载数据需要很长时间,而且也很丑陋。因此,我添加了一个线程来扩展子代,然后将TreeNode元素添加到树中。

private void getChildNodes() {
    areChildrenDefined = true;
    Thread t = new Thread(new Runnable()
    {
        @Override
        public void run() {
        System.out.println("Expand");
            final List<DECTTreeNode> listNodes = new ArrayList<DECTTreeNode>();
            if (castNode().canExpand())
            {
                for(DECTNode crt : castNode().getChildren())
                {
                    DECTTreeNode treeNode = new DECTTreeNode(crt);
                    listNodes.add(treeNode);
                }

                try {
                    SwingUtilities.invokeAndWait(new Runnable()
                    {
                        @Override
                        public void run() {
                            System.out.println(listNodes.size());
                            for (DECTTreeNode crt : listNodes)
                            {
                                add(crt); // <==== Adds the node to the JTree
                            }
                        }

                    });
                    //}).run();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }

    });
    t.start();
}


没有线程,它就可以正常工作。如果添加线程并将add-调用放入SwingUtilities.invokeAndWait(...),则子级似乎已扩展,但它们在树中不可见。

我已经在树上尝试过revalidate()repaint()-没有任何效果。

任何想法如何使这些元素可见?

先感谢您。

最佳答案

@Override
public void treeWillExpand(TreeExpansionEvent e) throws ExpandVetoException {
    CustomTreeNode t = (CustomTreeNode) e.getPath().getLastPathComponent();
    t.addChildLoadedListener(new ChildLoadedListener() {
        @Override
        public void childLoaded(TreeNode parent) {
            ((CustomTreeNode) parent).setExpanded(true);
            expandPath(new TreePath(((CustomTreeNode) parent).getPath()));
        }
    });
    if (!t.isExpanded()) {
        factory.loadChildren(t);
        throw new ExpandVetoException(null);
    }
}

public void treeWillCollapse(TreeExpansionEvent e) throws ExpandVetoException {
    CustomTreeNode t = (CustomTreeNode) e.getPath().getLastPathComponent();
    t.setExpanded(false);
}


不管我是不是。这对我有用。 CustomTreeNode是从defaultMutableTreeNode扩展而来的,并添加了一个自写的ChildLoadedListener,当工厂加载了子级时会调用它。 isExpanded布尔值是为了避免无限循环。
工厂将创建一个SwingWorker来加载并执行子代。之后,将调用ChilLoadedListener并再次扩展树。

希望这会帮助或至少帮助您考虑问题;-)

编辑:

@Override
public void loadChildren(CustomTreeNode tn) {
    ctn = tn;
    LoadChildrenWorker worker = new LoadChildrenWorker();
    worker.execute();
}


private class LoadChildrenWorker extends SwingWorker<String, Object> {

            @Override
    protected String doInBackground() throws Exception {
                    //load source here and return a string when finished.
                    //In my case its a string repesentation of a directory
    }

    @Override
    protected void done() {
            //with get(), you get the string from doBackground()
            for (String str : parseFromOutput(get())) {
                    if (str.endsWith("/")) {
                        ctn.add(new CustomTreeNode("Directory");
                    } else {
                        ctn.add(new CustomTreeNode("Leaf");
                    }
            }
            //call listeners
            ctn.fireChildrenLoaded();
    }

07-26 09:29