Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование на Java часть 2

.pdf
Скачиваний:
135
Добавлен:
16.03.2016
Размер:
3.07 Mб
Скачать

JLabel label = new JLabel("Тестовый текст");

//добавление метки к фрейму fr.add(label);

//установка операции по нажатию на крестик fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//прорисовка фрейма

fr.setVisible(true);

}

}

public class Main {

public static void main(String[] args) { new MyFrame();

}

}

Данная программа компилируется и запускается так же, как и любое Java-приложение. В процессе работы программа отображает окно, показанное на рисунке 3.1.

Рисунок 3.1

Тема 3.5 Поддержка событий

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

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

71

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

Согласно модели делегирования, событие является объектом, описывающим изменения состояния источника. Событие может быть следствием действий пользователя с элементом графического интерфейса или сгенерировано программными средствами. Суперклассом всех событий является java.util.EventObject. Многие события объявлены в пакете java.awt.event, но некоторые содержатся в javax.swing.event.

Источник события – это объект, сгенерировавший его. Сгенерировав событие, источник должен передать его всем зарегистрированным обработчикам. Следовательно, чтобы обработчик получил событие, он должен быть зарегистрирован в источнике. Регистрация осуществляется путем вызова метода addТипListener(), принадлежащего источнику. Для каждого типа события определен собственный метод регистрации. Заголовок метода имеет вид, подобный представленному ниже.

public void addТипListener(ТипListener el)

где тип – это имя события, а параметр el представляет собой ссылку на обработчик события. Например, метод, регистрирующий обработчик событий клавиатуры, называется addKeyListener(). Для регистрации событий, связанных с перемещением мыши, используется метод addMouseMotionListener(). О возникшем событии оповещаются все обработчики.

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

public void removeТипListener(ТипListener el)

где тип – это имя события, а параметр el –ссылка на обработчик. Например, для того, чтобы удалить обработчик событий клавиатуры, надо вызвать метод removeKeyListener().

Методы, добавляющие или удаляющие обработчики, принадлежат объектам-источникам событий. Например, класс JButton содержит методы для регистрации отмены обработчика ActionListener. Будучи зарегистрированным, этот обработчик получает оповещение о действиях с кнопкой.

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

72

зарегистрирован в одном или нескольких источниках. Во-вторых, он должен реализовывать метод, предназначенный для обработки события.

Методы, позволяющие получать и обрабатывать события, определены в интерфейсах, содержащихся в пакетах java.awt.event, javax.swing.event и java.beans. Например, в интерфейсе ActionListener объявлен метод, который вызывается тогда, когда пользователь щелкает на кнопке или выполняет другое действие, затрагивающее компонент. Это событие может быть обработано любым объектом, при условии, что он реализует интерфейс

ActionListener.

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

Классы, представляющие события, лежат в основе механизма обработки события Java. Эти классы формируют иерархическую структуру, на вершине которой находится класс EventObject, принадлежащий пакету java.util. Он является суперклассом для всех событий. Класс AWTEvent, объявленный в пакете java.awt, представляет собой подкласс EventObject. Он, в свою очередь, является родительским классом для всех событий AWT, используемых в модели делегирования событий. Swing использует события AWT и, кроме того, определяет несколько дополнительных событий. Как упоминалось ранее, соответствующие классы определены в пакете javax.swing.event.

Втаблице 3.2 описаны некоторые классы событий и соответствующие им интерфейсы обработчиков, определенные в пакете java.awt.event.

Втаблице 3.3 приведено несколько классов событий и интерфейсов обработчиков из пакета javax.swing.event. Конкретные классы и интерфейсы будут подробно описываться по мере того, как они будут использоваться.

Таблица 3.2 Некоторые классы событий из пакета java.awt.event

Класс события

Описание

 

 

 

Обработчик

 

 

 

 

 

ActionEvent

Генерируется

 

при

ActionListener

 

выполнении

действий

с

 

 

интерфейсным

 

элементом,

 

 

например по щелчку на кнопке

 

