展开折叠展开与JTree延迟加载有关的问题 [英] Expand Collapse Expand Issue with JTree Lazy loading
问题描述
我已经使用延迟加载实现了一棵树.一级节点是在创建树时创建的,而子级节点只有在用户扩展任何特定节点时才创建.
I have implemented a tree using Lazy Loading. The 1st level nodes are created at the time of tree creation, where as the child nodes are created only when a user expands any particular node.
数据来自数据库,我们向数据库发出查询,以便填充子节点.实现TreeExpansionListener并使用treeExpanded方法的重写实现.扩展时,我将删除所选节点的所有子节点,进行数据库查询,并将记录作为子节点添加到所选节点.在将任何节点添加到树之前,将虚拟子节点添加到该节点.使用DefaultMutableTreeNode.
The data is coming from DB, and we fire a query to the database so as to populate the child nodes. Implemented TreeExpansionListener and using overridden implementation of treeExpanded method. On expansion, I remove all child nodes for the selected node, make a DB query and add the records as child to the selected node. Before adding any node to a tree, a dummy child is added to the node. Working with DefaultMutableTreeNode.
到目前为止,一切都很好,符合预期.
So far so good, it was working fine per expectation.
问题1-就像您一样,它是每个扩展的数据库调用,因此,如果某个节点折叠并再次扩展,我将进行一次DB跳闸并再次进行处理...这个想法是不重新加载节点如果已经扩展...
Problem 1 - As you, its a DB call per expansion, so if a node is collapsed and again expanded I will be doing a DB trip and processing again an again... The idea is to not to load the nodes fresh if already expanded...
问题2-如果必须强制刷新,即重新加载树并保持扩展状态.现在处于工作状态...如何解决上述问题1?
Problem 2 - If I had to do a force refresh i.e. re load the tree and keep expansion state. This is in working state now... How can I achieve the same along with fix to Problem 1 above ?
对此表示感谢.
推荐答案
如MadProgrammer所述,这是一个小型演示示例,显示了JTree在树在节点上扩展时动态加载数据的过程(并附带一个不错的加载栏作为奖励) ):
As explained by MadProgrammer, here is a small demo example showing a JTree loading dynamically data as the tree expands on nodes (and with a nice loading bar as a bonus):
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<MyTreeNode> 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<List<MyTreeNode>, Void> worker = new SwingWorker<List<MyTreeNode>, Void>() {
@Override
protected List<MyTreeNode> doInBackground() throws Exception {
// Here access database if needed
setProgress(0);
List<MyTreeNode> children = new ArrayList<TestJTree.MyTreeNode>();
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();
}
});
}
}
这篇关于展开折叠展开与JTree延迟加载有关的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!