Назад Зміст Вперед

11.8 Технологія Listeners. Варіанти реалізації інтерфейсу ActionListener

Обробка будь-якої події (натискання кнопки, клацання мишею і ін.) полягає в зв'язуванні події з методом, його обробляють. Принцип обробки подій, починаючи з Java 2, базується на моделі делегування подій. У цій моделі є блок прослуховування події (EventListener), який чекає надходження події певного типу від джерела, після чого обробляє його і повертає управління. Джерело - це об'єкт, який генерує подію, якщо змінюється його внутрішній стан, наприклад, змінився розмір, змінилося значення поля, клацнули миші по формі або вибрали значення зі списку. Після генерації об'єкт-подія пересилається для обробки зареєстрованому в джерелі блоку прослуховування як параметр його методів - обробників подій.

Блоки прослуховування Listener є об'єктами класів, що реалізують інтерфейси прослуховування подій, визначених в пакеті java.awt.event. Відповідні методи, оголошені в використовуваних інтерфейсах, необхідно явно реалізувати при створенні власних класів прослуховування. Ці методи і є обработчиками події. Рухаючись джерелом блоку прослуховування, об'єкт-подія є аргументом обробника події. Об'єкт класу - блоку прослуховування події необхідно зареєструвати в джерелі методом джерело.addПодіяListener (об'єкт_прослуховувач);

Після цього об'єкт-прослуховувач (Listener) буде реагувати саме на цю подію і викликати метод «обробник події». Така логіка обробки подій дозволяє легко відокремити інтерфейсну частину додатка від функціональної, що вважається необхідним при проектуванні сучасних додатків. Видалити слухача певної події можна за допомогою методу removeПодіяListener ().

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

Коли подія відбувається, всі зареєстровані блоки прослуховування повідомляються і приймають копію об'єкта події. Таким чином, джерело викликає метод-обробник події, визначений у класі, що є блоком прослуховування, і передає методу об'єкт події як параметр. Як блоки прослуховування на практиці використовуються внутрішні класи. У цьому випадку в методі, що реєструє блок прослуховування в якості параметра, використовується об'єкт цього внутрішнього класу.

Кожен інтерфейс, що включається в блок прослуховування, успадковується від інтерфейсу EventListener і призначений для обробки певного типу подій. При цьому він містить один або кілька методів, які завжди беруть об'єкт події в якості єдиного параметра і викликаються в певних ситуаціях. У таблиці наведено деякі інтерфейси і їхні методи, які повинні бути реалізовані в класі прослуховування подій, що реалізує відповідний інтерфейс:
Інтерфейси
Обробники подій
ActionListener
actionPerformed(ActionEvent e)
AdjustmentListener
adjustmentValueChanged(
AdjustmentEvent e)
ComponentListener
componentResized(
ComponentEvent e)
componentMoved(ComponentEvent e)
componentShown(ComponentEvent e)
componentHidden(ComponentEvent e)
ContainerListener
componentAdded(ContainerEvent e)
componentRemoved(
ContainerEvent e)
FocusListener
focusGained(FocusEvent e)
focusLost(FocusEvent e)
ItemListener
itemStateChanged(ItemEvent e)
KeyListener
keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
MouseListener
mouseClicked(MouseEvent e)
mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
mouseEntered(MouseEvent e)
mouseExited(MouseEvent e)
MouseMotionListener
mouseDragged(MouseEvent e)
mouseMoved(MouseEvent e)
TextListener
textValueChanged(TextEvent e)
WindowListener
windowOpened(WindowEvent e)
windowClosing(WindowEvent e)
windowClosed(WindowEvent e)
windowIconified(WindowEvent e)
windowDeiconified(WindowEvent e)
windowActivated(WindowEvent e)

Подія, яка генерується в разі виникнення певної ситуації і потім передається зареєстрованому блоку прослуховування для обробки - це об'єкт класу подій. У корені ієрархії класів подій знаходиться суперклас EventObject з пакета java.util. Цей клас містить два методи: getSource (), який повертає джерело подій, і toString (), який повертає рядковий еквівалент події. Абстрактний клас AWTEvent з пакета java.awt є суперкласом всіх AWT-подій, пов'язаних з компонентами. Метод getID () визначає тип події, що виникає внаслідок дій користувача в візуальному додатку. Нижче наведені деякі з класів подій, похідних від AWTEvent, і розташовані в пакеті java.awt.event:
ActionEvent – генерується: при натисканні кнопки; подвійне клацання клавішею миші по елементах списку; при виборі пункту меню;
AdjustmentEvent – генерується при зміні смуги прокрутки;
ComponentEvent – генерується, якщо компонент прихований, переміщений, змінений в розмірі або стає видимим;
FocusEvent – генерується, якщо компонент отримує або втрачає фокус введення;
TextEvent – генерується при зміні текстового поля;
ItemEvent – генерується при виборі елемента зі списку.
Клас InputEvent є абстрактним суперкласом подій введення (для клавіатури та миші). Події вводу з клавіатури обробляє клас KeyEvent, події миші – MouseEvent.
Щоб реалізувати методи-обробники подій, пов'язаних з клавіатурою, необхідно визначити три методи, оголошені в інтерфейсі KeyListener. При натисканні клавіші генерується подія зі значенням KEY_PRESSED. Це призводить до запиту обробника подій keyPressed (). Коли клавіша відпускається, генерується подія зі значенням KEY_RELEASED і виконується оброблювач keyReleased (). Якщо натисканням клавіші згенерований символ, то надсилається повідомлення про подію зі значенням KEY_TYPED і викликається обробник keyTyped ().

