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

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

30

ГЛАВА 2

вести к нажатию кнопки). Источником события (event source) в Swing может быть любой компонент, будь то кнопка, надпись с текстом или диалоговое окно. Для того чтобы узнавать в своей программе о происходящих в компоненте событиях, нам необходимо сообщить компоненту о своей заинтересованности. Сделать это можно, передав компоненту слушателя (listener) определенного события. Слушатель — этот тот самый наблюдатель (разница только в названиях), которому компонент будет сообщать о происходящих в нем событиях.

Каждому типу события соответствует свой слушатель. Так гораздо проще следить именно за теми событиями, что нас интересуют, а не за всеми подряд — код, обрабатывающий щелчки мыши, будет отделен от кода, ответственного за нажатия клавиш. Обязанности слушателей (то есть методы, которые в них должны быть определены) описаны в соответствующих интерфейсах. Вы реализуете в своем классе нужный вам интерфейс слушателя, передаете его в интересующий вас компонент и спокойно ждете наступления события. Давайте рассмотрим простой пример, в котором мы попытаемся узнать о нажатиях клавиш при активном окне.

//FirstEvents.java

//События - нажатия клавиш на клавиатуре import javax.swing.*;

import java.awt.event.*;

public class FirstEvents extends JFrame { public FirstEvents() {

super("FirstEvents");

//при закрытии окна - выход setDefaultCloseOperation(EXIT_ON_CLOSE);

//регистрируем нашего слушателя addKeyListener(new KeyL());

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

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

}

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

new Runnable() {

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

}

}

// этот класс будет получать извещения о событиях class KeyL implements KeyListener {

// печать символа

public void keyTyped(KeyEvent k) { System.out.println(k);

}

// нажатие клавиши

Модель событий

31

public void keyPressed(KeyEvent k) { System.out.println(k);

}

// отпускание нажатой клавиши

public void keyReleased(KeyEvent k) { System.out.println(k);

}

}

Пример очень прост — мы создаем класс, унаследованный от окна JFrame, устанавливаем для него размер методом setSize(), указываем, что при закрытии окна следует завершить работу приложения (методом setDefaultCloseOperation(), подробнее об этом методе мы узнаем в главе 4, посвященной окнам) и выводим окно на экран. Правда сам запуск приложения происходит через некий таинственный класс SwingUtilities, однако такова архитектура Swing. Очень скоро мы узнаем, почему не стоит вызывать конструктор окна напрямую, а сейчас гораздо интереснее посмотреть, как создается слушатель события.

Прежде всего, необходимо написать класс, реализующий интерфейс слушателя. Если вы просмотрите интерактивную документацию Java, то увидите, что для получения информации о нажатиях клавиш используется интерфейс KeyListener, именно его мы и реализовали в классе KeyL. В этом интерфейсе определены три метода, каждый из которых вызывается при наступлении определенного события: keyPressed() и keyReleased() — при нажатии и отпускании клавиши, keyTyped() — при печати символа (когда нажимается и отпускается клавиша, соответствующая печатному символу1). В качестве параметра каждому методу передается объект KeyEvent, который используется для получения дополнительной информации о событии (кода клавиши, источника события и т. д.). Чтобы сделать программу максимально простой, мы просто передаем эту информацию в стандартный поток вывода.

Последний этап — регистрация нашего слушателя в интересующем нас компоненте. Компонент у нас в программе только один — это наше окно. Для регистрации слушателя событий от клавиатуры мы вызываем метод addKeyListener(), в который передаем ссылку на объект класса KeyL. После этого остается только запустить программу

ипосмотреть, какие сообщения она выводит в стандартный поток вывода при нажатиях клавиш (конечно, события от нажатий клавиш будут возникать только при активном окне).

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

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

