- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在处理树状态(扩展/选定节点)保存并制作了一个可以保存和恢复节点状态的实用程序类。它工作正常。
但 JTree 本身仍然存在一个问题 - 当用户使用某些 JTree 实例(展开/折叠节点)时,可能会出现某些节点(隐藏在另一个折叠节点下)展开的情况。没什么特别的 - 这很好。
JTree 在一个单独的 expandedState
哈希表中保存有关展开/折叠节点的记录,使用节点路径作为键,使用 boolean 值作为展开状态值。因此,当折叠父节点下的展开节点变得可见时,它仍会展开,因为在 expandedState
哈希表中有一条记录,其值为 true
。
屏幕截图说明的情况...
1、展开root,展开root下的一些节点(“glassfish4”文件夹):
2. 崩根:
3.再次展开root,我们仍然看到子节点(“glassfish4”文件夹)展开了:
想象一下我在屏幕截图#2 时刻保存了树状态,当根折叠时 - 问题是如果我想恢复所有树节点状态(即使是隐藏的)我无法展开另一个折叠下的节点节点,因为这将强制所有父节点展开。此外,我无法访问 expandedState
Hashtable 以直接在其中更改扩展状态,因为它在 JTree 中被声明为私有(private),并且没有好的方法来访问它。所以我无法完全重现初始树状态。
所以我能做的是:
也许我还漏掉了什么?
所以基本上问题是:
有没有其他方法可以在不导致父节点展开的情况下展开子节点?
您可以在下面找到我用来保存/恢复树状态的几个类。
只需调用 TreeUtils.getTreeState(tree)
来检索 JTree 状态,调用 TreeUtils.setTreeState(tree,treeState)
来恢复 JTree 状态。请注意,树必须使用 UniqueNode,否则这些方法将抛出 ClassCastException - 如果您有自己的节点扩展 DefaultMutableTreeNode,您可以简单地将 DefaultMutableTreeNode 替换为 UniqueNode。
UniqueNode.java - 具有自己唯一 ID 的简单节点
public class UniqueNode extends DefaultMutableTreeNode implements Serializable
{
/**
* Prefix for node ID.
*/
private static final String ID_PREFIX = "UN";
/**
* Unique node ID.
*/
protected String id;
/**
* Costructs a simple node.
*/
public UniqueNode ()
{
super ();
setId ();
}
/**
* Costructs a node with a specified user object.
*
* @param userObject custom user object
*/
public UniqueNode ( Object userObject )
{
super ( userObject );
setId ();
}
/**
* Returns node ID and creates it if it doesn't exist.
*
* @return node ID
*/
public String getId ()
{
if ( id == null )
{
setId ();
}
return id;
}
/**
* Changes node ID.
*
* @param id new node ID
*/
public void setId ( String id )
{
this.id = id;
}
/**
* Changes node ID to new random ID.
*/
private void setId ()
{
this.id = TextUtils.generateId ( ID_PREFIX );
}
/**
* {@inheritDoc}
*/
public UniqueNode getParent ()
{
return ( UniqueNode ) super.getParent ();
}
/**
* Returns TreePath for this node.
*
* @return TreePath for this node
*/
public TreePath getTreePath ()
{
return new TreePath ( getPath () );
}
}
TreeUtils.java - 将 TreeState 从 JTree 保存/加载到 JTree 的实用程序类
public class TreeUtils
{
/**
* Returns tree expansion and selection states.
* Tree nodes must be instances of UniqueNode class.
*
* @param tree tree to process
* @return tree expansion and selection states
*/
public static TreeState getTreeState ( JTree tree )
{
return getTreeState ( tree, true );
}
/**
* Returns tree expansion and selection states.
* Tree nodes must be instances of UniqueNode class.
*
* @param tree tree to process
* @param saveSelection whether to save selection states or not
* @return tree expansion and selection states
*/
public static TreeState getTreeState ( JTree tree, boolean saveSelection )
{
TreeState treeState = new TreeState ();
List<UniqueNode> elements = new ArrayList<UniqueNode> ();
elements.add ( ( UniqueNode ) tree.getModel ().getRoot () );
while ( elements.size () > 0 )
{
UniqueNode element = elements.get ( 0 );
TreePath path = new TreePath ( element.getPath () );
treeState.addState ( element.getId (), tree.isExpanded ( path ), saveSelection && tree.isPathSelected ( path ) );
for ( int i = 0; i < element.getChildCount (); i++ )
{
elements.add ( ( UniqueNode ) element.getChildAt ( i ) );
}
elements.remove ( element );
}
return treeState;
}
/**
* Restores tree expansion and selection states.
* Tree nodes must be instances of UniqueNode class.
*
* @param tree tree to process
* @param treeState tree expansion and selection states
*/
public static void setTreeState ( JTree tree, TreeState treeState )
{
setTreeState ( tree, treeState, true );
}
/**
* Restores tree expansion and selection states.
* Tree nodes must be instances of UniqueNode class.
*
* @param tree tree to process
* @param treeState tree expansion and selection states
* @param restoreSelection whether to restore selection states or not
*/
public static void setTreeState ( JTree tree, TreeState treeState, boolean restoreSelection )
{
if ( treeState == null )
{
return;
}
tree.clearSelection ();
List<UniqueNode> elements = new ArrayList<UniqueNode> ();
elements.add ( ( UniqueNode ) tree.getModel ().getRoot () );
while ( elements.size () > 0 )
{
UniqueNode element = elements.get ( 0 );
TreePath path = new TreePath ( element.getPath () );
// Restoring expansion states
if ( treeState.isExpanded ( element.getId () ) )
{
tree.expandPath ( path );
// We are going futher only into expanded nodes, otherwise this will expand even collapsed ones
for ( int i = 0; i < element.getChildCount (); i++ )
{
elements.add ( ( UniqueNode ) tree.getModel ().getChild ( element, i ) );
}
}
else
{
tree.collapsePath ( path );
}
// Restoring selection states
if ( restoreSelection )
{
if ( treeState.isSelected ( element.getId () ) )
{
tree.addSelectionPath ( path );
}
else
{
tree.removeSelectionPath ( path );
}
}
elements.remove ( element );
}
}
}
TreeState.java - 保存节点状态的 map 容器类
public class TreeState implements Serializable
{
/**
* Tree node states.
*/
protected Map<String, NodeState> states = new LinkedHashMap<String, NodeState> ();
/**
* Constructs new object instance with empty states.
*/
public TreeState ()
{
super ();
}
/**
* Constructs new object instance with specified states.
*
* @param states node states
*/
public TreeState ( Map<String, NodeState> states )
{
super ();
if ( states != null )
{
setStates ( states );
}
}
/**
* Returns all node states.
*
* @return all node states
*/
public Map<String, NodeState> getStates ()
{
return states;
}
/**
* Sets all node states.
*
* @param states all node states
*/
public void setStates ( Map<String, NodeState> states )
{
this.states = states;
}
/**
* Adds node state.
*
* @param nodeId node ID
* @param expanded expansion state
* @param selected selection state
*/
public void addState ( String nodeId, boolean expanded, boolean selected )
{
states.put ( nodeId, new NodeState ( expanded, selected ) );
}
/**
* Returns whether node with the specified ID is expanded or not.
*
* @param nodeId node ID
* @return true if node with the specified ID is expanded, false otherwise
*/
public boolean isExpanded ( String nodeId )
{
final NodeState state = states.get ( nodeId );
return state != null && state.isExpanded ();
}
/**
* Returns whether node with the specified ID is selected or not.
*
* @param nodeId node ID
* @return true if node with the specified ID is expanded, false otherwise
*/
public boolean isSelected ( String nodeId )
{
final NodeState state = states.get ( nodeId );
return state != null && state.isSelected ();
}
}
NodeState.java - 单节点展开/选择状态
public class NodeState implements Serializable
{
/**
* Whether node is expanded or not.
*/
protected boolean expanded;
/**
* Whether node is selected or not.
*/
protected boolean selected;
/**
* Constructs empty node state.
*/
public NodeState ()
{
super ();
this.expanded = false;
this.selected = false;
}
/**
* Constructs node state with the specified expansion and selection states.
*
* @param expanded expansion state
* @param selected selection state
*/
public NodeState ( boolean expanded, boolean selected )
{
super ();
this.expanded = expanded;
this.selected = selected;
}
/**
* Returns whether node is expanded or not.
*
* @return true if node is expanded, false otherwise
*/
public boolean isExpanded ()
{
return expanded;
}
/**
* Sets whether node is expanded or not.
*
* @param expanded whether node is expanded or not
*/
public void setExpanded ( boolean expanded )
{
this.expanded = expanded;
}
/**
* Returns whether node is selected or not.
*
* @return true if node is selected, false otherwise
*/
public boolean isSelected ()
{
return selected;
}
/**
* Sets whether node is selected or not.
*
* @param selected whether node is selected or not
*/
public void setSelected ( boolean selected )
{
this.selected = selected;
}
}
顺便说一句,setTreeState
方法避免了此时在折叠节点下恢复展开状态:
// Restoring expansion states
if ( treeState.isExpanded ( element.getId () ) )
{
tree.expandPath ( path );
// We are going futher only into expanded nodes, otherwise this will expand even collapsed ones
for ( int i = 0; i < element.getChildCount (); i++ )
{
elements.add ( ( UniqueNode ) tree.getModel ().getChild ( element, i ) );
}
}
else
{
tree.collapsePath ( path );
}
收集子节点的方法仅在父节点展开时调用。因此,折叠节点下的所有子节点都将被忽略。如果您更改该行为,您将看到我在此问题开头描述的问题 - 父节点将得到扩展。
最佳答案
为什么不通过执行与描述相同的操作来恢复状态,首先将子节点设置为展开,然后根据需要将其父节点设置为折叠?
与您当前代码的唯一区别是使用两次迭代而不是一次迭代。首先在需要的地方迭代和展开,然后在需要的地方迭代和折叠。
由于重绘逻辑,树应该只绘制一次。
关于java - 恢复展开/折叠的树节点状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18250615/
关于 B 树与 B+ 树,网上有一个比较经典的问题:为什么 MongoDb 使用 B 树,而 MySQL 索引使用 B+ 树? 但实际上 MongoDb 真的用的是 B 树吗?
如何将 R* Tree 实现为持久(基于磁盘)树?保存 R* 树索引或保存叶值的文件的体系结构是什么? 注意:此外,如何在这种持久性 R* 树中执行插入、更新和删除操作? 注意事项二:我已经实现了一个
目前,我正在努力用 Java 表示我用 SML 编写的 AST 树,这样我就可以随时用 Java 遍历它。 我想知道是否应该在 Java 中创建一个 Node 类,其中包含我想要表示的数据,以及一个数
我之前用过这个库http://www.cs.umd.edu/~mount/ANN/ .但是,它们不提供范围查询实现。我猜是否有一个 C++ 范围查询实现(圆形或矩形),用于查询二维数据。 谢谢。 最佳
在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择
书接上回,今天和大家一起动手来自己实现树。 相信通过前面的章节学习,大家已经明白树是什么了,今天我们主要针对二叉树,分别使用顺序存储和链式存储来实现树。 01、数组实现 我们在上一节中说过,
书节上回,我们接着聊二叉树,N叉树,以及树的存储。 01、满二叉树 如果一个二叉树,除最后一层节点外,每一层的节点数都达到最大值,即每个节点都有两个子节点,同时所有叶子节点都在最后一层,则这个
树是一种非线性数据结构,是以分支关系定义的层次结构,因此形态上和自然界中的倒挂的树很像,而数据结构中树根向上树叶向下。 什么是树? 01、定义 树是由n(n>=0)个元素节点组成的
操作系统的那棵“树” 今天从一颗 开始,我们看看如何从小树苗长成一颗苍天大树。 运转CPU CPU运转起来很简单,就是不断的从内存取值执行。 CPU没有好好运转 IO是个耗费时间的活,如果CPU在取值
我想为海洋生物学类(class)制作一个简单的系统发育树作为教育示例。我有一个具有分类等级的物种列表: Group <- c("Benthos","Benthos","Benthos","Be
我从这段代码中删除节点时遇到问题,如果我插入数字 12 并尝试删除它,它不会删除它,我尝试调试,似乎当它尝试删除时,它出错了树的。但是,如果我尝试删除它已经插入主节点的节点,它将删除它,或者我插入数字
B+ 树的叶节点链接在一起。将 B+ 树的指针结构视为有向图,它不是循环的。但是忽略指针的方向并将其视为链接在一起的无向叶节点会在图中创建循环。 在 Haskell 中,如何将叶子构造为父内部节点的子
我在 GWT 中使用树控件。我有一个自定义小部件,我将其添加为 TreeItem: Tree testTree = new Tree(); testTree.addItem(myWidget); 我想
它有点像混合树/链表结构。这是我定义结构的方式 struct node { nodeP sibling; nodeP child; nodeP parent; char
我编写了使用队列遍历树的代码,但是下面的出队函数生成错误,head = p->next 是否有问题?我不明白为什么这部分是错误的。 void Levelorder(void) { node *tmp,
例如,我想解析以下数组: var array1 = ["a.b.c.d", "a.e.f.g", "a.h", "a.i.j", "a.b.k"] 进入: var json1 = { "nod
问题 -> 给定一棵二叉树和一个和,确定该树是否具有从根到叶的路径,使得沿路径的所有值相加等于给定的和。 我的解决方案 -> public class Solution { public bo
我有一个创建 java 树的任务,它包含三列:运动名称、运动类别中的运动计数和上次更新。类似的东西显示在下面的图像上: 如您所见,有 4 种运动:水上运动、球类运动、跳伞运动和舞蹈运动。当我展开 sk
我想在 H2 数据库中实现 B+ Tree,但我想知道,B+ Tree 功能在 H2 数据库中可用吗? 最佳答案 H2 已经使用了 B+ 树(PageBtree 类)。 关于mysql - H2数据库
假设我们有 5 个字符串数组: String[] array1 = {"hello", "i", "cat"}; String[] array2 = {"hello", "i", "am"}; Str
我是一名优秀的程序员,十分优秀!