Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

300 ГЛАВА 11

// интерфейс создаем в потоке рассылки событий

SwingUtilities.invokeLater( new Runnable() {

public void run() {

// присоединяем список

JList list = new JList(dblm); // помещаем список в окно

JFrame frame = new JFrame("DBList"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 200);

frame.add(new JScrollPane(list)); frame.setVisible(true);

} });

}

}

Для работы модели нам понадобится соединение с базой данных. Подойдет практически любая база данных и ее любая таблица, в которой есть столбец с текстовыми данными. Для соединения с базой данных мы задействуем интерфейс JDBC (Java Database Connectivity)3, настройка его для работы с вашей системой управления базами данных (СУБД) зависит от используемой платформы. Чаще всего это несложно и подробно описано в документации. Для правильной работы нам необходимо загрузить драйвер (мы применяем стандартный драйвер JDBC-ODBC от Sun, входящий в пакет JDK) и создать соединение с базой данных. Для этого требуется три параметра: идентификатор базы данных (Data Source Name DSN), имя пользователя (User ID UID) и его пароль (Password PWD). Эти параметры будут зависеть от базы данных и ее настроек. После этого, если все проходит успешно, производится запрос к базе данных (запрос находится в строке query, измените его так, чтобы он работал с вашей базой данных), и модель DatabaseListModel получает результат запроса ResultSet и название столбца, данные которого появятся в списке. Мы смело вызываем методы модели DatabaseListModel прямо из потока метода main(), потому что сама модель пока еще не присоединена ни к одному графическому компоненту.

Напоследок, уже из потока рассылки событий, к модели присоединяется вид — список JList, который мы помещаем в окно. Запустив приложение, вы увидите, как список выводит элементы, полученные моделью из базы данных. Использованный нами в примере подход гибок и удобен: модель выполняет все действия по получению и подготовке данных, и если у вас есть вопросы по данным, вы обращаетесь к ней. Список связывается с моделью и отображает ее информацию, и вы знаете, что для изменения внешнего вида программы нужно работать с видом, но не с данными. Все на своих местах.

Модели для больших списков

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

3 Интерфейс JDBC — часть стандартной библиотеки JDK. Узнать об этом интерфейсе подробнее вы сможете в интерактивной документации пакета java.sql и на официальном сайте java.sun.com.

Списки

301

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

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

Постепенное добавление элементов в модель списка, который уже находится на экране, требует наличия отдельного потока, загружающего данные (это может быть объект SwingWorker, который мы рассматривали в главе 3). Чем реже мы будем сообщать списку о новых данных (блоками новых элементов), тем меньше он будет перерисовывать себя, и значит, тем быстрее будет отклик на действия пользователя, а это для последнего всегда важно. Сообщать списку о добавлении новых данных следует только из потока рассылки событий, иначе рано или поздно крах программы неминуем.

Список JList никогда не просит информацию об элементах списка, не видных в данный момент на экране, так же работают и остальные сложные компоненты Swing. Если приложение подразумевает работу в определенном диапазоне элементов списка, то список JList будет запрашивать информацию только о них и элементах, находящихся около них. Этот факт можно использовать для кэширования, если, например, элементы списка хранятся на диске. Все элементы большого списка невозможно хранить в памяти, так как она не безгранична, поэтому вы можете хранить их где-либо еще, в базе данных или подобном хранилище, и идея кэширования элементов, с которыми в данный момент работает пользователь, и близлежащих элементов позволит порядочно ускорить доступ к ним.

Выделение

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

Главные два метода модели выделения — setSelectionInterval() и addSelectionInterval(). Первый метод устанавливает новый интервал выделения, а второй добавляет к уже имеющемуся выделению еще один интервал выделения. Интервал выделения задается двумя целыми числами: позицией первого выделенного элемента и позицией последнего выделенного элемента. Они могут совпадать, что означает выделение одного элемента, и необязательно первое число должно быть больше второго. В методе addSelectionInterval() вы сможете провести основную работу по выделению элементов, задав именно те режимы выделения, которые вам подходят. К примеру, используемая списком JList по умолчанию модель в режиме одиночного выделения позволяет выделять только один элемент, даже если пользователь попытался выделить большой интервал из нескольких элемен-

302

ГЛАВА 11

