Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> многоуровневые (иерархические) таблицы, как создать такую таблицу 
V
    Опции темы
bara
Дата 23.7.2010, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



В Java не очень силен. Есть необходимость создать таблицу, содержащую многоуровневые данные (древовидную структуру), с возможностью скрытия и раскрытия информации нижних уровней. Для ясности привожу картинки:
Свернутый вариант:
user posted image
Развернутый вариант:
user posted image
Пока что смог организовать подобное расположение путем манипулирования запросов к базе данных и ручным расположением данных. В таком варианте отсутствует возможность сортировки, кроме того в  одном столбце находятся данные разного типа, что тоже добавляет головной боли. Есть ли какие-либо стандартные средства решения подобной задачи?
PM MAIL   Вверх
jk1
Дата 23.7.2010, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 21
Всего: 75



Посмотрите в этой демке компонент JXTreeTable.


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
bara
Дата 23.7.2010, 15:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Похоже то что надо. Спасибо, буду разбираться...
PM MAIL   Вверх
bara
Дата 29.7.2010, 19:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Удалось добиться вот такого результата:
user posted image

Пока тревожат две проблемы: 

Во-первых не могу вывести сетку таблицы в первой колонке. Во всех остальных отрисовываю в TableCellRenderer следующим образом :
Код

public Component getTableCellRendererComponent(JTable table,
                        Object value, boolean isSelected, boolean hasFocus,
                        int row, int column) {
                    // TODO Auto-generated method stub
                    
                    if (column != 0){
                        
                        JLabel l = new JLabel();
                        
                        l.setText((String )value);
                        l.setForeground(isSelected ?
                                table.getSelectionForeground() :
                                    table.getForeground());
                        l.setBackground(isSelected ?
                                table.getSelectionBackground() :
                                    table.getBackground());
                        l.setBorder(hasFocus ?
                                BorderFactory.createLineBorder(table.getSelectionForeground(), SBT) :
                                BorderFactory.createMatteBorder(0, 0, BT, BT, table.getSelectionForeground()));
    
                        l.setOpaque(true);
    
                        l.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12));
                        return l;
                    }
                    
                    else {

                        System.out.println("1111");
                        
                        if (value == null)
                            System.out.println("value is empty");
                        else

                            System.out.println("value = "+value);
                        JLabel t = new JLabel("tra-ta-ta");
                        t.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12));
                        return t;
                    }
                }


Обработка первой колонки никаких результатов не дает, как будто она и не вызывается. Кто что может посоветовать?

Во-вторых отсутствует возможность сортировки. Насколько я понял, ее нужно реализовывать самому? пока этим вопросом не занимался, но может кто сведущ в этом вопросе подскажет заранее, дабы сократить время моих мученийsmile

Надеюсь на вашу помощь)
PM MAIL   Вверх
jk1
Дата 29.7.2010, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 21
Всего: 75



Цитата

Во-первых не могу вывести сетку таблицы в первой колонке. 

Код

table.setShowHorizontalLines(true);
table.setShowVerticalLines(true);

Border при этом совсем необязателен.
Цитата

Обработка первой колонки никаких результатов не дает, как будто она и не вызывается. Кто что может посоветовать?

Там Renderer другой, от дерева. Устанавливается методом setTreeCellRenderer();
Цитата

Во-вторых отсутствует возможность сортировки. Насколько я понял, ее нужно реализовывать самому? 

Стандартная сортировка, присутствующая в JTable в этом расширении отключена из-за неопределенности: в самом деле, что будет с деревом, если отсортировать последний столбец?


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
bara
Дата 29.7.2010, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Код

table.setShowHorizontalLines(true);
table.setShowVerticalLines(true);

Не срабатывает в данном случае. Первая колонка действительно обрабатывается setTreeCellRenderer(), пока не совсем все корректно, но думаю добью скоро. Спасибо за инфу.

