Вопрос по rename, java, swing, events, treenode – Получить отредактированный TreeNode от CellEditorListener

3

Ранее я спрашивал, как вызвать событие, когда TreeNode был переименован (Вот). На мой вопрос ответили, но я столкнулся с другой проблемой. Мне нужно получить доступ к TreeNode, который редактируется в событии CellSditorListener editStopped. Вот код, который я должен сделать так:

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());
    }
}

Я получаю эту ошибку:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.tree.DefaultTreeCellEditor$1 cannot be cast to 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;
}

Я получил ту же ошибку (я ожидал, что будет). Что у меня должно работать, так что единственный реальный вопрос остается: «Почему я получаю сообщение об ошибке и как я могу это исправить?», & Quot; но если у кого-то есть лучший способ сделать это, я готов выслушать.

РЕДАКТИРОВАТЬ 2: Я сделал небольшой пример того, чего я пытаюсь достичь, и который можно найти.Вот (Это архив Eclipse).

@mKorbel: +1 за ваш ответTreeCellEditor интерфейс v. реализация по умолчанию. Я приветствую ваш критический отзыв о моихapproach. trashgod
Ужасно, что CellEditor (JTextField или JComboBox) доступен только на 3-м месте. mouse_click, mKorbel

Ваш Ответ

2   ответа
0

которое было на самом деле очень простым. Когда TreeNode переименовывается, он становится единственным выбранным узлом в дереве. Из-за этого я смог использовать:

    CustomTreeNode node = (CustomTreeNode) tree.getLastSelectedPathComponent();
Смею ли я предположить, что это на самом деле не идеально? Что, если ваша модель выбора JTree не работает с множественным выбором, поэтому переименование не отменяет другие выборы? Или если вы изменили JTree каким-то образом, чтобы редактировать без выбора? Я предлагаю один из способов - создать подкласс DefaultTreeCellEditor (DTCE), добавить CellEditorListener в конструктор, переопределить getTreeCellEditorComponent, а затем создать любые данные, которые должны сохраняться при редактировании полей. Одним из полезных (защищенных) полей в DTCE является «lastRow» ... вы можете получить к нему доступ изнутри editStopped, чтобы в большинстве кругов вернуться к своему узлу.
8

Resource вDefaultMutableTreeNode, Как вы обнаружили, источникChangeEvent отправленоeditingStopped() вnot DefaultTreeCellEditor; это делегат редактора (анонимный) пользовательского интерфейса.

Вместо этого переопределитеgetCellEditorValue() в вашемDefaultTreeCellEditor, как показано ниже.DefaultTreeCellRenderer просто звонитtoString(), с помощьюconvertValueToText(), который обращается к объекту пользователяDefaultMutableTreeNode.

Дополнения: обратите внимание, чтоisCellEditable() обеспечивает редактирование только конечных узлов.

Как отмечает @kleopatra в комментариях, предыдущийTreeCellEditor реализация была недействительной, так как она изменяла редактируемый узел. Пересмотренная версия ниже создает новый узел с обновленным именем;конструктор копирования было бы полезно в этом контексте. Преимущество состоит в том, чтоuserObject остаетсяResource, Смотрите также этоальтернативный подход.

image

/**
 * @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();
            }
        });
    }
}
может быть, самое время изучить этот ужасный JComponent
хм ... это не совсем корректная реализация редактора: этоmust not изменить что-либо в модели, как сделано выше в getCellEditorValue.
Я действительно смог изменить количество кликов очень легко. Я просто поместил это в свой класс CustomTreeCellEditor (расширяет DefaultTreeCellEditor): защищенный логический canEditImmediately (событие EventObject) {if (event == null) return true; if (((MouseEvent) event) .getClickCount () & gt; = 2) return true; вернуть ложь; } jimn346
+1 и пожалуйстаsee my question
Для удобства можно привязать ключ к существующему редактированиюAction: tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Fn, 0), "startEditing").

Похожие вопросы