Архитектура визуального применения Windows. Принципы событийно - ориентированного программирования




На данном этапе осуществляется переход к наиболее важным элементам Swing – работе с событиями и реакции на взаимодействия с UI. Swing обрабатывает события, используя модель событие / слушатель. Эта модель работает путем разрешения некоторым классам регистрироваться на события от компонента. Такой класс называется слушателем (Listener), поскольку он ждет возникновения событий в компоненте и выполняет действия при их возникновении. Компонент сам знает, как «активировать» событие (то есть, он знает типы взаимодействий, которые может генерировать, и как дать слушателям знать, когда происходят эти взаимодействия). Он передает это взаимодействие при помощи событий (event), классов, содержащих информацию о взаимодействии.

Обработка любого события (нажатие кнопки, щелчок мышью и так далее) состоит в связывании события с методом, его обрабатывающим. Принцип обработки событий, начиная с Java 2, базируется на модели делегирования событий. В этой модели имеется блок прослушивания события (EventListener), который ждет поступления события определенного типа от источника, после чего обрабатывает его и возвращает управление. Источник – это объект, который генерирует событие, если изменяется его внутреннее состояние, например, изменился размер, изменилось значение поля, произведен щелчок мыши по форме или выбор значения из списка. После генерации объект-событие пересылается для обработки зарегистрированному в источнике блоку прослушивания как параметр его методов – обработчиков событий.

Блоки прослушивания Listener представляют собой объекты классов, реализующих интерфейсы прослушивания событий, определенных в пакете java.awt.event. Соответствующие методы, объявленные в используемых интерфейсах, необходимо явно реализовать при создании собственных классов прослушивания. Эти методы и являются обработчиками события. Передаваемый источником блоку прослушивания объект-событие является аргументом обработчика события. Объект класса – блока прослушивания события необходимо зарегистрировать в источнике методом:

источник.addСобытиеListener(объект_прослушиватель);

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

источник.removeСобытиеListener();

Источником событий могут являться элементы управления: кнопки (JButton, JCheckbox, JRadioButton), списки, кнопки-меню. События могут генерироваться фреймами и апплетами, как mouse- и key- события. События генерируются окнами при развертке, сворачивании, выходе из окна. Каждый класс-источник определяет один или несколько методов addСобытиеListener() или наследует эти методы

Когда событие происходит, все зарегистрированные блоки прослушивания уведомляются и принимают копию объекта события. Таким образом, источник вызывает метод-обработчик события, определенный в классе, являющемся блоком прослушивания, и передает методу объект события в качестве параметра. В качестве блоков прослушивания на практике используются внутренние классы. В этом случае в методе, регистрирующем блок прослушивания в качестве параметра, используется объект этого внутреннего класса.

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

Рассмотрим простейший пример – кнопка JButton и вывод сообщений «Hello» на консоль при ее нажатии.

JButton знает, когда на нее нажимают; это обрабатывается внутри компонента, код для обработки этого не нужен. Однако слушатель должен зарегистрироваться для получения этого события от JButton, для того чтобы вы могли вывести сообщение «Hello». Класс listener делает это, реализуя интерфейс listener и вызывая метод addActionListener() компонента JButton:

// Создать JButton

JButton b = new JButton("Button");

// Зарегистрировать слушателя

b.addActionListener(new HelloListener());

class HelloListener implements ActionListener {

// Метод интерфейса для получения нажатий кнопки

public void actionPerformed(ActionEvent e) {

System.out.println("Hello");

}

}

Компонент JList работает аналогично. Когда кто-то выбирает что-то в JList, вы выводите на консоли сообщение о выбранном объекте:

// myList - это JList, заполненный данными

myList.addListSelectionListener(new ListSelectionListener() {

public void valueChanged(ListSelectionEvent e) {

Object o = myList.getSelectedItem();

System.out.println(o.toString());

}

});

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

 

Модели

Ранее был рассмотрен материал о Java Collections (коллекциях языка Java), наборе Java-классов, обрабатывающих данные. К этим классам относятся ArrayList, HashMap и Set. Большинство приложений использует эти классы повсюду при перемещении данных назад и вперед. Однако при необходимости использования этих данных в UI возникает одно ограничение. UI не знает, как их отображать. Если у вас есть JList и ArrayList некоторых объектов данных (например, объектов Person), как JList узнает, что отображать? Должен ли он отображать только фамилию, или фамилию и имя вместе?

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

· JComboBox требует от своей модели описания текста для отображения в виде вариантов выбора и количества существующих вариантов.

· JSpinner требует от своей модели описания текста для отображения, а также описания предыдущего и следующего вариантов.

· JList тоже требует от своей модели описания текста для отображения как вариантов выбора и количества существующих вариантов.

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

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



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-06-11 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: