простой и быстрый редактор ячеек JTree

У меня есть JTree с пользовательской TreeModel и пользовательским TreeRenderer. Модель дерева содержит множество объектов разных типов. Один из этих типов отображается иначе, чем другие: Отображаемый текст является конкатенацией двух полей объекта. Когда я редактирую ячейку, я хочу обновить одно из этих полей с отредактированным текстом. До сих пор у меня это работало довольно хорошо.

Моя проблема: это сбивает с толку, когда текст, отображаемый при редактировании, представляет собой полное объединенное значение двух полей, хотя на самом деле вы просто редактируете одно из полей. Поэтому я хочу отображать только содержимое одного поля, которое вы редактируете, когда пользователь начинает редактирование.

Я попытался сделать это с помощью пользовательского CellEditor и увидел, как он должен работать, и в моем случае этот подход кажется излишним. Я просто хочу изменить отображаемый текст в одном из многих случаев, поэтому, естественно, я хочу реализовать это, а не весь CellEditor для всего содержимого моего дерева.

Есть ли более быстрый и простой способ сделать это, или мне нужно использовать специальный редактор?

Спасибо


person Simiil    schedule 28.09.2012    source источник


Ответы (2)


Нет никакого способа обойти пользовательский редактор, и это самое короткое возможное решение :-) Кроме того, вам понадобятся некоторые средства в области data, которые могут интерпретировать значение редактирования соответствующим образом и обновлять себя, т.е. пользовательский узел.

F.i (прокомментирую позже, мой хромой firefox на этой машине доводит меня до мурашек)

/**
 * Basic code stolen from @trashgod at
* @see http://stackoverflow.com/a/11113648/230513
*/
public class TreeEditDemo extends JPanel {

    private JTree tree;
    private DefaultMutableTreeNode root;
    private DefaultTreeCellEditor editor;

    public TreeEditDemo() {
        super.setLayout(new GridLayout());
        root = new DefaultMutableTreeNode("Nodes");
        root.add(new MyResourceNode(new Resource("one", "first")));
        root.add(new MyResourceNode(new Resource("two", "first")));
        tree = new JTree(root);
        tree.setEditable(true);
        editor = new MyTreeCellEditor(tree,
            (DefaultTreeCellRenderer) tree.getCellRenderer());
        tree.setCellEditor(editor);
        this.add(new JScrollPane(tree));
    }

    private static class MyTreeCellEditor extends DefaultTreeCellEditor {

        public MyTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
            super(tree, renderer);
        }

        @Override
        public Component getTreeCellEditorComponent(JTree tree, Object value,
                boolean isSelected, boolean expanded, boolean leaf, int row) {
            if (value instanceof MyResourceNode) {
                value = ((MyResourceNode) value).getName();
            }
            return super.getTreeCellEditorComponent(tree, value, isSelected, expanded,
                    leaf, row);
        }

        @Override
        public boolean isCellEditable(EventObject e) {
            return super.isCellEditable(e)
                && ((TreeNode) lastPath.getLastPathComponent()).isLeaf();
        }
    }

    public static class MyResourceNode extends DefaultMutableTreeNode {

        /**
         * @param resource
         */
        public MyResourceNode(Resource resource) {
            super(resource);
        }

        @Override
        public void setUserObject(Object userObject) {
            if (userObject instanceof String) {
                setName((String) userObject);
            } else if (userObject instanceof Resource) {
                super.setUserObject(userObject);
            }    
        }

        public void setName(String name) {
            if (getUserObject() != null) {
                getUserObject().setName(name);
            }
        }

        public String getName() {
            if (getUserObject() != null) {
                return getUserObject().getName();
            }
            return null;
        }

        @Override
        public Resource getUserObject() {
            return (Resource) super.getUserObject();
        }


    }
    private static class Resource {

        String name;
        private String category;

        public Resource(String name, String category) {
            this.name = name;
            this.category = category;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
        @Override
        public String toString() {
            // BEWARE: don't do this in production code!
            return name + " (" + category + ")";
        }
    }

    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();
            }
        });
    }
}
person kleopatra    schedule 29.09.2012
comment
+1 за более надежный подход. Может ли CellEditorListener быть подходящей альтернативой? - person trashgod; 29.09.2012
comment
хороший вопрос - как правило, не рекомендую его, потому что это будет конкурировать со стандартными слушателями (в дереве или таблице) - person kleopatra; 29.09.2012
comment
Привет. Я новичок в свинге. Что должно быть установлено для lastPath? - person null; 23.04.2013
comment
@ hal9000 настройка выполняется в super.isCellEditable :-) Хотя вы можете столкнуться с небольшим сбоем: он устанавливается только в том случае, если событие имеет тип MouseEvent, а не для клавиатуры или других ... нужно копать на днях - спасибо за головы вверх! Ведь никакого глюка: обновляется свойство в selectionListener - какой яркий зверь, DTreeCR, берущий на себя оооочень много задач.. - person kleopatra; 23.04.2013
comment
@kleopatra Извините, я все еще кое-что упускаю. Здесь определен lastPath? - person null; 24.04.2013
comment
@hal9000 lastpath — это путь к строке: либо один клик в isCellEditable, либо последний выбранный, если событие не является mouseEvent — взгляните на источник super, то есть DTreeCR - person kleopatra; 24.04.2013
comment
@kleopatra спасибо, я был полностью озадачен тем, как делать такие вещи (очень распространенное требование). Отличное практическое решение. Одна вещь: бизнес lastPath немного усложняет ситуацию... вы можете просто вернуть true из isCellEditable (для демонстрационных целей). - person mike rodent; 26.04.2014

Требуется пользовательский редактор. MyTreeCellEditor, показанный здесь, показывает один подход. Он обновляет произвольный атрибут userObject, который называется Resource и хранится в DefaultMutableTreeNode. Поскольку атрибут является текстовым, он также использует расширение DefaultTreeCellRenderer. Ваш пользовательский TreeModel, вероятно, управляет аналогичным userObject, который является родителем ваших "объектов разных типов".

person trashgod    schedule 28.09.2012