1 Метод keyTyped() — более высокого уровня, чем остальные два слушателя KeyListener. Он сообщает программе, что пользователь нажал и отпустил или удерживает клавишу с печатным символом (печатные символы — это все буквы, цифры, а также пробел и клавиши Enter и Esc), однако эти печатные символы могут не иметь точного отображения на одну клавишу клавиатуры, в то время как другие два метода сообщают именно о нажатии физических клавиш.

32

ГЛАВА 2

Схема именования событий JavaBeans

Система обработки событий в Swing является частью архитектуры JavaBeans, которая позволяет создавать переносимые и легко используемые графические компоненты для визуальных средств разработки программ. В главе 1 мы узнали, что все компоненты Swing являются компонентами JavaBeans. Как вы помните, основой JavaBeans является соглашение об именах, которое позволяет визуальным средствам легко узнавать, какими свойствами обладает компонент. Для этого компонент определяет набор методов со специальными именами get/set. Методы эти служат для считывания и записи значений свойств компонента.

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

У каждого события есть имя. Например, в примере из предыдущего раздела этим именем было слово «Key» (клавиша) — неудивительно, ведь это событие происходит при нажатии клавиш на клавиатуре. События, которые происходят в окнах, называются «Window» (окно); в общем случае будем считать, что названием события являются просто символы «XXX». Чтобы событие стало доступно визуальному средству разработки, необходимо проделать описанную ниже процедуру.

1.Определить класс, в котором будет храниться информация о произошедшем событии (что это будет за информация, определяет создатель события). Класс должен быть унаследован от базового класса java.util.EventObject и иметь название вида XXXEvent, где «XXX» — это название нашего события. В предыдущем примере мы видели, что информация о событиях от клавиатуры хранилась в классе с названием KeyEvent.

2.Создать интерфейс слушателя, в который будет приходить информация о событии. Это должен быть именно интерфейс, а не класс. Название интерфейса должно иметь следующий вид: XXXListener — в предыдущем примере мы использовали слушателя с именем KeyListener. Этот интерфейс должен быть унаследован от базового интерфейса всех слушателей событий java.util.EventListener (это пустой интерфейс без методов, он просто помечает то, что унаследованный от него интерфейс является слушателем). В интерфейсе может быть определено сколь угодно много методов, единственное требование к этим методам — наличие параметра типа XXXEvent. Никаких других параметров у методов быть не должно.

3.Включить поддержку события в класс компонента, в котором это событие может происходить. Чтобы сделать это, необходимо определить два метода: один для присоединения слушателей, другой для их отсоединения. Названия методов должны выглядеть следующим образом: addXXXListener() — для метода, присоединяющего слушателей, и removeXXXListener() — для метода, отсоединяющего слушателей. Если вспомнить пример, то там присоединение слушателя происходило как раз с помощью метода addKeyListener(), определенного в классе окон JFrame (на самом деле этот метод определен в базовом классе всех компонентов Component, и добавлять слушателей клавиатуры можно к любому компоненту).

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

Модель событий

33

мечали, насколько JavaBeans упрощает создание компонентов. Сейчас для нас гораздо важнее то, что, зная правила, по которым создаются события JavaBeans (а компоненты Swing используют именно эти события), мы можем очень просто определить всю интересующую информацию о событии, не перерывая документацию. Предположим, нам захотелось узнать, что происходит в окне нашего приложения. Скорее всего, события, происходящие в окнах, описаны в классе WindowEvent. Если это так, то согласно схеме именования нам нужно реализовать интерфейс WindowListener и зарегистрировать его в нашем окне с помощью метода addWindowListener(). Как оказывается, именно такие классы и интерфейсы позволяют обрабатывать оконные события, и, хотя мы не знали об этом, а просто предполагали, наши предположения полностью подтвердились!

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

Стандартные события

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