тов, и следит за этим она именно в упомянутых двух методах. В модели выделения также отдельно хранится начало последнего интервала выделения (selection anchor) и конец этого интервала выделения (selection lead). На некоторых платформах выделенные последними интервалы изображаются особым образом (так пользователи поймут, что же именно они выделили в последний раз), в расчете на такие случаи эти интервалы хранятся в модели отдельно. С помощью модели выделения вы также можете полностью отменить текущее выделение и задать специальный режим методом setValueIsAdjusting(). Такой режим полезен там, где выделение непрерывно обновляется (к примеру, выделение путем перетаскивания мыши), и каждый новый интервал можно считать частью предыдущего, не оповещая о нем слушателей.

Все описанные в интерфейсе ListSelectionModel возможности полностью реализованы в стандартной модели выделения DefaultListSelectionModel. Именно она используется в списках JList по умолчанию и менять ее чем-то особенным требуется редко. Она поддерживает три режима выделения элементов списка и позволяет получить исчерпывающую информацию о текущем выделении. Давайте посмотрим на примере, как с ней работать:

//ListSelectionModes.java

//Различные режимы выделения import javax.swing.*;

import java.awt.*;

public class ListSelectionModes extends JFrame { private String[] data = { "Красный", "Синий",

"Зеленый", "Желтый", "Белый"}; public ListSelectionModes() {

super("ListSelectionModes"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//заполним модель данными

DefaultListModel dlm =

new DefaultListModel(); for (String next : data)

dlm.addElement(next);

//три списка с разным типом выделения

JList list1 = new JList(dlm); list1.setSelectionMode(

ListSelectionModel.SINGLE_SELECTION); JList list2 = new JList(dlm); list2.setSelectionMode(

ListSelectionModel.SINGLE_INTERVAL_SELECTION); JList list3 = new JList(dlm);

//аналогично предыдущему вызову list3.getSelectionModel().setSelectionMode(

ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

//добавляем компоненты

Списки

303

setLayout(new FlowLayout()); add(new JScrollPane(list1)); add(new JScrollPane(list2)); add(new JScrollPane(list3)); // выведем окно на экран setSize(300, 200); setVisible(true);

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new ListSelectionModes(); } });

}

}

В примере мы заполняем стандартную модель DefaultListModel данными из массива (можно было бы передать массивы напрямую в конструкторы списков, но это не позволит нам сэкономить память) и на ее основе создаем три списка с одинаковыми элементами. Разница между списками лишь в режиме выделения элементов. Режим выделения можно сменить двумя способами: вызвав метод setSelectionMode() класса JList или вызвав метод с точно таким же названием уже для самой модели выделения. На самом деле это одно и тоже, метод класса JList просто обращается к модели выделения. В нашем распоряжении имеется три режима выделения (табл. 11.1).

Таблица 11.1. Режимы выделения элементов списка

Режим

Описание

 

 

SINGLE_SELECTION

Позволяет пользователю выбирать только один

 

элемент списка. Часто используемый режим, хотя

 

для тех же целей могут быть успешно примене-

 

ны группы переключателей или раскрывающиеся

 

списки

SINGLE_INTERVAL_SELECTION

Пользователь может одновременно выбирать не-

 

сколько элементов списка, но только смежных

MULTIPLE_INTERVAL_SELECTION

Самый гибкий режим, используемый моделью вы-

 

деления по умолчанию. Позволяет выбирать произ-

 

вольное количество элементов списка в произволь-

 

ном сочетании (в любом месте списка, поодиночке

 

или интервалами)

 

 

Запустив программу с примером, вы сможете оценить разницу в различных режимах выделения. Один элемент может быть выбран щелчком мыши или нажатием клавиш управления курсором, а интервалы и дополнительные элементы могут быть выбраны с помощью вспомогательных клавиш Shift и Ctrl. Стандартными внешними видами Swing поддерживаются и многие другие клавиши, особенно удобные для навигации в больших списках, их описание вы сможете найти в интерактивной документации Java.

304

ГЛАВА 11

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

//CustomListSelection.java

//Реализация особого режима выделения import javax.swing.*;

import java.awt.*;

public class CustomListSelection extends JFrame { private String[] data = { "Мороженное", "Курица",

"Холодное", "Горячее"}; public CustomListSelection() {

super("CustomListSelection"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//настроим список и добавим его в окно

JList list = new JList(data); list.setSelectionModel(new CustomSelectionModel()); add(new JScrollPane(list));

//выведем окно на экран

setSize(300, 200); setVisible(true);

}

// специальная модель выделения class CustomSelectionModel

Источник: https://studfile.net/preview/15935977/