要创建动态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();
}