А по поводу сортировки: понятно, что сортировать разные типы данных нелогично, но мне это и не нужно. Нужна сортировка по значениям верхнего уровня дерева, а нижние чтобы за ними перескакивали. Я так понимаю это нужно делать сортировкой Nod`ов, наверное не так и сложно. У меня вопрос в том, как ловить щелчок мыши по заголовкам, чтобы его обрабатывать? Ну и желательно заголовки тоже перерисовывать в зависимости от выбранного типа сортировки (стрелочки там на них нарисовать)
PM MAIL   Вверх
jk1
Дата 29.7.2010, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 21
Всего: 75



Код

table.getTableHeader().addMouseListener();

это что касается щелчка мыши по заголовкам
Цитата

Не срабатывает в данном случае. 

Скорее всего виноват LAF, я попробовал - на дефолтном работает. Либо Вы что-то совсем перемудрили в margin'ами или рендерерами, что они просто затирают линии. Вот пример на котором я тестил:
Код

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
        JFrame frame = new JFrame();
        JXTreeTable table = new JXTreeTable(new AbstractTreeTableModel() {
            public Object getValueAt(Object o, int i) {
                return " cell "+i + o.toString();
            }

            public void setValueAt(Object o, Object o1, int i) {
                //To change body of implemented methods use File | Settings | File Templates.
            }

            @Override
            public String getColumnName(int i) {
                return "Column "+i;
            }

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

            @Override
            public Object getRoot() {
                return "root";
            }

            @Override
            public int getChildCount(Object o) {
                return o.equals("root")?10:0;
            }

            @Override
            public Object getChild(Object o, int i) {
                return o.toString()+" child "+i;
            }
        });
        JScrollPane scroll = new JScrollPane(table);
        frame.add(scroll);

        table.setShowHorizontalLines(true);
        table.setShowVerticalLines(true);
        table.setRootVisible(true);
        frame.pack();
        frame.setVisible(true);
    }
}


Есть еще вероятность того, что в вашем случае сетка отрисовывается, но белого цвета. Лечится так:
Код

table.setGridColor(Color.BLACK);

Цитата

Я так понимаю это нужно делать сортировкой Nod`ов, наверное не так и сложно.

Пожалуй, это самое разумное решение. Это удобно будет сделать в модели таблицы.


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
bara
Дата 30.7.2010, 11:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Ваш пример у меня также отображается некорректно - сетка первой колонки не отрисовывается. setGridColor тоже не помогает. Делаю в Eclipse, Java 1.6 - в чем может быть проблема?
PM MAIL   Вверх
bara
Дата 4.8.2010, 15:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Написано кривовато, но результат определенно есть) Выкладываю получившийся вариант, вдруг кому понадобиться:

Эти рендереры рисуют сетку и красят строки чет/нечет (пока без разбора где какой узел).
Код

        class MyTreeTableCellRenderer extends JLabel implements TableCellRenderer {

            //Cell border thickness        
            public static final int BT = 1;

            //Selected cell border thickness
            private static final int SBT = 1;

            
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                // TODO Auto-generated method stub
                
                
                setText((String) value);
                if (isSelected){
                    setForeground(Color.black);
                    setBackground(Color.white);

                }else{
                    if (row%2 == 0){
                        setForeground(Color.black);
                        setBackground(new Color(153,167,255));
                    }else{
                        setForeground(Color.black);
                        setBackground(new Color(205,217,255));
                    }
                }
                setBorder(hasFocus ?
                        BorderFactory.createLineBorder(Color.gray, SBT) :
                        BorderFactory.createMatteBorder(0, BT, BT, 0, Color.gray));
                setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12));
                setOpaque(true);

                return this;
            }
        }
        
        class MyTreeCellRenderer extends JLabel implements TreeCellRenderer {

                ... 

// Для первого столбца все аналогично, только требуется установить размер JLabel, а то ячейка обрезанная получается
                    setPreferredSize(new Dimension(jf.getWidth(),20));     // jf - мой JFrame. Рисую линю на всю ширину, чтобы при любых изменениях ширины столбца ячейка была отрисована. Ничего умнее не придумал:)
                    ...
            }
        }



