Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > Как скрыть/восстановить столбец в JTable?..


Автор: Kurt 6.1.2005, 19:27
Не так давно на форуме промелькнул вопрос о том, как можно скрыть столбцы в JTable. В ответ предлагалось использовать removeColumn(). Однако, в таком случае довольно затруднительно обратно показать те столбцы, что были скрыты. Информация из сети и мудрые люди натолкули меня на довольно изящное, как мне кажется, решение - поработать с TableModel. Ведь именно там хранятся данные и там описываются методы доступа к ним.
В итоге, получилось так:
В класса TableModel будем хранить не только сами данные и заголовки, но и некий объект содержащий список видимых столбцов. У меня - это вектор, хотя можно использовать все, что душе угодно. Индекс эл-та вектора - номер ОТОБРАЖАЕМОГО столбца, а значение - индекс "постоянного" столбца таблицы. А потом переопределим методы получения данных из модели.
..Н-да.. Туманно объяснил.. Лучше на примере. Я взял стандартный сановский пример и чуток подкорректировал его.

Итак, создаем нашу TableModel:
Код

..
class MyTableModel extends AbstractTableModel {

//это наши заголоки:
       final String[] columnNames = {"First Name",
                                     "Last Name",
                                     "Sport",
                                     "# of Years",
                                     "Vegetarian"};

//данные таблицы:
       final Object[][] data = {
           {"Mary", "Campione",
            "Snowboarding", new Integer(5), new Boolean(false)},
           {"Alison", "Huml",
            "Rowing", new Integer(3), new Boolean(true)},
           {"Kathy", "Walrath",
            "Chasing toddlers", new Integer(2), new Boolean(false)},
           {"Sharon", "Zakhour",
            "Speed reading", new Integer(20), new Boolean(true)},
           {"Angela", "Lih",
            "Teaching high school", new Integer(4), new Boolean(false)}
       };

//вектор видимых столбцов:
       Vector visible_columns;

//конструктор:
       MyTableModel(){
 //здесь мы создаем наш вектор и заполняем его начальными значениями.
           visible_columns = new Vector();
           for (int i=0; i<columnNames.length; i++){
                  visible_columns.add(new Integer(i));
           }

       }
..


А теперь переопределим основные методы:
Код

..
     public int getColumnCount() { //получаем кол-во ВИДИМЫХ столбцов
           return visible_columns.size();
       }

..

       public String getColumnName(int col) { //получаем заголовок
           //для этого с помощь вектора видимых столбцов получаем номер столбца,
   // к-й надо отобразить
           int true_column = ((Integer)visible_columns.get(col)).intValue();
           return columnNames[true_column];
       }

       public Object getValueAt(int row, int col) {
    //аналогично getColumnName
           int true_column = ((Integer)visible_columns.get(col)).intValue();
           return data[row][true_column];
       }
..

Далее можно определить методы сокрытия/восстановления столбцов. Возможно, я зря использовал Vector, может, с другими классами было бы легче - ну, воля ваша. Я написал метод turnOffColumn(), к-й скрывает i-й столбец (где i - индекс столбца в "статичном" массиве столбцов. Он не зависит от кол-ва видимых колонок!) , и метод resetColumns() - он восстанавливает видимтость всех столбцов.
Можно было бы написать метод восстановления конкретного столбца, но при решении моей задачи это было не нужно. smile
Итак, вот код этих методов. Он не представляет особой сложности:
Код

..
public void turnOffColumn(int col) {
       Integer intCol = new Integer(col);
       int i=visible_columns.indexOf(intCol);
       if(i!=-1){
            visible_columns.remove(i);
       };
       fireTableStructureChanged();
   }

   public void resetColumns(){
       visible_columns.clear();
       for (int i=0; i<columnNames.length; i++){
                  visible_columns.add(new Integer(i));
       };
        fireTableStructureChanged();
   }
..


Вот, собственно, и все. Прелесть моего решения - нет зависимости от отображаемых столбцов и кроме того, можно легко восстановить скрытые колонки.
Повторюсь, мысль применить такой способ принадлежит не мне, я лишь реализовал. Кроме того, я практически не пишу на Java, поэтому не отрицаю, что мой код содержит множество неэффективных решений. Ну, по крайней мере, это работает. smile
Итак, я прикрепляю авхив с исходником работающего примера - можно брать и компилить. Правда, пример реализован крайне убого, но ведь это не главное. smile В коде я по кнопке удаляю/восстанавливаю 2-й и 4-й столбцы. Enjoy it.
..
Если мои усилия оказались полезными - можно кинуть в FAQ. ;)

Автор: Domestic Cat 6.1.2005, 19:37
Попытался добавить в ФАК - как в пустоту кануло, ни ответа ни привета. smile

Автор: AntonSaburov 6.1.2005, 19:40
Сейчас попробую - подождите минутку.
Добавлено @ 19:45
Все нормально - можно http://vingrad.ru/VF-JAV-002188 smile

Kurt - большое спасибо.

Автор: Domestic Cat 6.1.2005, 19:48
А почему у меня не сработало?

Автор: Kurt 6.1.2005, 19:55
Рад, что понравилось. smile

Автор: AntonSaburov 6.1.2005, 20:03
Цитата(Domestic @ 6.1.2005, 19:48)
А почему у меня не сработало?