AdjustmentEvent

Генерируется

 

при

AdjustmentListener

 

выполнении действий с полосой

 

 

прокрутки

 

 

 

 

FocusEvent

Генерируется

тогда,

когда

FocusListener

 

компонент получает или

теряет

 

 

фокус ввода

 

 

 

 

ItemEvent

Генерируется

при выборе

ItemListener

 

 

73

 

 

 

 

или отмене выбора элемента,

 

 

 

например, по щелчку на флажке

 

 

 

опций

 

 

 

 

 

 

 

KeyEvent

 

 

Генерируется

при

 

вводе

KeyListener

 

 

данных с клавиатуры

 

 

 

 

 

MouseEvent

 

 

Генерируется

 

 

при

MouseListener

и

 

перемещении

 

 

или

MouseMotionListener

 

перетаскивании мыши,

нажатии

 

 

 

или отпускании клавиши, а

 

 

 

также при

помещении

курсора

 

 

 

мыши на компонент или выводе

 

 

 

курсора за пределы компонента

 

 

MouseWheelEvent

 

 

Генерируется при движении

MouseWheelListener

 

 

колесика мыши

 

 

 

 

 

 

WindowEvent

 

 

Генерируется

 

 

при

WindowListener

 

 

активизации,

деактивизации,

 

 

 

закрытии, окна, сворачивании

 

 

 

его

в

пиктограмму

и

 

 

 

разворачивании из пиктограммы

 

 

Таблица 3.3 Некоторые классы событий из пакета javax.swing.event

 

Класс события

 

Описание

 

 

 

Обработчик

 

 

 

 

 

 

 

 

 

AncestorEvent

 

Генерируется

 

при

 

AncestorListener

 

 

 

 

добавлении,

перемещении

 

 

 

 

 

 

или

удалении

предка

 

 

 

 

 

 

компонента

 

 

 

 

 

 

GaretEvent

 

Генерируется

 

при

 

CaretListener

 

 

 

 

изменении позиции курсора

 

 

 

 

 

 

в текстовом компоненте

 

 

 

 

ChangeEvent

 

Генерируется

 

при

 

ChangeListener

 

 

 

 

изменении

состояния

 

 

 

 

 

 

компонента

 

 

 

 

 

 

HyperlinkEvent

 

Генерируется

 

при

 

HyperlinkListener

 

 

 

 

действиях с гипертекстовой

 

 

 

 

 

 

ссылкой

 

 

 

 

 

 

ListDataEvent

 

Генерируется

 

при

 

ListDataListener

 

 

 

 

изменении

содержимого

 

 

 

 

 

 

списка

 

 

 

 

 

 

 

ListSelectionEvent

 

Генерируется

 

при

 

ListSelectionListener

 

 

 

 

выборе или отмене выбора

 

 

 

 

 

 

пунктов списка

 

 

 

 

 

MenuEvent

 

Генерируется

 

при

 

MenuLxstener

 

 

 

 

выборе или отмене выбора

 

 

 

 

 

 

пунктов меню

 

 

 

 

 

 

 

 

 

 

74

 

 

 

 

 

TableModelEvent

Генерируется

при

TableModelListener

 

изменении модели таблицы

 

TreeExpansionEvent

Генерируется

при

TreeExpansionListener

 

разворачивании

или

 

 

сворачивании дерева

 

 

TreeModelEvent

Генерируется

при

TreeModelListener

 

изменении модели дерева

 

TreeSelectionEvent

Генерируется

при

TreeSelectionListener

 

выборе узла дерева

 

 

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

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

составе MouseMotionListener присутствуют два метода: mouseDragged() и mouseMoved (). Реализации этих методов, не выполняющие никаких действий, определены в классе MouseMotionAdapter. Если вас интересуют только события, связанные с перетаскиванием мыши, вам следует создать обработчик как подкласс MouseMotionAdapter и реализовать в нем метод mouseDragged(). Пустой метод mouseMoved(), унаследованный от суперкласса, будет обрабатывать события перемещения мыши.