Для реєстрації події додаток-джерело зі свого об'єкта треба викликати метод addКеуListener (KeyListener el), який реєструє блок прослуховування цієї події. Тут el - посилання на блок прослуховування події.
/* приклад# 1 : обробка подій клавіатури: MyKey.java */
package chapt12;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JApplet;
public class MyKey extends JApplet {
private String msg = " ";
private int x = 0, y = 20; // координати виводу
private class AppletKeyListener
implements KeyListener {
// реалізація всіх трьох методів інтерфейсу KeyListener
public void keyPressed(KeyEvent e) {
showStatus("Key Down");
} // відображення в рядку стану
public void keyReleased(KeyEvent e) {
showStatus("Key Up");
} // відображення в рядку стану
public void keyTyped(KeyEvent e) {
msg += e.getKeyChar();
repaint(); // перемалювати
}
}
public void init() {
/* реєстрація блоку прослуховування */
addKeyListener(new AppletKeyListener());
requestFocus(); // запит фокусу введення
}
public void paint(Graphics g) {
// значення клавіші в позиції виведення
g.drawString(msg, x, y);
}
}
clip_image002
Рис. 12.1. Результат натискання клавіші відображення в рядку стану
Коди спеціальних клавіш (переміщення курсору, функціональних клавіш) недоступні через keyTyped (), для обробки натискання цих клавіш використовується метод keyPressed ().

Як блок прослуховування в методі init () зареєстрований внутрішній класс AppletKeyListener. Потім в блоці прослуховування реалізовані всі три методи обробки події, оголошені в інтерфейсі KeyListener.

У наступному апплететі перевіряється приналежність прямокутника координат натискання клавіші миші за допомогою реалізації інтерфейсу MouseListener і події MouseEvent.
/* приклад # 2 :події натискання клавіші миші: MyRect.java */
package chapt12;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyRect extends JApplet {
private Rectangle rect =
new Rectangle(20, 20, 100, 60);
private class AppletMouseListener //блок обробки подій
implements MouseListener {
/* реалізація всіх п'яти методів інтерфейсу MouseListener */
public void mouseClicked(MouseEvent me) {
int x = me.getX();
int y = me.getY();
if (rect.contains(x, y)) {
showStatus("клік в синьому прямокутнику");
else {
showStatus("клік в білому тлі");
}
}
// реалізація інших методів інтерфейсу порожня
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
public void init() {
setBackground(Color.WHITE);
/ * Реєстрація блоку прослуховування * /
addMouseListener(new AppletMouseListener());
}
public void paint(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(rect.x, rect.y,
rect.width, rect.height);
}
}


Рис. 12.2Результат натискання кнопки відображено в рядку стану
Спосіб обробки подій в компонентах Swing - це інтерфейс (графічні компоненти) і реалізація (код обробника події, який запускається при виникненні події). Кожна подія містить повідомлення, яке може бути оброблено в розділі реалізації.

При використанні компонента JButton визначається подія, пов'язана з натисканням кнопки. Для реєстрації зацікавленості блоку прослуховування в цю подію викликається метод addActionListener () об'єктом класу JButton. Інтерфейс ActionListener містить єдиний метод actionPerformed (), який потрібно реалізувати в блоці обробки відповідно до поставленого завданням: витягти числа з двох текстових полів, додати їх і помістити результат в мітку.
/ * Приклад # 3: реєстрація, генерація і обробка ActionEvent: SimpleButtonAction.java */
package chapt12;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleButtonAction extends JApplet {
private JButton additionBtn = new JButton("Додати");
private JTextField txtField1 = new JTextField(3);
private JTextField txtField2 = new JTextField(3);
private JLabel answer = new JLabel();
private class ButtonListener
implements ActionListener {
// Реалізація класу-обробника події
public void actionPerformed(ActionEvent ev) {
try {
int t1, t2;
t1 = Integer.parseInt(txtField1.getText());
t2 = Integer.parseInt(txtField2.getText());
answer.setText("Відповідь: " + (t1 + t2));
showStatus("Виконано успішно!");
catch (NumberFormatException e) {
showStatus("Помилка вводу!");
}
/*  String s1, s2; витяг напису на кнопці з події  s1 = ((JButton)ev.getSource()).getText(); */
//витяг команди з події  s2 = ev.getActionCommand();
/* витяг з події об'єкта, асоційованого з кнопкою if (ev.getSource() == additionBtn)
застосовується якщо обробляються події кількох кнопок одним обробником
*/
}
}
public void init() {
Container c = getContentPane();
setLayout(new FlowLayout()); /* «плаваюче» розміщення компонентів*/
c.add(txtField1);
c.add(txtField2);
// Реєстрація блоку прослуховування події
additionBtn.addActionListener(
new ButtonListener());
c.add(additionBtn);
c.add(answer);
}
}
Рис. 12.3Обробка події кнопки
При створенні кнопки викликається конструктор JButton з рядком, яку потрібно помістити на кнопці. JButton - це компонент, який автоматично дбає про свою перемальовуванні. Розміщення кнопки на формі зазвичай проводиться всередині метода init () викликом методу add () класу Container.
.