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

如何在编辑节点后不在JTree中折叠节点

穆俊哲
2023-03-14

我想知道如何实现这个功能:

我有一个可编辑的JTree,可以编辑节点的名称。如果我有一个节点是分支节点(其中有一些叶节点),并且该分支节点在编辑时展开,编辑后,该节点将折叠。

编辑完成后,如果分支节点打开,我想让它保持打开状态,如果分支节点折叠,我想让它折叠。

我试图查看TreeWireExpandListener,但它似乎无法解决我的问题,因为在调用这些方法之前,我需要识别实际节点是否处于编辑模式。。。

怎么玩这个把戏?很明显这是必要的,但我根本找不到答案:/

好的,这就是代码,我会尽力解释。首先,我有一个实现TreeModel的ContactTreeModel类。构造函数只是从主应用程序框架中加载addressbook和group manager,我创建了新的根,并在第二种方法中从数据库中加载数据。

public ContactTreeModel() {
    addressBookManager = ContactManagerFrame.getAddressBookManager();
    groupManager = ContactManagerFrame.getGroupManager();
    root = new DefaultMutableTreeNode();
    processTreeHierarchy();
}

private void processTreeHierarchy() {
    DefaultMutableTreeNode group, contact;
    for (Group g : addressBookManager.getGroups()) {
        group = new DefaultMutableTreeNode(g);
        root.add(group);
        for (Contact c : addressBookManager.getContactsFromGroup(g)) {
            contact = new DefaultMutableTreeNode(c);
            group.add(contact);
        }
    }
}

我读到,如果

当用户将由路径标识的项的值更改为newValue时发出消息。如果newValue表示一个真正的新值,模型应该发布一个treeNodesChanged事件。

所以我写了这样的方法:

@Override
public void valueForPathChanged(TreePath path, Object newValue) {
    // backup of the original group
    Group oldGroup = (Group) path.getLastPathComponent();
    try {
        Group testGroup = (Group) path.getLastPathComponent();
        testGroup.setName((String) newValue);
        // validation of the group to be updated
        groupManager.validateGroup(testGroup, true);
        oldGroup.setName((String) newValue);
        // updating of the group in db
        groupManager.updateGroup(oldGroup);
    } catch (ServiceFailureException | ValidationException ex) {
        // if database error occured or validation exception is raised, 
        // update label in gui 
        ContactManagerFrame.getStatusPanelLabel().setText(ex.getMessage());
    } finally {
        fireTreeStructureChanged();
    }
}

注意最后一个块中的方法,该方法总是被激活。看起来像

protected void fireTreeStructureChanged() {
    Object[] o = {root};
    TreeModelEvent e = new TreeModelEvent(this, o);
    for (TreeModelListener l : treeModelListeners) {
        l.treeNodesChanged(e);
    }
}

这有点棘手,我想这就是它不起作用的原因。我只是遍历所有TreeModelListener,然后启动TreeNodeChanged方法。

我在ContactTreeModel和相关方法中将树模型侦听器的数组指定为私有属性:

private Vector<TreeModelListener> treeModelListeners = new Vector<>();

@Override
public void addTreeModelListener(TreeModelListener l) {
    treeModelListeners.addElement(l);
}

@Override
public void removeTreeModelListener(TreeModelListener l) {
    treeModelListeners.removeElement(l);
}

最后一件事,我添加到模型中的模型侦听器是什么样子的?来了:

public class ContactTreeModelListener implements TreeModelListener {
    @Override
    public void treeNodesChanged(TreeModelEvent e) {
        System.out.println("nodes changed");
    }

    @Override
        public void treeNodesInserted(TreeModelEvent e) {
        System.out.println("nodes inserted");
    }

    @Override
    public void treeNodesRemoved(TreeModelEvent e) {
        System.out.println("nodes removed");
    }

    @Override
    public void treeStructureChanged(TreeModelEvent e) {
        System.out.println("structure changed");
    }
}

所以它基本上什么都不做。我在另一个地方注册了听众,现在没关系。

因此,当我执行它时,在这种状态下,树不会崩溃,并且行为符合需要。但即使它真的重写了节点(标签)的名称,如果原始字符串约为5个字符,我将其更改为4个字符,则标签中只有4个字符,但第五个字符的空格也是空的。所以,在我完成编辑标签后,原始标签的大小没有改变。类似地,当我扩展组名时,例如我将其从4个字符重命名为5个字符,该节点的标签将包含点,表明整个文本太大,无法显示。真奇怪。。。如何制作该标签的udpdate?

最后一件事。。。因为我在JTree中有自定义图标,所以我在空组和非空组之间进行识别,每次我在树中执行一些操作时,我都需要检查实际的图标(我检查它是否执行,即使我只是打开和关闭节点)。这是非常低效的,所以我扩展了DefaultTreeCellRenderer,在这里我进行实际缓存:

@Override
public Component getTreeCellRendererComponent(
        JTree tree,
        Object value,
        boolean sel,
        boolean expanded,
        boolean leaf,
        int row,
        boolean hasFocus) {

    if (iconCache == null) {
        throw new NullPointerException("iconCache in " 
             + this.getClass().getName() + " is null");
    }

    super.getTreeCellRendererComponent(
            tree, value, sel,
            expanded, leaf, row,
            hasFocus);

    if (value instanceof Group) {
        Group g = (Group) value;
        Icon groupIcon = iconCache.get(g);
        if (groupIcon == null) {
            if (groupHasContacts(g)) {
                groupIcon = groupNonEmpty;
            } else {
                groupIcon = groupEmptyIcon;
            }
            iconCache.put(g, groupIcon);
        }
        JLabel result = (JLabel) super.getTreeCellRendererComponent(tree,
                g.getName(), sel, expanded, leaf, row, hasFocus);

        result.setIcon(groupIcon);
        return result;
    }
    else if (value instanceof Contact) {
        Contact c = (Contact) value;
        Icon icon = iconCache.get(c);
        if (icon == null) {
            icon = this.contactIcon;
            iconCache.put(c, icon);
        }
        JLabel result = (JLabel) super.getTreeCellRendererComponent(
                tree, c.getName() + c.getSurname(), 
                sel, expanded, leaf, row, hasFocus);
        result.setIcon(icon);
        return result;
    }

    JLabel defaultNode = (JLabel) super.getTreeCellRendererComponent(
            tree, "?", sel, expanded, leaf, row, hasFocus);

    defaultNode.setIcon(unknownNode);
    return defaultNode;
}

共有1个答案

柳志专
2023-03-14

未正确重新绘制标签的更新问题可能与以下事实有关:您在标识路径的数组中仅使用root触发treeNodesChanged事件。

尝试从valueForPathChanged调用以下内容:

public void fireTreeNodesChanged(TreePath path) {
    TreeModelEvent e = new TreeModelEvent(this, path.getPath());
    for (TreeModelListener l : treeModelListeners) {
        l.treeNodesChanged(e);
    }
}

顺便说一下,您为fire Tree结构更改命名,实际上会触发treeNodesChanged,这是非常误导人的。

 类似资料:
  • 问题内容: 我在创建JTree时遇到困难,该JTree允许通过将节点拖放到JTree中进行重组。看来应该比较简单。我在网上看过示例,但似乎无法在自己的代码中实现它。 例如,sun提供的这种功能允许在不同组件之间拖动到树中,但不能从树本身内部拖动。 而且我也发现了这一点,它允许您将文本拖到JTree中,但不能拖到树中。 任何参考或建议将是巨大的。谢谢 问题答案: 之前没有做过,但是谷歌快速搜索在这里

  • 在提交对话框的时,我添加的更新,以便查看添加的节点 问题是用户打开的所有展开节点都将崩溃 我发现这个问题避免了更新后p:treeTable的折叠,在他写的问题中解决了这个问题,但他的问题没有答案或解决方案

  • 折叠隐藏节点,可记录用户上次行为。 标题 内容 类型 通用 支持布局 responsive, fixed-height, fill, container, fixed 所需脚本 https://c.mipcdn.com/static/v2/mip-accordion/mip-accordion.js 使用说明 mip-accordion 是一个折叠隐藏节点的 MIP 组件,可以对满足特定结构的节点

  • 在bluemix中创建节点红色应用程序时,介绍页面会显示 我在bluemix UI或节点红色编辑器中看不到添加/编辑静态内容的任何地方。如何编辑node red应用程序的静态内容?

  • 我有一棵树,上面有一个JButton作为节点。 我希望能够在两组值之间切换按钮名称及其调用的方法。 我认为这将工作正常,如果树将刷新后,每次按钮点击。 这种方法似乎有效,但它会在刷新时将树折叠,我需要树保持打开状态。 我没有添加/删除节点,所以我在网上看到的许多其他方法都不适用。

  • 我正在使用jsTree显示一个树。我想选择树中可以使用的所有节点。这工作得很好。 但是,这将展开所有节点,并且拥有一个大树将把其余的内容一直往下推。 我想在检查所有节点后折叠树,但使用不起作用。 有人有办法解决吗?