JXtreeTable игнорирует getValueAt для узлов дерева

У меня есть JXTreeTable, который имеет дерево узлов (разные типы данных) с левой стороны и сетку с правой стороны (по умолчанию).

Теперь я хочу, чтобы все отображаемые значения (также заголовки деревьев) брались из метода getValueAt(row,column), но вместо узлов дерева отображались их методом toString()

Как я могу заставить JXTreeTable не принимать класс toString() и использовать значение, возвращаемое getValueAt(...)?

Спасибо!

вот моя модель:

public class TreeTableGroupTreeTableModel extends AbstractTreeTableModel {

    private final static String[] COLUMN_NAMES = { "Tree",
            "Add/Edit", "Remove" };

    //Group-Hierarchy:
    private JXGroup groupRootObject;

    public TreeTableGroupTreeTableModel(JXGroup groupRoot) {

        this.groupRootObject = groupRoot;

    }

// Here is my structure:
//GROUP 1-1 ModuleAggregation 1-* Modules 1-1 JXGroupAccessMemberAggregation 1-* JXGroupAccessSimpleUserObjectLeaf

    /**
     * Returns the value for the node at columnIndex. The node must be managed
     * by this model. Unamanaged nodes should throw an IllegalArgumentException.
     * 
     * 
     * node - the node whose value is to be queried column - the column whose
     * value is to be queried
     */
    @Override
    public Object getValueAt(Object node, int column) {

        System.out.println(node.getClass());

        if (node instanceof JXGroup) {
            switch (column) {
            case 0:
                return "this should render this string instead of the class tostring()";//((JXGroup) node);
            case 1:
            case 2:
                return "";
            }
        } else if (node instanceof JXGroupAccessModuleAggregation) {
            switch (column) {
            case 0:
                return "Modules";
            case 1:
                return "ADD";
            case 2:
                return "REMOVE ALL";
            }
        } else if (node instanceof JXGroupAccessModule) {
            switch (column) {
            case 0:
                return ((JXGroupAccessModule) node).getModule();
            case 1:
                return "ADD";
            case 2:
                return "REMOVE";
            }
        } else if (node instanceof JXGroupAccessMemberAggregation) {
            switch (column) {
            case 0:
                return "Members";
            case 1:
                return "ADD";
            case 2:
                return "REMOVE ALL";
            }
        } else if (node instanceof JXGroupAccessSimpleUserObjectLeaf) {
            switch (column) {
            case 0:
                SimpleUserObject c = FunctionsUser.getUser(
                        metaDataPackage.getUsers(),
                        ((JXGroupAccessSimpleUserObjectLeaf) node).getUserId().getId());
                return c.getShowAs();
            case 1:
                return "";
            case 2:
                return "REMOVE";
            }
        } 

        return null;
    }

    /**
     * Sets the value for the node at columnIndex to value. The node must be
     * managed by this model. Unamanaged nodes should throw an
     * IllegalArgumentException.
     * 
     * value - the new value node - the node whose value is to be changed column
     * - the column whose value is to be changed
     */
    @Override
    public void setValueAt(Object value, Object node, int column) {

        return; // changes are not allowed

    }

    @Override
    public Object getRoot() {
        return groupRootObject;
    }

    @Override
    public int getColumnCount() {
        return COLUMN_NAMES.length;
    }

    @Override
    public String getColumnName(int column) {
        return COLUMN_NAMES[column];
    }

    @Override
    public boolean isCellEditable(Object node, int column) {
        return false;
    }

    @Override
    public boolean isLeaf(Object node) {
        return node instanceof JXGroupAccessCategoryLeaf
                || node instanceof JXGroupAccessChapterLeaf
                || node instanceof JXGroupAccessEntryLeaf
                || node instanceof JXGroupAccessSimpleUserObjectLeaf;
    }

    @Override
    public int getChildCount(Object obj) {

        if (!(obj instanceof JXICountable)) {
            System.out.println("parsing error. should be JXCountable (but is "
                    + obj.getClass() + ")");
            return 0;
        }

        JXICountable obj2 = (JXICountable) obj;

        return obj2.getChildrenCount();

    }

    @Override
    public Object getChild(Object parent, int index) {
        if (parent instanceof JXITreeNodeAble) {
            return ((JXITreeNodeAble) parent).getChild(index);
        }
        throw new IllegalArgumentException(
                "parent is not a member of JXITreeNodeAble");
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        if (parent instanceof JXITreeNodeAble) {
            return ((JXITreeNodeAble) parent).getIndexOfChild(child);
        }
        throw new IllegalArgumentException(
                "parent is not a member of JXITreeNodeAble");
    }
}

person Niko    schedule 27.10.2014    source источник
comment
Это должен быть свингх JXTreeTable (в стандартном свинг нет JXTreeTable), я добавил тег swingx   -  person lbalazscs    schedule 27.10.2014
comment
Почему бы вам просто не использовать getValueAt(Object node, int column)?   -  person Ordous    schedule 29.10.2014


Ответы (1)


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

  • Иерархический: учитывая отношения родитель-потомок.
  • Пользовательские данные: предоставляется возможность сохранять и извлекать пользовательские объекты с помощью методов setUserObject(..) и getUserObject().
  • Данные столбцов: каждый узел отвечает за получение данных, связанных с каждым индексом столбца, чтобы обеспечить возможность представления в табличной форме.

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

Обновлять

Теперь, когда вы разместили свой код и исходный код откуда он основан, имейте в виду, что реализация не имеет корня (узла, с которым у вас возникли проблемы) и работает напрямую с объектами домена, чтобы избежать проблем с TreeTableNodes. Существует последующий пост, в котором автор изменяет реализацию модели таблицы дерева, чтобы включить корневой узел. Сказав это, есть по крайней мере две вещи, которые вы должны изменить:

  1. Не переопределяйте метод getRoot() и оставьте реализацию, унаследованную от AbstractTreeTableModel.
  2. Измените конструктор класса, вызвав соответствующий конструктор super.

В коде:

public class TreeTableGroupTreeTableModel extends AbstractTreeTableModel {
    ...
//    private JXGroup groupRootObject; Not needed!
    ...
    public TreeTableGroupTreeTableModel(JXGroup groupRoot) {
        super(groupRoot);
    }
    ...    
//    @Override
//    public Object getRoot() {
//        return groupRootObject;
//    }
    ...
}

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

class JXGroupAccessModuleTreeTableNode extends AbstractMutableTreeTableNode {

    public JXGroupAccessModuleTreeTableNode(JXGroupAccessModule module) {
        super(module);
    }

    public JXGroupAccessModuleTreeTableNode(JXGroupAccessModule module, boolean allowsChildren) {
        super(module, allowsChildren);
    }

    @Override
    public Object getValueAt(int column) {
        JXGroupAccessModule module = (JXGroupAccessModule)getUserObject();
        switch (column) {
            case 0: return module.getModule();
            case 1: return "ADD";
            case 2: return "REMOVE";
                default: throw new ArrayIndexOutOfBoundsException(column);
        }
    }

    @Override
    public int getColumnCount() {
        return 3;
    }
}

Чтобы разрешить редактирование ячеек, вы также должны переопределить методы setValueAt(Object value, int column) и isEditable(column): по умолчанию AbstractMutableTreeTableNodes недоступны для редактирования.

При таком подходе вы получите следующие преимущества:

  • С моделью древовидного стола вообще не нужно возиться.
  • Если древовидную структуру необходимо изменить, вам нужно только изменить порядок узлов по мере необходимости. Опять же, нет необходимости изменять код какой-либо модели.
  • Представление каждого узла отделено от модели, поэтому вы можете представлять один и тот же объект домена по-разному, просто переопределяя пару методов в узле таблицы дерева (не модели).
person dic19    schedule 29.10.2014
comment
привет, я следовал этому примеру (который не использует UserObject или AbstractMutableTreeTableNodes): javanbswing.blogspot.co.at/2013/08/. Это причина, по которой он берет значение из нормального toStrign() моего, например. Класс сотрудников? - person Niko; 04.11.2014
comment
Это совершенно другой способ использования JXTreeTable, потому что автор реализует свой собственный TreeTableModel, чтобы избежать работы с TreeTableNodes. В этом случае я не могу помочь вам, не видя вашего кода. Пожалуйста, рассмотрите возможность редактирования вашего вопроса, включая модель таблицы дерева. Интересный пост кстати @Niko - person dic19; 04.11.2014
comment
Привет, я добавил модель - person Niko; 05.11.2014
comment
Вау, это много кода. Мне было интересно узнать о потенциальных узких местах в реализации TreeTableModel таким образом. Теперь у меня есть ответ: это действительно сложно отлаживать/обслуживать. См. Таблицы дерева предназначены для работы с TreeTableNodes и полагаются на эти узлы для предоставления данных столбцов с помощью метода getValueAt(int column), как показано выше. Моими лучшими предложениями были бы: 1) Откажитесь от пользовательской модели таблицы дерева и используйте DefaultTreeTableModel, которая предназначена для работы с узлами дерева. 2) Определите столько узлов таблицы дерева, сколько вам нужно, чтобы сохранить иерархию группировки. @Нико - person dic19; 05.11.2014
comment
так вы говорите, что простое расширение treetablenode решит проблему? дело в том, что я хочу повторно использовать эти JX-объекты и для других древовидных таблиц (с другими значениями для возврата в getValueAt()). поэтому я должен выполнять основной рендеринг в модели getValueAt(), а не в каждом отдельном узле-объекте... - person Niko; 05.11.2014
comment
или он не предназначен для получения значения деревьев из getValueAt моделей? или проблема в том, что это должен быть объект, возвращаемый getChild(index...) (который, например, является ModuleAggregation со всеми его дочерними элементами и т. д.), и я пытаюсь вернуть простую строку?) - person Niko; 05.11.2014
comment
Пожалуйста, смотрите мое обновление. Надеюсь, в этот раз будет полезнее. @Нико - person dic19; 06.11.2014
comment
Привет @kleopatra, извините за беспокойство. Не могли бы вы взглянуть на это дело? Ваши отзывы будут действительно оценены. Заранее спасибо. - person dic19; 06.11.2014