Таблицы |
545 |
же интерфейсом ListSelectionModel) отвечает за выделение столбцов таблицы, но хранится она немного в другом месте: в модели столбцов таблицы TableColumnModel, которую мы недавно изучали. Как вы помните, модель выделения списка позволяет проводить выделение в одном из трех режимов: в режиме выделения одиночных элементов (SINGLE_ SELECTION), в режиме выделения непрерывными интервалами (SINGLE_INTERVAL_ SELECTION), а также в наиболее гибком режиме выделения произвольного набора элементов MULTIPLE_INTERVAL_SELECTION (в случае таблицы элементами для выделения являются строки или столбцы). Таким образом, для строк и для столбцов имеется по три режима выделения, так что всего таблица предоставляет нам девять комбинаций — впечатляющая гибкость, способная удовлетворить даже самым взыскательным нуждам.
Нетрудно догадаться, что по умолчанию в таблице и для строк, и для столбцов используется стандартная реализация интерфейса ListSelectionModel — класс DefaultListSelectionModel. Когда мы обсуждали выделение в списках, то пришли к выводу, что чаще всего писать собственную модель выделения нет особого смысла, стандартная реализация прекрасно подходит в подавляющем большинстве ситуаций. Она поддерживает списки слушателей ListSelectionListener, которые оповещаются об изменениях в выделенных строках и столбцах таблицы, и все три режима выделения. Только при реализации нетривиального поведения таблицы вам может понадобиться создание собственной модели выделения (как правило, путем наследования ее от класса DefaultListSelectionModel, как это делается, рассказано в главе 11).
Разберем теперь небольшой пример, в котором взглянем на некоторые способы управления выделением строк и столбцов в таблице JTable:
//TableSelection.java
//Режимы выделения ячеек таблицы import javax.swing.*;
import javax.swing.table.*; import java.awt.*;
public class TableSelection extends JFrame {
//названия столбцов таблицы private String[] columnNames = {
"Название", "Вкус", "Цвет"
};
//данные для таблицы
private String[][] data = {
{"Апельсин", "Кисло-сладкий", "Оранжевый"},
{"Арбуз", "Сладкий", "Темно-зеленый"},
{"Лимон", "Кислый", "Желтый"}
};
public TableSelection() { super("TableSelection"); setDefaultCloseOperation(EXIT_ON_CLOSE);
//создаем пару таблиц с одинаковыми данными
//первая таблица — выделение по строкам
JTable table1 = new JTable(data, columnNames); table1.getSelectionModel().setSelectionMode(
ListSelectionModel.SINGLE_INTERVAL_SELECTION);
548 |
ГЛАВА 17 |
и ее модели выделения позволяют узнавать, какие строки и столбцы выделяет пользователь. В табл. 17.8 собраны воедино основные методы, служащие этой цели.
Таблица 17.8. Методы для получения информации о выделенных ячейках
Методы |
Описание |
isSelectedIndex() (метод |
Метод позволяет узнать, выделен ли элемент на некоторой позиции. |
модели выделения) |
Именно данным методом модели выделения пользуются все осталь- |
|
ные, более удобные в работе, методы |
isRowSelected(), |
Методы класса JTable, позволяющие быстро узнать, выделена ли |
isColumnSelected(), |
строка (или столбец) с некоторым индексом. Третий метод дает воз- |
isCellSelected() |
можность определить, выделена ли ячейка, заданная строкой или |
|
столбцом |
getSelectedRows(), |
Также методы класса JTable, позволяющие получить массивы индек- |
getSelectedColumns() |
сов выделенных на данный момент строк и столбцов |
Модели выделения и изученные нами методы и свойства таблицы JTable позволяют полностью управлять работой механизмов выделения ячеек таблицы и получать исчерпывающую информацию о выделенных элементах таблицы. Не забывайте только, что модели выделения строк и столбцов действуют независимо друг от друга, как бы это не выглядело на экране. К примеру, если в вашей таблице действует режим выделения строк, и вы щелкаете на некоторой ячейке, выделяется вся строка, которой принадлежит выделенная ячейка, то есть все ячейки в данной строке выглядят как выделенные. Однако выделенными будут считаться только та строка и тот столбец, которым принадлежит ячейка, на которой вы щелкнули. Работу с выделением лучше всего проводить посредством моделей, и только изредка прибегать к методам класса JTable. Это сделает код более элегантным, упростит его поддержку и развитие, а модели вы при случае сможете разделить между видами, во многом сократив объем требуемой работы.
Сортировка и фильтрация
Таблица JTable позволяет не только отображать те данные, которые вы ей предоставляете посредством модели TableModel, но и обладает встроенными функциями их сортировки и фильтрации с минимальными усилиями с вашей стороны. Учитывая, что табличные данные очень часты в приложениях и, как правило, требуют сортировки (особенно если их много и их не охватить взглядом), наличие такой встроенной возможности, позволяющей не беспокоиться об этом в своей модели данных, приходится очень кстати.
Создатели Swing подошли к проблеме сортировки данных со всей возможной серьезностью. В пакет javax.swing был добавлен абстрактный класс RowSorter, способный проводить сортировку строк в любой модели, коль скоро она способна предоставить свои данные в виде строк и дает узнать общее количество этих строк. В принципе, данный класс можно было бы встроить во все компоненты библиотеки Swing, предоставляющие свои данные в виде строк, хотя бы в хорошо известные нам списки JList, однако на данный момент поддержка класса RowSorter имеется только в таблицах. Как и всегда в Swing, библиотека любезно предоставляет некую реализацию по умолчанию класса RowSorter под названием DefaultRowSorter. Однако, несмотря на название класса, он все еще абстрактный, так как все еще не знает точный тип модели, данные которой надо сортировать. Ну а конкретный класс для сортировки таблиц называется TableRowSorter.
Вникать в тонкие взаимоотношения классов для сортировки совсем не обязательно, если ваша задача состоит в простой сортировке таблицы. Пары методов класса JTable и знания некоторых деталей классов для сортировки, как правило, достаточно для подавляющего большинства приложений. Посмотрим, как добавить стандартную сортировку в таблицу:
Таблицы |
549 |
//SimpleSorting.java
//Сортировка таблицы по умолчанию import javax.swing.*;
import javax.swing.table.DefaultTableModel; import java.awt.*;
public class SimpleSorting extends JFrame { public SimpleSorting() {
super("SimpleSorting"); setDefaultCloseOperation(EXIT_ON_CLOSE);
// создаем таблицу на основе модели по умолчанию
SortModel sm = new SortModel(); sm.setColumnCount(4);
//добавляем сто строк случайных чисел for ( int i = 0; i < 100; i++ ) {
sm.addRow(new Integer[] { i, (int)(5*Math.random()), (int)(5*Math.random()), (int)(5*Math.random())} );
}
JTable table = new JTable();
//автоматическое включение сортировки table.setAutoCreateRowSorter(true);
//ограничение по количеству столбцов
((TableRowSorter)table.getRowSorter()).setMaxSortKeys(2); table.setModel(sm);
add(new JScrollPane(table));
//выводим окно на экран
setSize(400, 300); setVisible(true);
}
// модель для демонстрации сортировки и фильтрации static class SortModel extends DefaultTableModel {
// тип данных, хранимых в столбце
public Class getColumnClass(int column) { return Integer.class;
}
}
public static void main(String[] args) { SwingUtilities.invokeLater(
new Runnable() {