gpt4 book ai didi

java - 使用延迟加载恢复 JTree 中的扩展/选择状态

转载 作者:搜寻专家 更新时间:2023-11-01 00:51:19 27 4
gpt4 key购买 nike

我有一个包含 JTree 的应用程序,该 JTree 由 DefaultTreeModel 支持,用于显示反射(reflect)我服务器上文件系统部分的文件层次结构(我将把它称为我的客户端应用程序 )。我还有一个服务器应用程序,它提供我的客户端应用程序需要显示的数据(我将其称为我的服务器应用程序)。我正在使用“延迟加载子项”方法,这样我只需要在用户对文件感兴趣时将文件加载到我的树中。延迟加载方法:

  1. 我覆盖 treeWillExpand(TreeExpansionEvent evt)
  2. 我将选择路径设置为展开节点的路径。
  3. 然后我向服务器发送一条消息,请求该节点的子节点。
  4. 当服务器响应时,我得到最后选择的路径组件。
  5. 然后我使用 DefaultTreeModel.insertNodeInto()对于每个返回的数据文件。
  6. 最后我调用DefaultTreeModel.nodeStructureChanged() .

以上工作正常,我对延迟加载 child 没有任何问题。当新数据上传到服务器时,我的问题就来了,我想更新树,不仅要包含新数据,还要将扩展状态和选定节点设置为更新树之前的状态(以便用户不会因为有新数据要查看而在树上猛拉)。流程如下:

  1. 新数据上传到服务器
  2. 服务器应用程序存档此数据并使用有关上传文件的信息填充数据库。
  3. 服务器应用通知客户端应用新数据已上传。
  4. 客户端应用使用 JTree.getExpandedDescendants() 保存树的展开状态
  5. 客户端应用使用 JTree.getSelectionPath() 保存树的选择路径
  6. 客户端应用程序从 DefaultTreeModel 中删除所有节点。
  7. 客户端应用从根节点开始从服务器请求数据。
  8. 客户端应用程序遍历从 JTree.getExpandedDescendants() 返回的树路径枚举打电话JTree.expandPath()在枚举中的每个 TreePath 上。
  9. 客户端应用程序设置选定的树路径。

我的问题是无论我尝试什么,树的 GUI 都不会更新以反射(reflect)展开状态。我知道我对 expandPath 的调用是有效的,因为我可以看到从客户端发送的数据请求以及每次调用 expandPath 时服务器对数据的响应。我还在另一个窗口中显示有关当前选定节点的信息,它显示了正确选择的节点。但是,唉,令我失望的是,GUI 只显示根节点(已展开)及其子节点(未展开),而不是之前的展开状态。

所以我的问题是:如何恢复我的 JTree 的扩展状态,以便 GUI 在数据模型更新前后保持不变?

这些是我尝试过的一些事情:

  • 我找到了 a thread使用与我类似的设置,他的问题通过覆盖 equals() 解决了和 hashCode()但这对我不起作用。
  • 调用扩展的各种方法,例如:setExpandsSelectedPaths(true) , nodeStructureChanged() , JTree.invalidate()
  • 保存展开状态有许多不同的变体,但是,我不认为展开状态是不正确的,因为我可以看到在客户端应用程序和服务器应用程序之间来回传递的数据是正确的。

这是我的 SSCCE:

package tree.sscce;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.JButton;
import java.util.Enumeration;
import javax.swing.BoxLayout;
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;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JTextPane;

public class TreeSSCCE extends JFrame implements TreeWillExpandListener {

private static final long serialVersionUID = -1930472429779070045L;

public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TreeSSCCE inst = new TreeSSCCE();
inst.setLocationRelativeTo(null);
inst.setVisible(true);
inst.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
});
}

private DefaultMutableTreeNode rootNode;
private JTree tree;
private DefaultTreeModel treeModel;
private TreePath selectionPathPriorToNewData;
private Enumeration<TreePath> expandedPathsPriorToNewData;
private int treeSize = 5;

public TreeSSCCE() {

this.setBounds(0, 0, 500, 400);
JPanel mainPanel = new JPanel();
getContentPane().add(mainPanel, BorderLayout.CENTER);
mainPanel.setBounds(0, 0, 500, 400);
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));

JPanel descriptionPanel = new JPanel();
descriptionPanel.setBounds(0, 0, 500, 200);
mainPanel.add(descriptionPanel);

JTextPane textPane = new JTextPane();
String newLine = System.getProperty("line.separator");
descriptionPanel.setLayout(new BorderLayout(0, 0));
textPane.setText("Start by expanding some nodes then click 'Add New Data' and you will notice that the tree state is not retained.");
descriptionPanel.add(textPane);

// Initialize The Tree
tree = new JTree();
rootNode = new DefaultMutableTreeNode("Root");
treeModel = new DefaultTreeModel(rootNode);
tree.addTreeWillExpandListener(this);
tree.setModel(treeModel);
tree.setShowsRootHandles(true);
populateTree(false);