Ниже перечислено несколько классов адаптеров. Большинство из них определено в пакете java.awt.event, однако класс MouseInputAdapter содержится в пакете javax.swing.event.

Таблица 3.4 Классы адаптеры

Класс адаптера

Реализуемый интерфейс

FocusAdapter

FocusListener

KeyAdapter

KeyListener

MouseAdapter

MouseListener

MouseMotionAdapter

MouseMotionListener

MouseInputAdapter

MouseListener и MouseMotionListener

WindowAdapter

WindowListener

 

75

Тема 3.6 Использование кнопок и обработка событий

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

JButton(String msg)

Параметр msg определяет строку, которая должна отображаться на кнопке.

По щелчку на кнопке генерируется событие ActionEvent. Для регистрации и отключения обработчиков данного события JButton предоставляет следующие методы (они унаследованы от класса

AbstractButton):

void addActionListener(ActionListener al) void removeActionListener(ActionListener al)

Здесь параметр al задает объект, который будет оповещаться о возникновении событий. Объект должен представлять собой экземпляр класса, реализующего интерфейс ActionListener.

В интерфейсе ActionListener определен только один метод: actionPerformed(). Объявление этого метода выглядит следующим образом:

void actionPerformed(ActionEvent ae)

Данный метод вызывается по щелчку на кнопке, т.е. он занимается обработкой событий, связанных с действиями пользователя с кнопкой. Реализуя метод actionPerformed(), необходимо позаботиться о том, чтобы он быстро выполнял свою задачу и возвращал управление. Как было сказано ранее, обработчики не должны выполнять длительных операций, поскольку это может привести к замедлению работы всего приложения. Если же обработка события предполагает действия, требующие длительного времени, их надо выполнять в потоке, специально создаваемом для этой цели.

Объект ActionEvent, передаваемый методу actionPerformed(), позволяет получить важную информацию, связанную с событием данного типа. В данном модуле мы будем использовать строку команды действия, связанной с кнопкой. По умолчанию в качестве команды действия принимается строка, отображаемая на кнопке. Для получения команды действия надо вызвать метод getActionCommand(), принадлежащий объекту события. Он объявляется следующим образом:

String getActionCommand()

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

76

Листинг 3.2

import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*;

public class MyFrame extends JFrame implements ActionListener { private JPanel panel;

private JLabel label1, label2; private JButton button1, button2;

private JTextField textField1, textField2; public MyFrame() {

//установка заголовка и размеров фрейма setTitle("Заголовок");

setBounds(700, 300, 200, 150); panel = new JPanel();

//создание всех компонент label1 = new JLabel("Метка 1"); label2 = new JLabel("Метка 2");

button1 = new JButton("Кнопка 1"); button2 = new JButton("Кнопка 2");

textField1 = new JTextField("Новый текст1", 10); textField2 = new JTextField("Новый текст2", 10);

//добавление компонент к панели panel.add(label1); panel.add(label2); panel.add(button1); panel.add(button2); panel.add(textField1); panel.add(textField2);

//добавление панели к фрейму add(panel);

//добавление кнопок к прослушиванию button1.addActionListener(this); button2.addActionListener(this);

//установка операции по нажатию на крестик setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//прорисовка фрейма

setVisible(true);

}

@Override

public void actionPerformed(ActionEvent e) {

//в метку 1 выводим текст из текстового поля 1 if (e.getActionCommand().equals("Кнопка 1")) {

label1.setText(textField1.getText());

}

//в метку 2 выводим текст из текстового поля 2

77

if (e.getActionCommand().equals("Кнопка 2")) { label2.setText(textField2.getText());

}

}

}

public class Main {

public static void main(String[] args) { new MyFrame();

}

}

На рисунке 3.2 показан фрейм до нажатия на кнопки, а на рисунке 3.3 – после.

Рисунок 3.2

Рисунок 3.3

Если элементов много,

то обрабатывать сабытия в одном методе не