Надо сказать, что события в Java условно разделяются на низкоуровневые (low-level events) и высокоуровневые (high-level events). К низкоуровневым событиям относят те, что происходят непосредственно в результате действий пользователя: это движения мыши, передача фокуса ввода от одного приложения другому, нажатия клавиш и т. п.2 Они поступают в Java-программу от операционной системы или от внутренних механизмов виртуальной машины. Высокоуровневые события происходят в результате изменения состояния компонента. Такие события поступают не от операционной системы, а создаются самим компонентом. Процесс создания события еще называют запуском (fire). Во многих компонентах Swing вы можете увидеть методы с именами вида fireXXX(); именно в таких методах создаются объекты с информацией о событиях, которые затем рассылаются слушателям. Часто события высокого уровня возникают после того, как происходят несколько событий низкого уровня (например, кнопка сообщает о своем нажатии, после того как над ней была нажата и отпущена кнопка мыши).

Начнем мы с низкоуровневых событий (табл. 2.1). Эти события могут возникать в любом графическом компоненте, унаследованном от класса java.awt.Component (правда, есть несколько исключений).

Таблица 2.1. Основные низкоуровневые события

Краткое описание события

Методы слушателя

Источник события

Событие от клавиатуры.

keyPressed(KeyEvent),

Все компоненты (на-

Описано в классе KeyEvent.

keyReleased(KeyEvent),

следники класса java.

Возникает, когда пользователь

keyTyped(KeyEvent)

awt.Component)

нажимает клавишу

 

 

2 Низкоуровневые события легко отличить от высокоуровневых — все они унаследованы от особого базового класса AWTEvent.

34

 

ГЛАВА 2

Таблица 2.1 (продолжение)

 

 

 

 

 

Краткое описание события

Методы слушателя

Источник события

Нажатия и отпускания кнопок

mouseClicked(MouseEvent),

Все компоненты

мыши и попадание курсора

mouseEntered(MouseEvent),

 

в область компонента. Класс

mouseExited(MouseEvent),

 

MouseEvent позволяет следить

mousePressed(MouseEvent),

 

за состоянием кнопок мыши

mouseReleased(MouseEvent)

 

и контролировать нахождение

 

 

указателя мыши в определен-

 

 

ной области

 

 

Перемещение мыши. Класс

mouseDragged(MouseEvent),

Все компоненты

события тот же — Mouse-

mouseMoved(MouseEvent)

 

Event, но вот слушатель

 

 

называется по-другому —

 

 

MouseMotionListener3

 

 

Прокрутка колесика мыши.

mouseWheelMoved(MouseWheelEvent)

Все компоненты

Класс MouseWheelEvent

 

 

Передача фокуса ввода. Класс

focusGained(FocusEvent),

Все компоненты

FocusEvent

focusLost(FocusEvent)

 

Добавление или удаление

componentAdded(ContainerEvent),

Все контейнеры (на-

компонентов в контейнере.

componentRemoved(ContainerEvent)

следники класса java.

Класс ContainerEvent

 

awt.Container)

Изменения состояния окна.

windowActivated(WindowEvent),

Окна (наследники

Класс WindowEvent. Позволяет

windowClosed(WindowEvent),

класса java.awt.

узнать о перемещении, сверты-

windowClosing(WindowEvent),

Window), напри-

вании, закрытии окна и т. д.

windowDeactivated(WindowEvent),

мер, окна с рамкой

 

windowDeiconified(WindowEvent),

(JFrame) или диало-

 

windowIconified(WindowEvent),

говые окна (JDialog)

 

windowOpened(WindowEvent)

 

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

Чтобы окончательно убедиться в том, что события эти на самом деле возникают,

икомпоненты сообщают о них слушателям, рассмотрим небольшой пример:

//LowLevelEvents.java

//Наблюдение за основными низкоуровневыми событиями import javax.swing.*;

import java.awt.event.*; import java.awt.*;

3 Это единственное исключение из правила именования событий JavaBeans. По идее, для класса MouseEvent слушатель должен был бы называться MouseListener (как в предыдущей строке таблицы), но разработчики решили разбить этот слушатель на два.

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