Философия Java

Захват событий


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

Способ, которым это совершается в Swing, это ясно отделенный интерфейс (графические компоненты) и реализация (код, который вы хотите запустить при возникновении события от компоненты). Каждый компонент Swing может посылать все сообщения, которые могут в нем случатся, и он может посылать события каждого вида индивидуально. Так что если вам, например, не интересно было ли перемещение мыши над кнопкой, вы не регистрируете это событие. Это очень простой и элегантный способ обработки в событийном программировании, и как только вы поймете основы концепции, вы сможете легко использовать компоненты Swing, которые вы до этого не видели — фактически, эта модель простирается на все, что может быть классифицировано как JavaBean (который вы выучите позднее в этой главе).

Сначала мы сфокусируем внимание на основном, интересующем нас событии используемого компонента. В случае JButton, этим “интересующем событием” является нажатие кнопки. Для регистрации своей заинтересованности в нажатии кнопки вы вызываете метод addActionListener( ) класса JButton. Этот метод ожидает аргумент, являющийся объектом, реализующим интерфейс ActionListener, который содержит единственный метод, называемый actionPerformed( ). Таким образом, все, что вам нужно сделать для присоединения кода к JButton, это реализовать интерфейс ActionListener в классе и зарегистрировать объект этого класса в JButton через addActionListener( ). Метод будет вызван при нажатии кнопки (это обычно называется обратным вызовом).

Но что должно быть результатом нажатия кнопки? Нам хотелось бы увидеть какие-то изменения на экране, так что введем новый компонент Swing: JTextField. Это то место, где может быть напечатан текст или, в нашем случае, текст может быть изменен программой. Хотя есть несколько способов создания JTextField, самым простым является сообщение конструктору нужной вам ширину текстового поля. Как только JTextField помещается на форму, вы можете изменять содержимое, используя метод setText( ) (есть много других методов в JTextField, но вы должны посмотреть их в HTML документации для JDK на java.sun.com). Вот как это выглядит:

//: c13:Button2.java


// Ответ на нажатие кнопки.

// <applet code=Button2 width=200 height=75>

// </applet>

import javax.swing.*; import java.awt.event.*; import java.awt.*; import com.bruceeckel.swing.*;

public class Button2 extends JApplet { JButton b1 = new JButton("Button 1"), b2 = new JButton("Button 2"); JTextField txt = new JTextField(10); class BL implements ActionListener { public void actionPerformed(ActionEvent e){ String name = ((JButton)e.getSource()).getText(); txt.setText(name); } } BL al = new BL(); public void init() { b1.addActionListener(al); b2.addActionListener(al); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(b1); cp.add(b2); cp.add(txt); } public static void main(String[] args) { Console.run(new Button2(), 200, 75); } } ///:~

Создание JTextField и помещение его на канву - это шаги, необходимые для и для JButton или любого компонента Swing. Отличия приведенной выше программы в создании вышеупомянутого класса BL, являющегося ActionListener. Аргумент для actionPerformed( ) имеет тип ActionEvent, который содержит всю информацию о событии и откуда оно исходит. В этом случае я хочу описать кнопку, которая была нажата: getSource( ) производит объект, явившийся источником события, и я полагаю, что это JButton. getText( ) возвращает текст, который есть на кнопке, а он помещается в JTextField для демонстрации, что код действительно был вызван при нажатии кнопки.

В init( ) используется addActionListener( ) для регистрации объекта BL в обеих кнопках.

Часто более последовательно кодировать ActionListener как анонимный внутренний класс, особенно потому, что вы склонны использовать единственный интерфейс для каждого следящего класса. Button2.java может быть изменена для использования анонимного внутреннего класса следующим образом:

//: c13:Button2b.java

// Использование анонимного внутреннего класса.

// <applet code=Button2b width=200 height=75>

// </applet>

import javax.swing.*; import java.awt.event.*; import java.awt.*; import com.bruceeckel.swing.*;

public class Button2b extends JApplet { JButton b1 = new JButton("Button 1"), b2 = new JButton("Button 2"); JTextField txt = new JTextField(10); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e){ String name = ((JButton)e.getSource()).getText(); txt.setText(name); } }; public void init() { b1.addActionListener(al); b2.addActionListener(al); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(b1); cp.add(b2); cp.add(txt); } public static void main(String[] args) { Console.run(new Button2b(), 200, 75); } } ///:~

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


Содержание раздела