Java 高亮显示JTree节点在引擎盖下工作,但在视觉上不起作用
在我的应用程序中,我在左侧显示一个JTree,如果用户双击某个叶子,相应的数据将加载到右侧。加载此数据时,I(I)保存现有文档(此处不相关),(ii)更新树以说明可能发生的任何更改,(iii)确保更新后在树中选择正确的节点(即用户双击的节点)和(iv)加载所选节点应用程序逻辑工作正常,即加载了正确的文件,因此我们知道在树中选择了正确的节点,但在上述步骤之后,视觉上根本没有选择任何节点。 我知道,但问题似乎是树没有聚焦。我已经尝试了在那篇文章中建议的不同的补救方法,但是没有能够解决我的问题。(还有一个问题,尽管网站现在似乎已经关闭了。此外,表面上看起来类似,但问题源于OP构建专有渲染器。) 请看下面我的代码;我试着把它简化成一个SSCCE,但我还是被卡住了我目前的最佳猜测是,问题与这样一个事实有关:每次调用Java 高亮显示JTree节点在引擎盖下工作,但在视觉上不起作用,java,swing,jtree,Java,Swing,Jtree,在我的应用程序中,我在左侧显示一个JTree,如果用户双击某个叶子,相应的数据将加载到右侧。加载此数据时,I(I)保存现有文档(此处不相关),(ii)更新树以说明可能发生的任何更改,(iii)确保更新后在树中选择正确的节点(即用户双击的节点)和(iv)加载所选节点应用程序逻辑工作正常,即加载了正确的文件,因此我们知道在树中选择了正确的节点,但在上述步骤之后,视觉上根本没有选择任何节点。 我知道,但问题似乎是树没有聚焦。我已经尝试了在那篇文章中建议的不同的补救方法,但是没有能够解决我的问题。(还有
updateTree
时,都会创建一个全新的TreeModel并将其加载到树中,这使得无法直观地选择正确的节点。如果确实如此,然后一个可能的解决方案是改变TreeModel,而不是从头开始重新创建它,但是(i)这对我来说不太方便,(ii)我相信这本身就提出了一个有趣的问题
public class JTree_Problem_SSCCE
extends JFrame
{
private final JTree tree;
public JTree_Problem_SSCCE()
{
super("XYZ");
// Tree to select data
DefaultTreeModel treeModel = getTreeModel();
this.tree = new JTree(treeModel);
// I don't allow the user to select more than one node at a time but I can reproduce the problem with or without this
//TreeSelectionModel tsm = new DefaultTreeSelectionModel();
//tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
//tree.setSelectionModel(tsm);
tree.addMouseListener(new TreeMouseAdapter());
expandAllTreeNodes();
getContentPane().add(tree,BorderLayout.WEST);
setLocation(25,25);
setSize(1700,1000);
setVisible(true);
}
private DefaultTreeModel getTreeModel()
{
DefaultMutableTreeNode n1 = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode n2 = new DefaultMutableTreeNode("Child 1");
DefaultMutableTreeNode n3 = new DefaultMutableTreeNode("Child 2");
n1.add(n2);
n1.add(n3);
return new DefaultTreeModel(n1);
}
private void updateTree(DefaultMutableTreeNode treeNode)
{
DefaultTreeModel dtm = getTreeModel();
tree.setModel(dtm);
expandAllTreeNodes();
// No idea why the below doesn't work visually (the application logic works just fine but no tree node is actually selected)
System.err.println(tree.getExpandsSelectedPaths()); // always returns true (I've seen this to be the problem in other questions)
System.err.println(new TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode)));
if (treeNode != null)
{
tree.setSelectionPath(new TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode)));
}
// As recommended in the answers here (https://stackoverflow.com/q/8896678/8031521),
// I have tried the below but to no avail
// tree.requestFocus(); // I have also tried requestFocusInWindow
// SwingUtilities.invokeLater(new Runnable() {
// @Override
// public void run()
// {
// tree.setSelectionPath(new TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode)));
// }
// });
}
private void expandAllTreeNodes()
{
// Expand all the nodes in the tree
// See https://stackoverflow.com/a/15211697/8031521
for (int i = 0; i < tree.getRowCount(); i++)
{
tree.expandRow(i);
}
}
class TreeMouseAdapter
extends MouseAdapter
{
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 2 &&
((DefaultMutableTreeNode)tree.getLastSelectedPathComponent()).isLeaf())
{
// [Before opening the new file, save the old one]
// After saving the old file, make sure the tree is up to date
updateTree((DefaultMutableTreeNode)tree.getLastSelectedPathComponent());
// [Now we open the new file]
}
}
}
}
public class JTree\u Problem\u SSCCE
扩展JFrame
{
私有最终JTree树;
公共JTree_Problem_SSCCE()
{
超级(“XYZ”);
//选择数据的树
DefaultTreeModel treeModel=getTreeModel();
this.tree=newjtree(treeModel);
//我不允许用户一次选择多个节点,但我可以在有或无此选项的情况下重现问题
//TreeSelectionModel tsm=新的默认TreeSelectionModel();
//tsm.setSelectionMode(树选择模型。单树选择);
//树.集合选择模型(tsm);
addMouseListener(新的TreeMouseAdapter());
expandAllTreeNodes();
getContentPane().add(树,BorderLayout.WEST);
设置位置(25,25);
设置大小(17001000);
setVisible(真);
}
私有DefaultTreeModel getTreeModel()
{
DefaultMutableTreeNode n1=新的DefaultMutableTreeNode(“根”);
DefaultMutableTreeNode n2=新的DefaultMutableTreeNode(“子项1”);
DefaultMutableTreeNode n3=新的DefaultMutableTreeNode(“子项2”);
n1.添加(n2);
n1.添加(n3);
返回新的DefaultTreeModel(n1);
}
私有void updateTree(DefaultMutableTreeNode treeNode)
{
DefaultTreeModel dtm=getTreeModel();
树模型;
expandAllTreeNodes();
//不知道为什么下面的代码在视觉上不起作用(应用程序逻辑工作正常,但实际上没有选择树节点)
System.err.println(tree.getexpandsselectedpath());//始终返回true(我在其他问题中看到这是问题所在)
System.err.println(新的TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode));
if(treeNode!=null)
{
setSelectionPath(新树路径(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode));
}
//正如这里的答案所建议的那样(https://stackoverflow.com/q/8896678/8031521),
//我试过下面的方法,但没有用
//tree.requestFocus();//我也尝试过requestFocusInWindow
//SwingUtilities.invokeLater(新的Runnable(){
//@覆盖
//公开募捐
// {
//setSelectionPath(新树路径(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode));
// }
// });
}
私有void expandAllTreeNodes()
{
//展开树中的所有节点
//看https://stackoverflow.com/a/15211697/8031521
对于(int i=0;i
问题与在每次调用updateTree
时创建全新的TreeModel
有关。问题是treeNode
变量引用旧树中的节点。因此,从新树的根到旧树中的节点没有路径(即,从treeNode开始多次调用getParent()
将指向旧树的根,而不是新树的根)。我认为有两种可能的方法可以解决你的问题
选项1:搜索新的树节点
您可以编写一个类似下面的函数,从新根开始搜索树节点,路径为旧的treeNode
private static DefaultMutableTreeNode searchTree(DefaultMutableTreeNode root, Object[] path) {
if (!root.getUserObject().equals(path[0])) {
// completely different root
// potentially problematic
return null;
}
DefaultMutableTreeNode node = root;
for (int i = 1; i < path.length; ++i) {
Object searchItem = path[i];
Enumeration<TreeNode> children = node.children();
boolean found = false;
while (children.hasMoreElements()) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) children.nextElement();
if (searchItem.equals(child.getUserObject())) {
found = true;
node = child;
break;
}
}
if (!found) {
// path does not exist any more
// potentially problematic
return null;
}
}
return node;
}
选项2:修改现有树
而不是每次修改现有树模型时都创建新的树模型。对于每个目录,首先在目录中创建一组文件,并在树中为目录创建一组树节点。删除不在目录中的文件的所有树节点。然后,为目录中包含的所有文件创建节点
treeNode = searchTree((DefaultMutableTreeNode) tree.getModel().getRoot(), treeNode.getUserObjectPath());