очень удобно. В листинге 3.3 приведен пример того же класса, только обработка событий сделана с помощью неименованных внутренних классов.

Листинг 3.3

import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*;

public class MyFrame extends JFrame { private JPanel panel;

private JLabel label1, label2; private JButton button1, button2;

private JTextField textField1, textField2; public MyFrame() {

//установка заголовка и размеров фрейма setTitle("Заголовок");

setBounds(700, 300, 200, 150); panel = new JPanel();

//создание всех компонент label1 = new JLabel("Метка 1"); label2 = new JLabel("Метка 2");

button1 = new JButton("Кнопка 1");

78

button2 = new JButton("Кнопка 2");

textField1 = new JTextField("Новый текст1", 10); textField2 = new JTextField("Новый текст2", 10);

// добавление компонент к панели panel.add(label1); panel.add(label2); panel.add(button1); panel.add(button2); panel.add(textField1); panel.add(textField2);

//добавление панели к фрейму add(panel);

//добавление кнопок к прослушиванию button1.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) { label1.setText(textField1.getText());

}

});

button2.addActionListener(new ActionListener() { @Override

public void actionPerformed(ActionEvent e) { label2.setText(textField2.getText());

}

});

//установка операции по нажатию на крестик setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//прорисовка фрейма

setVisible(true);

}

}

Тема 3.7 Краткие сведения о диспетчерах компоновки

Расположение компонентов в составе контейнера определяется диспетчером компоновки, связанным с этим контейнером. Диспетчер можно отключить, написав setLayout(null), тогда позиционирование будет ручное, т.е. каждой компоненте нужно задать ее координаты и размеры. В Java определено несколько диспетчеров компоновки. Большинство из них входят в состав AWT (пакет java.awt), но Swing также предоставляет несколько дополнительных диспетчеров компоновки. Все диспетчеры являются экземплярами классов, реализующих интерфейс LayoutManager. В таблице

79

3.5 описано несколько диспетчеров компоновки, доступных программистам, использующим средства Swing.

Таблица 3.5 – Диспетчеры компоновки

Диспетчер

Описание

 

компоновки

 

 

FlowLayout

Располагает компоненты в строке слева направо;

 

следующая строка размещается под

предыдущей.

 

(Установки для некоторых стран предполагают

 

следование компонентов в строке справа налево.)

BorderLayout

Помещает компоненты в пяти областях,

 

расположенных по центру и по краям контейнера. По

 

умолчанию такой диспетчер компоновки связан с

 

панелью содержимого

 

GridLayout

Располагает компоненты в виде таблицы

GridBagLayout

Располагает компоненты в виде таблицы с

 

ячейками различных размеров

 

BoxLayout

Располагает компоненты по вертикали или по

 

горизонтали

 

SpringLayout

Использует при размещении

компонентов

 

специальные ограничения

 

До сих пор вам встречались два диспетчера: BorderLayout (который по умолчанию связан с панелью содержимого фрейма) и FlowLayout. Сейчас обратим более пристальное внимание на BorderLayout, поскольку именно он используется по умолчанию с панелью содержимого контейнера верхнего уровня.

Диспетчер BorderLayout определяет в составе контейнера пять областей, в которые могут помещаться компоненты. Первая область расположена по центру окна. Остальные четыре – по краям. Соответственно области называются центральной (center), северной (north), южной (south), восточной (east) и западной (wesf). По умолчанию компонент, помещаемый в панель содержимого, располагается в центральной области. Явным образом управлять размещением компонентов можно, используя специальную форму метода add().

void add(Component comp, Object loc)

где параметр comp задает компонент, добавляемый к панели, а параметр loc определяет область, в которую этот компонент будет помещен. Допустимо одно из следующих значений параметра loc:

BorderLayout.CENTERBorderLayout.NORTHBorderLayout.EAST

BorderLayout.SOUTHBorderLayout.WEST

Диспетчер компоновки BorderLayout наиболее удобен, если вы создаете объект JFrame, который должен содержать лишь один компонент (он

80