我想知道如何实现这个功能:
我有一个可编辑的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;
}
未正确重新绘制标签的更新问题可能与以下事实有关:您在标识路径的数组中仅使用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显示一个树。我想选择树中可以使用的所有节点。这工作得很好。 但是,这将展开所有节点,并且拥有一个大树将把其余的内容一直往下推。 我想在检查所有节点后折叠树,但使用不起作用。 有人有办法解决吗?