Иллюстрированный самоучитель по Java

Обработка событий

Методы обработки событий описаны в интерфейсах – слушателях (listener). Для каждого показанного на рис. 12.1 типа событий, кроме inputEvent (это событие редко используется самостоятельно), есть свой интерфейс. Имена интерфейсов составляются из имени события и слова Listener, например, ActionListener, MouseListener. Методы интерфейса "слушают", что происходит в потенциальном источнике события. При возникновении события эти методы автоматически выполняются, получая в качестве аргумента объект-событие и используя при обработке сведения о событии, содержащиеся в этом объекте.

Чтобы задать обработку события определенного типа, надо реализовать соответствующий интерфейс. Классы, реализующие такой интерфейс, классы-обработчики (handlers) события,, называются слушателями (listeners): они "слушают", что происходит в объекте, чтобы отследить возникновение события и обработать его.

Чтобы связаться с обработчиком события, классы-источники события должны получить ссылку на экземпляр eventHandier класса-обработчика события одним из методов addXxxListener(XxxEvent eventHandier), где Ххх – имя события.

Такой способ регистрации, при котором слушатель оставляет "визитную карточку" источнику для своего вызова при наступлении события, называется обратный вызов (callback). Им часто пользуются студенты, которые, звоня родителям и не желая платить за телефонный разговор, говорят: "Перезвони мне по такому-то номеру". Обратное действие – отказ от обработчика, прекращение прослушивания – выполняется методом removeXxxListener ().

Таким образом, компонент-источник, в котором произошло событие, не занимается его обработкой. Он обращается к экземпляру класса-слушателя, умеющего обрабатывать события, делегирует (delegate) ему полномочия по обработке.

Такая схема получила название схемы делегирования (delegation). Она удобна тем, что мы можем легко сменить класс-обработчик и обработать событие по-другому или назначить несколько обработчиков одного и того же события. С другой стороны, мы можем один обработчик назначить на прослушивание нескольких объектов-источников событий.

Эта схема кажется слишком сложной, но мы ей часто пользуемся в жизни. Допустим, мы решили оборудовать квартиру. Мы помещаем в нее, как в контейнер, разные компоненты: мебель, сантехнику, электронику, антиквариат. Мы предполагаем, что может произойти неприятное событие – квартиру посетят воры, – и хотим его обработать. Мы знаем, что классы-обработчики этого события – охранные агентства, – и обращаемся к некоторому экземпляру такого класса. Компоненты-источники события, т. е. те, которые могут быть украдены, присоединяют к себе датчики методом addXxxListener(). Затем экземпляр-обработчик "слушает", что происходит в объектах, к которым он подключен. Он реагирует на наступление только одного события – похищения прослушиваемого объекта, – прочие события, например, короткое замыкание или обрыв водопроводной трубы, его не интересуют. При наступлении "своего" события он действует по контракту, записанному в методе обработки.

Замечание
В JDK 1.0 была принята другая модель обработки событий. Не удивляйтесь, читая старые книги и просматривая исходные тексты старых программ, но и не пользуйтесь старой моделью
.

Приведем пример. Пусть в контейнер типа Frame помещено поле ввода tf типа TextField, не редактируемая область ввода ta типа TextArea и кнопка ь типа Button. В поле tf вводится строка, после нажатия клавиши Enter или щелчка кнопкой мыши по кнопке ь строка переносится в область ta. После этого можно снова вводить строку в поле tf и т. д.

Здесь и при нажатии клавиши Enter и при щелчке кнопкой мыши возникает событие класса ActionEvent, причем оно может произойти в двух компонентах-источниках: поле tf или кнопке ь. Обработка события в обоих случаях заключается в получении строки текста из поля tf (например, методом tf.getText()) и помещений ее в область ta (скажем, методом ta .append ()). Значит, можно написать один обработчик события ActionEvent, реализовав соответствующий интерфейс, который называется ActionListener. В этом Интерфейсе всего один метод actionPerformed().

Итак, пишем:

class TextMove implements ActionListener{
private TextField tf;
private TextArea ta;
TextMove(TextField tf, TextArea ta){
this.tf = tf; this.ta = ta;
}
public void actionPerformed(ActionEvent ae){
ta.append(tf.getText()+"\n");
}
}

Обработчик событий готов. При наступлении события типа ActionEvent будет создан экземпляр класса-обработчика TextMove, конструктор получит ссылки на конкретные поля объекта-источника, метод actionPerformed (), автоматически включившись в работу, перенесет текст из одного поля в другое.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.