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

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

320

ГЛАВА 11

initList(). Отдельного внимания заслуживает только специальный слушатель событий от мыши, реализованный прямо на месте. При подходящем событии (одно нажатие левой кнопкой мыши6) слушатель с помощью модели получает элемент, на котором было произведено нажатие, и меняет его состояние. Также он посылает запрос на перерисовку списка (repaint()), чтобы тот обновил свои элементы, заметьте, как мы эффективно это делаем, перерисовывая только один, изменившийся, элемент списка, определить его прямоугольник на экране помогает метод списка getCellBounds(). Это очень важно для списков больших размеров, со сложными рисующими объектами, иначе перерисовка будет слишком медленной. И здесь мы подразумеваем, что все элементы в списке имеют одинаковый тип CheckBoxListElement, так что других элементов лучше в него не помещать.

Мы сделали основу для правильной работы списка с флажками, и теперь нам остается только проверить его в деле. Проиллюстрирует все небольшой пример:

//CheckBoxListTest.java

//Проверка работы списка с флажками import javax.swing.*;

import com.porty.swing.*; import java.awt.*;

public class CheckBoxListTest { // данные списка

private

static Object[] data = {

new

CheckBoxListElement(false, "Корпус"),

new

CheckBoxListElement(false,

 

"<html><h3><font color=red>Колонки"),

new

CheckBoxListElement(false, "Набор шлейфов"),

new

CheckBoxListElement(true, "Системная плата")

};

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

new Runnable() { public void run() {

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

JList list = new CheckBoxList(data);

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

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

6 Обратите внимание, что в слушателе мы переопределяем метод mousePressed(), вызываемый при нажатиях кнопок мыши. Если бы мы выбрали метод mouseClicked (то есть щелчок), то у нас могли бы возникнуть небольшие затруднения. Щелчком мыши считается событие нажатия и отпускания кнопки мыши на одном и том же месте экрана. Если пользователь при этом хотя бы немного шевелит мышью, щелчка не получится. Все зависит от того, как конкретный пользователь работает с мышью, но иногда непредсказуемость щелчков мыши сильно раздражает, так что мы выбрали нажатия.

Списки

321

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

} });

}

}

Мы создаем небольшое окно JFrame, в панель содержимого которого добавляем наш новый список CheckBoxList, вложенный в панель прокрутки. Для списка CheckBoxList годятся только данные типа CheckBoxListElement, их мы и подготавливаем в массиве data: задаем начальное состояние элемента (флажок может быть установленным или сброшенным) и надпись к нему. Если вспомнить все, что мы узнали о флажках JCheckBox в главе 9, то не останется сомнений, что флажки в Swing тоже поддерживают HTML. Вы видите, как мы используем HTML-текст для второго элемента списка. Запустив программу с примером, вы увидите хорошо знакомый по многим приложениям список с флажками, который к тому же способен задействовать всю мощь HTML.

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

Конечно, это лишь начальная заготовка для полнофункционального списка со флажками, который будет легко вписываться в любой отшлифованный интерфейс. К примеру, у нас не поддерживается выделение флажков с клавиатуры, нет эффекта «нажимания» флажка, а стоило бы его добавить, чтобы флажок не отличался от своих существующих на самом деле на экране собратьев, на элементе не прорисовываются фокус ввода. Но это все легко добавить всего несколькими мазками богатой палитры Swing.

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

322

ГЛАВА 11

Списки JList в Java 7

Новая версия платформы Java 7 (или JDK 1.7) привнесла в списки JList некоторые изменения. Функциональность списков и все то, что мы рассмотрели в данной главе, осталось неизменным, а вот способ работы с элементами списка в модели ListModel стал несколько иным. Начиная с Java 7, списки JList являются типизированными компонентами, то есть при их создании вы можете указать точный тип, который они хранят. То же самое относится и к модели списков ListModel. Без сомнения это удобно, вспоминая наши специальные объекты для списков со значками и списков с флажками, где нам приходилось постоянно заниматься ручным приведением типов. В Java 7, задав тип хранимого в списке объекта, мы не только упрощаем реализацию, но и запрещаем хранение в списке объектов неподходящих типов еще на этапе компиляции. Типизированным стал и объект для отображения элементов списка ListCellRenderer, что также позволит избавиться от проверки конкретных типов в его коде.

Раскрывающиеся списки JComboBox

