从CellEditorListener获取编辑的TreeNode

之前我问过如何在TreeNode被重命名的时候触发一个事件( 这里 )。 我的问题得到了回答,但我遇到了另一个问题。 我需要访问CellEditorListener的editingStopped事件中正在编辑的TreeNode。 这是我必须这样做的代码:

package com.gamecreator; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.tree.DefaultTreeCellEditor; public class CustomCellEditorListener implements CellEditorListener { public CustomCellEditorListener() { } public void editingCanceled(ChangeEvent e) { } public void editingStopped(ChangeEvent e) { DefaultTreeCellEditor editor = (DefaultTreeCellEditor) e.getSource(); //This gives me the error. CustomTreeNode node = //What do I put here???; node.getResource().setName((String) node.getUserObject()); //For debugging System.out.println(node.getResource().getName()); } } 

我得到这个错误:

线程“AWT-EventQueue-0”中的exceptionjava.lang.ClassCastException:javax.swing.tree.DefaultTreeCellEditor $ 1不能转换为javax.swing.tree.DefaultTreeCellEditor

编辑:在另一个尝试中,我在CustomCellEditorListener中使用此代码

 public void editingStopped(ChangeEvent e) { TreePath path = ((CustomTreeCellEditor) e.getSource()).getLastPath(); //This gives me the error. CustomTreeNode node = (CustomTreeNode) path.getLastPathComponent(); node.getResource().setName((String) node.getUserObject()); //For debugging System.out.println(node.getResource().getName()); } 

和这个代码在CustomTreeCellEditor中

 public TreePath getLastPath() { return lastPath; } 

我得到了同样的错误(我希望我会)。 我所拥有的应该是工作,所以唯一真正的问题就是“为什么我会得到这个错误,我该如何解决?”,但是如果有人有更好的方法来完成这个,我愿意倾听。

编辑2:我已经做了我想要完成的一个小例子,可以在这里find(这是一个Eclipse档案)。

看来你想编辑一个DefaultMutableTreeNode中的Resource的名字。 正如你所发现的那样, ChangeEvent的源头不是DefaultTreeCellEditor发送到editingStopped() ; 它是编辑(匿名)UI委托。

相反,在您的DefaultTreeCellEditor覆盖getCellEditorValue() ,如下所示。 DefaultTreeCellRenderer只是通过convertValueToText()调用toString() ,它访问DefaultMutableTreeNode的用户对象。

附录:请注意, isCellEditable()确保只能编辑叶节点。

正如@kleopatra在注释中指出的那样,之前的TreeCellEditor实现是无效的,因为它修改了正在编辑的节点。 下面的修订版本创build了一个具有更新名称的新节点; 在这种情况下复制构造函数将会很有用。 优点是userObject保持一个Resource 。 另请参阅此替代方法 。

图片

 /** * @see https://stackoverflow.com/a/12651990/230513 * @see https://stackoverflow.com/a/11639595/230513 * @see https://stackoverflow.com/a/11113648/230513 */ public class TreeEditDemo extends JPanel { private JTree tree; private DefaultMutableTreeNode root; private DefaultTreeCellEditor editor; private JLabel label = new JLabel(" ", JLabel.CENTER); public TreeEditDemo() { super(new BorderLayout()); root = new DefaultMutableTreeNode("Nodes"); root.add(new DefaultMutableTreeNode(new Resource("one"))); root.add(new DefaultMutableTreeNode(new Resource("two"))); root.add(new DefaultMutableTreeNode(new Resource("three"))); final DefaultTreeModel treeModel = new DefaultTreeModel(root); tree = new JTree(treeModel); tree.setEditable(true); editor = new MyTreeCellEditor(tree, (DefaultTreeCellRenderer) tree.getCellRenderer()); tree.setCellEditor(editor); tree.getInputMap().put( KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "startEditing"); this.add(new JScrollPane(tree)); this.add(label, BorderLayout.SOUTH); tree.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { TreePath path = e.getNewLeadSelectionPath(); if (path != null) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); if (node.isLeaf()) { Resource user = (Resource) node.getUserObject(); label.setText(user.toString()); } else { label.setText(" "); } } } }); editor.addCellEditorListener(new CellEditorListener() { @Override public void editingStopped(ChangeEvent e) { label.setText(editor.getCellEditorValue().toString()); } @Override public void editingCanceled(ChangeEvent e) { } }); } private static class MyTreeCellEditor extends DefaultTreeCellEditor { public MyTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) { super(tree, renderer); } @Override public Object getCellEditorValue() { String value = (String) super.getCellEditorValue(); return new Resource(value); } @Override public boolean isCellEditable(EventObject e) { return super.isCellEditable(e) && ((TreeNode) lastPath.getLastPathComponent()).isLeaf(); } } private static class Resource { String name; public Resource(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return getName(); } } private void display() { JFrame f = new JFrame("TreeEditorDemo"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new TreeEditDemo().display(); } }); } } 

我find了一个非常简单的解决scheme。 当TreeNode被重命名时,它最终成为树中唯一选定的节点。 因此,我能够使用:

  CustomTreeNode node = (CustomTreeNode) tree.getLastSelectedPathComponent();