Сортировка происходит следующим образом (для данных типа String):
Код

        treeTable.getTableHeader().addMouseListener(new MouseListener(){

            @Override
            public void mouseClicked(MouseEvent arg0) {
                // TODO Auto-generated method stub
                int tmp=0;
                for(int i=0; i<treeTable.getColumnCount(); i++){
                    tmp=tmp+treeTable.getColumn(i).getWidth();
                    if (arg0.getX() < tmp){
                        
                        // сортировать узлы - в результате меняется root_node, на основе которого строится таблица 
                        Sorter.sort(i);
                        
                        //for (int n=0; n<root_node.getChildCount(); n++)
                        //    System.out.println(((Record) ((DefaultMutableTreeNode) root_node.getChildAt(n)).getUserObject()).getRecValue(i));
                        
                        // обновить таблицу на экране
                        refresh();
                        break;
                    }
                }
            }
}

    static class Sorter{
    
        // предыдущая отсортированный столбец
        static int prev_col;
        // направление сортировки
        static boolean forward=true;
        
        private static void sort(int col){
            
            // вспомогательный node
            DefaultMutableTreeNode tmp_root_node = new DefaultMutableTreeNode();
            
            // если столбец до этого не сортировался
            if (prev_col != col){
                prev_col=col;
                            
                // сортируем от меньшего к большему
                while (root_node.getChildCount()!=0)                    
                    //выбираем из root_node самый маленький элемент
                    //и добавляем его в вспомогательный node
                    tmp_root_node.add(getPik(col, true));
                
                //на основе root_node будет строиться таблица
                root_node = tmp_root_node;
                
            // если столбец сортирeтся повторно
            }else{
                // сортировать согласно переменной forward
                while (root_node.getChildCount()!=0){
                    //выбираем из root_node самый маленький/большой элемент
                    //и добавляем его в вспомогательный node
                    tmp_root_node.add(getPik(col, forward));                    
                }
                // изменить forward
                forward = !forward;
                //на основе root_node будет строиться таблица
                root_node = tmp_root_node;
            }            
        }
        
        private static DefaultMutableTreeNode getPik(int col, boolean forward){
            // принимаем экстремум равным первому элементу 
            String pik = (String) ((Record) ((DefaultMutableTreeNode) root_node.getChildAt(0)).getUserObject()).getRecValue(col);
            // индекс элемента, соответствующего экстремуму
            int pik_index=0;
            // от меньшего к большему
            if(forward){
                // перебираем все элементы
                for (int i=0; i<root_node.getChildCount(); i++){
                    // и если очередной элемент меньше текущего экстремума
                    if (((Record) ((DefaultMutableTreeNode) root_node.getChildAt(i)).getUserObject()).getRecValue(col).compareTo(pik)<0){
                        // запоминаем его
                        pik=((Record) ((DefaultMutableTreeNode) root_node.getChildAt(i)).getUserObject()).getRecValue(col);
                        pik_index=i;
                    }
                }
            // от большего к меньшему
            }else{
                // перебираем все элементы
                for (int i=0; i<root_node.getChildCount(); i++){
                    // и если очередной элемент меньше текущего экстремума
                    if (((Record) ((DefaultMutableTreeNode) root_node.getChildAt(i)).getUserObject()).getRecValue(col).compareTo(pik)>0){
                        // запоминаем его                        
                        pik=((Record) ((DefaultMutableTreeNode) root_node.getChildAt(i)).getUserObject()).getRecValue(col);
                        pik_index=i;
                    }
                }
            }
            
            // возвращаем наименьший/наибольший элемент
            return (DefaultMutableTreeNode) ((DefaultMutableTreeNode) root_node.getChildAt(pik_index));
        }
    }



У меня 2 насущных вопроса: 

1) как после сортировки отрисовать на заголовке соответствующего столбца стрелочку (или что-то подобное), чтобы наглядно было видно, какой столбец и в каком направлении отсортирован.

2) вопрос скорее по общему пониманию Java: сейчас таблица формируется методом getTable(). При ее изменении (например при сортировке), чтобы обновить отображаемый вид я удаляю из ScrollPane старую таблицу, формирую вызовом getTable() новую, и запихиваю ее обратно в ScrollPane. Если сделать собственный класс, экземпляром которого и будет таблица, как реализовать отображение ее обновленного состояния?
PM MAIL   Вверх
bara
Дата 9.8.2010, 19:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Может не очень понятно объяснил. Суть вопроса вот в чем: я формирую таблицу следующим образом:
Код

MyTreeTable treeTable = new MyTreeTable();


В классе MyTreeTable() описаны модель таблицы, рендереры и обработчики событий (сортировка). При клике на заголовке столбца изменяется дерево, на основе которого построена таблица, но перерисовка таблицы не происходит. Как выйти из ситуации?? Чувствую вопрос решается переписыванием каких-то методов, вроде repaint(), но пока ничего не получается(((
PM MAIL   Вверх
jk1
Дата 9.8.2010, 19:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 21
Всего: 75



Зря удаляете таблицу, по идеологии Swing MVC надо бы просто заменять модель у существующей.
А если непременно надо удалять и добавлять компоненты, когда форма уже видима, вызывайте revalidate() у контейнера после всех манипуляций с его содержимым.


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
bara
Дата 9.8.2010, 21:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Спасибо огромное! Замена модели - вот что мне нужно было. Удаление таблицы была полумера, потому как не знал как по-другому. Теперь все работает.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.0603 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.