JScrollPane scrollPane = new JScrollPane(tree);
mainPanel.add(scrollPane);

JPanel buttonPanel = new JPanel();
mainPanel.add(buttonPanel);

JButton btnAddNewData = new JButton("Add New Data");
btnAddNewData.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
addNewDataToTree();
}
});
buttonPanel.add(btnAddNewData);


}

private void removeAllTreeNodes()
{

while(!treeModel.isLeaf(treeModel.getRoot()))
{
treeModel.removeNodeFromParent((MutableTreeNode)treeModel.getChild(treeModel.getRoot(),0));
}
treeModel = null;
treeModel = new DefaultTreeModel(rootNode);
tree.setModel(treeModel);
}

public void restoreExpansionState(Enumeration enumeration)
{
if (enumeration != null)
{
while (enumeration.hasMoreElements())
{
TreePath treePath = (TreePath) enumeration.nextElement();
tree.expandPath(treePath);
tree.setSelectionPath(treePath);
}
tree.setSelectionPath(selectionPathPriorToNewData);
}
}

protected void addNewDataToTree()
{
// save the tree state
selectionPathPriorToNewData = tree.getSelectionPath();
expandedPathsPriorToNewData = tree.getExpandedDescendants(new TreePath(tree.getModel().getRoot()));
removeAllTreeNodes();
populateTree(true);
restoreExpansionState(expandedPathsPriorToNewData);
}

private void populateTree(boolean newData)
{
if(newData)
treeSize++;
MyParentNode[] parents = new MyParentNode[treeSize];
for(int i = 0; i < treeSize; i++)
{
parents[i] = new MyParentNode("Parent [" + i + "]");
treeModel.insertNodeInto(parents[i], rootNode, i);
}
}

@Override
public void treeWillCollapse(TreeExpansionEvent evt) throws ExpandVetoException {
// Not used.
}

@Override
public void treeWillExpand(TreeExpansionEvent evt) throws ExpandVetoException
{
System.out.println("Tree expanding: " + evt.getPath());
tree.setExpandsSelectedPaths(true);
tree.setSelectionPath(evt.getPath());
// we have already loaded the top-level items below root when we
// connected so lets just return...
if(evt.getPath().getLastPathComponent().equals(treeModel.getRoot()))
return;

// if this is not root lets figure out what we need to do.
DefaultMutableTreeNode expandingNode = (DefaultMutableTreeNode) evt.getPath().getLastPathComponent();

// if this node already has children then we don't want to reload so lets return;
if(expandingNode.getChildCount() > 0)
return;
// if this node has no children then lets add some
MyParentNode mpn = new MyParentNode("Parent Under " + expandingNode.toString());
treeModel.insertNodeInto(mpn, expandingNode, expandingNode.getChildCount());
for(int i = 0; i < 3; i++)
{
treeModel.insertNodeInto(new DefaultMutableTreeNode("Node [" + i + "]"), mpn, i);
}
}

private class MyParentNode extends DefaultMutableTreeNode
{
private static final long serialVersionUID = 433317389888990065L;
private String name = "";

public MyParentNode(String _name)
{
super(_name);
name = _name;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyParentNode other = (MyParentNode) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}

@Override
public boolean isLeaf()
{
return false;
}

private TreeSSCCE getOuterType() {
return TreeSSCCE.this;
}
}

}

在此先感谢您提供的任何帮助。

附言这是我的第一个问题,所以请让我知道我的问题是否正确(请放轻松 ;))。

最佳答案

我正在使用自定义树模型(扩展 DefaultTreeModel)并在 DBTreeEvent.STRUCTURE_CHANGED 事件中使用react来处理这个问题。这就是我为保持旧状态所做的事情。不知道对你有没有帮助。。

//NOTE: node is the tree node that caused the tree event
TreePath nodesPath = new TreePath(node.getPath());
TreePath currentSel = myTree.getLeadSelectionPath();
List<TreePath> currOpen = getCurrExpandedPaths(nodesPath);
super.nodeStructureChanged(node);
reExpandPaths(currOpen);
myTree.setSelectionPath(currentSel);

private List<TreePath> getCurrExpandedPaths(TreePath currPath)
{
List<TreePath> paths = new ArrayList<TreePath>();
Enumeration<TreePath> expandEnum = myTree.getExpandedDescendants(currPath);
if (expandEnum == null)
return null;

while (expandEnum.hasMoreElements())
paths.add(expandEnum.nextElement());

return paths;
}

private void reExpandPaths(List<TreePath> expPaths)
{
if(expPaths == null)
return;
for(TreePath tp : expPaths)
myTree.expandPath(tp);
}

关于java - 使用延迟加载恢复 JTree 中的扩展/选择状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15016489/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com