Раскрывающиеся списки JComboBox служат для выбора одного из множества доступных вариантов, примерно так же, как это происходит в группе переключателей JRadioButton или выключателей JToggleButton. В отличие от групп кнопок, которые располагаются на экране все вместе, в раскрывающемся списке JComboBox виден только сам выбранный элемент, а список возможных альтернатив появляется, только когда этого захочет пользователь (щелкнув на специальной кнопке раскрытия списка). Список возможных альтернатив выводится в специальном всплывающем меню, которое после выбора скрывается. Таким образом раскрывающиеся списки (в отличие от групп элементов управления и обычных списков) позволяют экономить место в контейнере, даже если список альтернатив велик. Кроме того, раскрывающиеся списки допускают редактирование текущего элемента, и пользователь может не только выбрать что-то среди имеющихся альтернатив, но и ввести свое собственное значение. К тому же Swing автоматически делает работу с раскрывающимся списком весьма комфортной: список JComboBox обладает встроенной возможностью поиска элементов с клавиатуры, и как мы вскоре увидим, это значительно упрощает работу с большими списками.

В отличие от обычного списка JList, раскрывающийся список JComboBox вполне обходится услугами одной модели, поставляющей ему информацию об элементах списка; обязанности этой модели описаны в интерфейсе ComboBoxModel. На самом деле, вряд ли имело бы смысл использовать для раскрывающегося списка отдельную модель выделения — в любом случае в нем может быть только один выделенный элемент. Создатели Swing учли это и максимально упростили нам знакомство с моделью раскрывающегося списка ComboBoxModel: во-первых, эта модель унаследована от уже знакомой нам очень простой модели списка ListModel, во-вторых, в ней появилась лишь пара новых методов, предназначенных для смены выделенного элемента или его получения. Помимо интерфейса модели ComboBoxModel вы можете использовать унаследованный от нее интерфейс MutableComboBoxModel, который поддерживает вставку и удаление произвольных элементов списка.

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

//SimpleComboBoxes.java

//Создание простых раскрывающихся списков import javax.swing.*;

import java.util.*;

Списки

323

import java.awt.*;

public class SimpleComboBoxes extends JFrame { // массив с элементами списка

public String[] elements = new String[] { "Обаятельный", "Умный", "Нежный", "Сильный"

};

public SimpleComboBoxes() { super("SimpleComboBoxes"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//создадим пару раскрывающихся списков

JComboBox combo1 = new JComboBox(elements);

//задаем прототип элемента списка combo1.setPrototypeDisplayValue("Длинный элемент");

//второй раскрывающийся список

Vector<String> data = new Vector<String>(); for (int i=0; i<10; i++)

data.add("Элемент №: " + i); JComboBox combo2 = new JComboBox(data);

//сделаем его редактируемым combo2.setEditable(true); combo2.setMaximumRowCount(6);

//добавим списки и выведем окно на экран setLayout(new FlowLayout());

add(combo1);

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

}

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

new Runnable() {

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

}

}

В примере мы создаем небольшое окно и размещаем в его панели содержимого пару раскрывающихся списков. Нетрудно заметить очевидное сходство раскрывающегося списка JComboBox с обычным списком JList: точно так же, как это было для него, вы можете задавать элементы раскрывающегося списка в конструкторе JComboBox в виде массива или динамического массива (вектора) Vector. Первый список мы создаем на основе массива строк elements. Его нужно просто передать в конструктор, который незаметно для нас создаст на его основе стандартную модель. Заметьте, как мы изменяем для первого списка свойство prototypeDisplayValue. С его помощью список получает возможность

324

ГЛАВА 11

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

Второй раскрывающийся список демонстрирует работу с вектором Vector. Мы динамически наполняем вектор простыми строками, а затем передаем его в конструктор JComboBox. Во многих ситуациях, если вам не нравится модель, использование класса Vector — намного более гибкий способ быстро создать раскрывающийся список (впоследствии содержимое вектора гораздо проще изменить). Второй список мы делаем редактируемым, а также изменяем для него свойство maximumRowCount. Это свойство контролирует, сколько элементов будет одновременно выводиться во всплывающем меню списка. Если это значение меньше количества элементов в списке (а у нас так и есть: в списке десять элементов, а свойство мы устанавливаем равным шести), то список элементов во всплывающем меню автоматически включается в панель прокрутки.

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

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

Модель ComboBoxModel

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

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