展开折叠使用JTree延迟加载展开问题

我使用Lazy Loading实现了一棵树。 第一级节点是在树创建时创建的,其中仅当用户扩展任何特定节点时才创建子节点。

数据来自数据库,我们向数据库发出查询以填充子节点。 实现TreeExpansionListener并使用重写的treeExpanded方法实现。 在扩展时,我删除所选节点的所有子节点,进行数据库查询并将记录作为子节点添加到所选节点。 在将任何节点添加到树之前,会将虚拟子节点添加到节点。 使用DefaultMutableTreeNode。

到目前为止一切顺利,它按预期工作正常。

问题1 – 正如你所说,它是每次扩展的数据库调用,所以如果一个节点被折叠并再次展开,我将进行数据库跳转并再次处理…我的想法是如果已经扩展,则不加载节点…

问题2 – 如果我必须进行强制刷新,即重新加载树并保持扩展状态。 现在处于工作状态……如何解决上述问题1?

感谢任何帮助。

正如MadProgrammer所解释的,这是一个小的演示示例,显示了当树在节点上展开时(以及一个不错的加载条作为奖励),动态数据加载的JTree:

import java.awt.BorderLayout; import java.awt.Dimension; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.Transient; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeWillExpandListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.ExpandVetoException; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreePath; public class TestJTree { public static class MyTreeNode extends DefaultMutableTreeNode { private boolean loaded = false; private int depth; private final int index; public MyTreeNode(int index, int depth) { this.index = index; this.depth = depth; add(new DefaultMutableTreeNode("Loading...", false)); setAllowsChildren(true); setUserObject("Child " + index + " at level " + depth); } private void setChildren(List children) { removeAllChildren(); setAllowsChildren(children.size() > 0); for (MutableTreeNode node : children) { add(node); } loaded = true; } @Override public boolean isLeaf() { return false; } public void loadChildren(final DefaultTreeModel model, final PropertyChangeListener progressListener) { if (loaded) { return; } SwingWorker, Void> worker = new SwingWorker, Void>() { @Override protected List doInBackground() throws Exception { // Here access database if needed setProgress(0); List children = new ArrayList(); if (depth < 5) { for (int i = 0; i < 5; i++) { // Simulate DB access time Thread.sleep(300); children.add(new MyTreeNode(i + 1, depth + 1)); setProgress((i + 1) * 20); } } else { Thread.sleep(1000); } setProgress(0); return children; } @Override protected void done() { try { setChildren(get()); model.nodeStructureChanged(MyTreeNode.this); } catch (Exception e) { e.printStackTrace(); // Notify user of error. } super.done(); } }; if (progressListener != null) { worker.getPropertyChangeSupport().addPropertyChangeListener("progress", progressListener); } worker.execute(); } } protected void initUI() { JFrame frame = new JFrame(TestJTree.class.getSimpleName()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); MyTreeNode root = new MyTreeNode(1, 0); final DefaultTreeModel model = new DefaultTreeModel(root); final JProgressBar bar = new JProgressBar(); final PropertyChangeListener progressListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { bar.setValue((Integer) evt.getNewValue()); } }; JTree tree = new JTree() { @Override @Transient public Dimension getPreferredSize() { Dimension preferredSize = super.getPreferredSize(); preferredSize.width = Math.max(400, preferredSize.width); preferredSize.height = Math.max(400, preferredSize.height); return preferredSize; } }; tree.setShowsRootHandles(true); tree.addTreeWillExpandListener(new TreeWillExpandListener() { @Override public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { TreePath path = event.getPath(); if (path.getLastPathComponent() instanceof MyTreeNode) { MyTreeNode node = (MyTreeNode) path.getLastPathComponent(); node.loadChildren(model, progressListener); } } @Override public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { } }); tree.setModel(model); root.loadChildren(model, progressListener); frame.add(new JScrollPane(tree)); frame.add(bar, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); } public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new TestJTree().initUI(); } }); } } 

一个节点填充后,简单不要重新填充它。 在treeExpanded ,只需检查父节点是否有子节点,如果有的话,不要重新加载任何东西。

您需要提供刷新父节点的function。 我通常使用JPopupMenu来做这件事。