А ты еще маленький smile Хоть и "Котище" smile
Дозволения на такие штуки у тебя нет.

Автор: Domestic Cat 6.1.2005, 20:07
Вроде ж в новостях Админ говорил что модератор раздела вносит статьи в ФАК.

Автор: igon 7.1.2005, 01:51
Цитата
Не так давно на форуме промелькнул вопрос о том, как можно скрыть столбцы в JTable. В ответ предлагалось использовать removeColumn(). Однако, в таком случае довольно затруднительно обратно показать те столбцы, что были скрыты. Информация из сети и мудрые люди натолкули меня на довольно изящное, как мне кажется, решение - поработать с TableModel.


Решение, предлагаемое Kurt'ом, безусловно заслуживает права на существование как один из вариантов реализации сокрытия/восстановления столбцов в JTable, однако хотелось бы остановиться на некоторых моментах:
1. "Промелькнул" - это не то слово, которым можно описать наличие на форуме нескольких топиков с огромными кусками исходных текстов, инициатором которых был sanic smile
2. Использование removeColumn() без использования TableModel никогда не предлагалось, т.к. в исходной постановке задачи указывалось на необходимость манипуляций со скрытыми столбцами.
3. Для реализации функциональности, предлагаемой Kurt'ом (скрыть некоторые/показать все), нет необходимости в создании отдельного класса с дополнительными структурами и переопределением методов. Использование removeColumn() для сокрытия некоторых столбцов тривиально и в комментариях не нуждается. Отмечу только, что удаление столбца из JTable не сопровождается удалением его и из TableModel. Что же касается восстановления показа всех столбцов, то вот эскизный вариант реализации:

Код

class Test...
  JTable table;
  DefaultTableModel model = DB.CallStoredProcedure();
...
метод showSome
   table = new JTable(model);
   table.removeColumn(7);
   table.removeColumn(3);    
   table.removeColumn(2);
...
метод showAll
   table = new JTable(model);
...



Автор: Domestic Cat 7.1.2005, 03:56
Цитата(igon @ 6.1.2005, 16:51)
3. Для реализации функциональности, предлагаемой Kurt'ом (скрыть некоторые/показать все), нет необходимости в создании отдельного класса с дополнительными структурами и переопределением методов. Использование removeColumn() для сокрытия некоторых столбцов тривиально и в комментариях не нуждается. Отмечу только, что удаление столбца из JTable не сопровождается удалением его и из TableModel. Что же касается восстановления показа всех столбцов, то вот эскизный вариант реализации:



Kurt реализовал MVC, это самый лучший вариант реализации; если учесть что в твоем примере создается лишний объект JTable smile Хотя не единственный конечно.

Автор: igon 7.1.2005, 05:32
Цитата
Kurt реализовал MVC, это самый лучший вариант реализации

И как именно Kurt реализовал часть V(View) MVC? ИМХО, мой лишний объект JTable и будет этим самым View smile Более того, любое совместное использование JTable и TableModel подпадает под определение MVC (при условии наличия Listener'ов, естественно)
В моем примере лишним является не объект JTable, а, возможно, его лишняя общая переинициализация из model с полным перечнем столбцов - Kurt это делает более локализованно. Но будут ли при этом накладные расходы очень ощутимы?
Еще раз подчеркну - я не против создания и использования custom TableModel, но нужно ли, в случаях, подобных данному, ИМХО, излишнее усложнение?

Domestic Cat,
Цитата
Хотя не единственный конечно

относится к
Цитата
лучший вариант
или
Цитата
создается лишний объект
? smile

Автор: Domestic Cat 7.1.2005, 07:06
Вариант не единственный.

А вообще это пример, а не только код для решения определенной задачи. Конечно, если бы нам было нужно только удалить пару столбцов и все, то нет проблем. Но на форум часто приходят новые люди и регулярно задается вопрос на который отвечают: создай модель тейбла. Так что пример это хороший.
При написании кода хорошо оставлять "зацепки". Вот понадобится тебе отсортировать таблицу по к-л столбцу, и все равно придется добавлять модель.

Автор: JavaDell 19.7.2011, 09:33
С этим все понятно.
Но как быть, если данные в таблице динамически удаляются/появляются?
Делаю как описано здесь: http://www.codeguru.com/java/articles/660.shtml
только вместо статического массива данных обращаюсь к getDataVector() методу TableModel.
В итоге getColumnCount() обрезает таблицу с конца и получаю array out of bounds после того, как прячу столбы.

Автор: JavaDell 19.7.2011, 10:51
Вопрос снят, если кто не хочет замарачиваться со всеми этими внутренностями, есть решение проще:
Спрятать:
Код

jTable1.getColumnModel().getColumn(index).setMaxWidth(0);
jTable1.getColumnModel().getColumn(index).setMinWidth(0);
jTable1.getColumnModel().getColumn(index).setPreferredWidth(0);

Показать:
Код

final int WIDTH_TO_SET = getWidth()/(columns.size()-hidden.size()); // для примера
jTable1.getColumnModel().getColumn(index).setMaxWidth(WIDTH_TO_SET);
jTable1.getColumnModel().getColumn(index).setMinWidth(WIDTH_TO_SET);
jTable1.getColumnModel().getColumn(index).setPreferredWidth(WIDTH_TO_SET);

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)