为什么重新加载 TreeModel 后节点选择无法正常工作?
Why does node selection not work properly after TreeModel reload?
我有一个使用 JTree
的 Swing 应用程序。我想隐藏树的一些节点,所以我实现了两个 DefaultTreeModel
s,一个包含每个节点,一个过滤后的节点只包含应该显示的节点。后者设置为实际模型
有时我必须更改过滤的节点,当我这样做时,树中的项目会正确更新,但它们的行为是错误的。 节点在被选中时不会高亮显示(即使它们确实被选中)并且用户不能再双击展开节点,他们必须点击小“+”按钮.
下面是我的代码的概括,我的自定义 class 中的两个方法扩展了 JTree
.
updateFilter
在过滤器需要更新时被调用。
populateFilteredNode
递归填充我过滤模型的根节点。为简单起见,filteredRoot
是一个 class 成员变量(DefaultMutableTreeNode
类型)并且是过滤模型的根。 fullModel
和 filteredModel
的类型是 DefaultTreeModel
public void updateFilter() {
// Get current expansion state
ArrayList<Integer> expansionState = getExpansionState();
DefaultMutableTreeNode fullModelRoot = fullModel.getRoot();
// Remove existing nodes in the filtered model
while(filteredRoot.getChildCount() > 0) {
filteredModel.removeNodeFromParent(filteredRoot.getFirstChild());
}
populateFilteredNode(fullModelRoot, filteredRoot);
// Repaint tree and restore expansion state
repaint();
setExpansionState(expansionState);
}
private void populateFilteredNode(DefaultMutableTreeNode fullNode, DefaultMutableTreeNode filteredNode) {
int index = 0;
for(int n = 0; n < fullNode.getChildCount(); n++) {
DefaultMutableTreeNode fullChildNode = fullNode.getChildAt(n);
// Show the item and its children if one of many cases is true
if(shouldShowItem(fullChildNode.getItem())) {
DefaultMutableTreeNode filteredChildNode = fullChildNode.clone();
filteredModel.insertNodeInto(filteredChildNode, filteredNode, index++);
populateFilteredNode(fullChildNode, filteredChildNode);
}
}
}
有没有人有类似的经历或者知道为什么选中的节点不会高亮显示,请告诉我。或者是否有更好的方法来完成过滤。或者,如果更多代码有助于提供答案。
我找到了适合我的情况的东西,尽管它又快又脏,而且我不一定理解它为什么有效。 This 12-year-old post 在 Code Ranch 上以某种方式让我朝着正确的方向前进。我只是把它贴在这里,以防有人遇到类似的问题,它可能会有所帮助。
我在对 table 模型进行任何更改之前保存选择路径,然后在进行更改后调用此新函数 findNewSelectionPath
。下面是该函数的通用版本(我使用了几个自定义 类 所以我尽力让它看起来一般可用)。
private TreePath findNewSelectionPath(TreePath oldSelectionPath) {
TreePath newSelectionPath = null;
if(oldSelectionPath != null) {
Object[] oldPathComponents = oldSelectionPath.getPath();
Object[] newPathComponents = new Object[oldPathComponents.length];
DefaultMutableTreeNode node = (DefaultMutableTreeNode) filteredModel.getRoot();
// Set the root
if(oldPathComponents[0].equals(node)) {
newPathComponents[0] = node;
}
// Set the rest of the path components
for(int n = 1; n < oldPathComponents.length; n++) {
for(int k = 0; k < node.getChildCount(); k++) {
if(oldPathComponents[n].equals(node.getChildAt(k))) {
newPathComponents[n] = node.getChildAt(k);
node = node.getChildAt(k);
break;
}
}
}
// Make sure that the last path component exists
if(newPathComponents[newPathComponents.length - 1] != null) {
newSelectionPath = new TreePath(newPathComponents);
}
}
return newSelectionPath;
}
我有一个使用 JTree
的 Swing 应用程序。我想隐藏树的一些节点,所以我实现了两个 DefaultTreeModel
s,一个包含每个节点,一个过滤后的节点只包含应该显示的节点。后者设置为实际模型
有时我必须更改过滤的节点,当我这样做时,树中的项目会正确更新,但它们的行为是错误的。 节点在被选中时不会高亮显示(即使它们确实被选中)并且用户不能再双击展开节点,他们必须点击小“+”按钮.
下面是我的代码的概括,我的自定义 class 中的两个方法扩展了 JTree
.
updateFilter
在过滤器需要更新时被调用。
populateFilteredNode
递归填充我过滤模型的根节点。为简单起见,filteredRoot
是一个 class 成员变量(DefaultMutableTreeNode
类型)并且是过滤模型的根。 fullModel
和 filteredModel
的类型是 DefaultTreeModel
public void updateFilter() {
// Get current expansion state
ArrayList<Integer> expansionState = getExpansionState();
DefaultMutableTreeNode fullModelRoot = fullModel.getRoot();
// Remove existing nodes in the filtered model
while(filteredRoot.getChildCount() > 0) {
filteredModel.removeNodeFromParent(filteredRoot.getFirstChild());
}
populateFilteredNode(fullModelRoot, filteredRoot);
// Repaint tree and restore expansion state
repaint();
setExpansionState(expansionState);
}
private void populateFilteredNode(DefaultMutableTreeNode fullNode, DefaultMutableTreeNode filteredNode) {
int index = 0;
for(int n = 0; n < fullNode.getChildCount(); n++) {
DefaultMutableTreeNode fullChildNode = fullNode.getChildAt(n);
// Show the item and its children if one of many cases is true
if(shouldShowItem(fullChildNode.getItem())) {
DefaultMutableTreeNode filteredChildNode = fullChildNode.clone();
filteredModel.insertNodeInto(filteredChildNode, filteredNode, index++);
populateFilteredNode(fullChildNode, filteredChildNode);
}
}
}
有没有人有类似的经历或者知道为什么选中的节点不会高亮显示,请告诉我。或者是否有更好的方法来完成过滤。或者,如果更多代码有助于提供答案。
我找到了适合我的情况的东西,尽管它又快又脏,而且我不一定理解它为什么有效。 This 12-year-old post 在 Code Ranch 上以某种方式让我朝着正确的方向前进。我只是把它贴在这里,以防有人遇到类似的问题,它可能会有所帮助。
我在对 table 模型进行任何更改之前保存选择路径,然后在进行更改后调用此新函数 findNewSelectionPath
。下面是该函数的通用版本(我使用了几个自定义 类 所以我尽力让它看起来一般可用)。
private TreePath findNewSelectionPath(TreePath oldSelectionPath) {
TreePath newSelectionPath = null;
if(oldSelectionPath != null) {
Object[] oldPathComponents = oldSelectionPath.getPath();
Object[] newPathComponents = new Object[oldPathComponents.length];
DefaultMutableTreeNode node = (DefaultMutableTreeNode) filteredModel.getRoot();
// Set the root
if(oldPathComponents[0].equals(node)) {
newPathComponents[0] = node;
}
// Set the rest of the path components
for(int n = 1; n < oldPathComponents.length; n++) {
for(int k = 0; k < node.getChildCount(); k++) {
if(oldPathComponents[n].equals(node.getChildAt(k))) {
newPathComponents[n] = node.getChildAt(k);
node = node.getChildAt(k);
break;
}
}
}
// Make sure that the last path component exists
if(newPathComponents[newPathComponents.length - 1] != null) {
newSelectionPath = new TreePath(newPathComponents);
}
}
return newSelectionPath;
}