当前位置: 首页 > 知识库问答 >
问题:

突出显示JTree节点可以在引擎盖下工作,但不能在视觉上

潘银龙
2023-03-14

在我的应用程序中,我在左侧显示一个JTree,如果用户双击一个叶子,相应的数据将加载到右侧。加载此数据时,I(I)保存现有文档(此处不相关),(ii)更新树以说明可能发生的任何更改,(iii)确保更新后在树中选择正确的节点(即用户双击的节点)和(iv)加载选定的节点。应用程序逻辑工作正常,即加载了正确的文件,因此我们知道树中选择了正确的节点,但在上述步骤之后,视觉上根本没有选择任何节点。

我知道这个问题,但问题似乎是树没有聚焦。我已经尝试过那篇帖子中建议的不同的补救方法,但都没能解决我的问题。(还有一个相关的论坛帖子,尽管网站现在似乎已经关闭了。此外,这个问题表面上似乎类似,但问题源于OP构建专有渲染器。)

请看下面我的代码;我试着把它简化成SSCCE,但我还是被卡住了。我目前的最佳猜测是,问题与这样一个事实有关:每次调用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]
            }
        }
    }

}

共有1个答案

百里光熙
2023-03-14

这个问题与每次调用updateTree时创建一个全新的TreeModel有关。问题是treeNode变量引用了旧树中的一个节点。因此,从新树的根到旧树中的节点没有路径(即,从treeNode开始多次调用getParent()将指向旧树的根,而不是新树的根)。我认为有两种可能的方法可以解决你的问题。

您可以编写一个类似下面的函数,从新根开始搜索树节点,路径为旧的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;
}

然后,在设置树选择路径之前,将以下内容添加到updateTree方法中。

treeNode = searchTree((DefaultMutableTreeNode) tree.getModel().getRoot(), treeNode.getUserObjectPath());

而不是每次都创建一个新的树模型来修改现有的树模型。对于每个目录,首先在目录中创建一组文件,并在树中为目录创建一组树节点。删除不在目录中的文件的所有树节点。然后,为目录中尚未在树中的所有文件创建节点。这个选项可能比选项1更复杂,但它不会在代码中产生重复树节点的潜在问题。

 类似资料:
  • 除了阅读github中的代码之外,是否有关于signalr.redis包如何工作的白皮书类型的文档?具体地说,我想知道它为Redis添加了哪些键、更新/删除策略等。当查看Redis内部时,我只看到以下调用中指定的一个键(即“signalr.Redis.sample”): 这把钥匙好像是Redis的柜台。我假设正在创建其他键并迅速删除,以方便连接到Redis的每个应用服务器之间的消息。

  • 我试图制作一个跨平台的JavaFX应用程序,它在Windows和OSX机器上工作得很好,但在Linux上不行。 jar是在Intellij思想中使用基本的JavaFX配置构建的。 有人帮忙吗?

  • @Component表示给定的类将是给定上下文中的单例,@aspect表示在运行时/编译期间,一个方面类的内容将以某种方式编织到目标类中--例如,这个目标类不是单例而是原型。我最后的结局是什么?

  • 正在更新属性文件:/home/mehmet/works/netbeansprojects/hsm_java/build/built-clean.属性删除目录/home/mehmet/works/netbeansprojects/hsm_java/build 清洁: 初始化: 已创建目录:/home///netbeansprojects/hsm_java/build/empty 已创建目录:/hom

  • 几天来,我一直在用头撞这个,完全被难倒了。下面是纲要: 我有一个Eclipse插件项目,使用Tycho通过Maven 3构建 在Maven中,我已经设置了maven-jarsigner-plugin来使用我的keystore对jars进行签名(有关keystore的详细信息,请参阅下文) 我的密钥库里有个Thawte签名的代码签名证书 我可以从目标/*中获取任何签名的jar文件,并在上面运行“ja

  • 点击图表上的某个条目,同时保持点击功能打开,是否可以隐藏/禁用突出显示?为了能够在图表上点击条目并显示自定义对话框,我必须设置: 这可以正常工作,但轻敲后,图表上会显示一个黄色突出显示(十字线)。我正在使用LineDataSet绘制图形,并尝试切换: 但这行不通。 我目前正在使用:v3.1.0