T.M. SoftStudio

feci quod potui, faciant meliora potentes

Купить полную версию курса "Введение в вычисления с Java" (русскоязычная версия, лекции, тесты, лабораторные работы)

Введение в вычисления с Java. Простое Event Driven программирование

Неделя 8

Лекция 33

Event Driven программирование

В лекции на этой неделе я дам вам краткое введение в управляемое событиями программирование и графический интерфейс пользователя или GUI.

Мы будем касаться только поверхности этих тем.

Введение обеспечит вам достаточный фон, чтобы вы смогли освоить более сложные понятия.

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

То есть, выполнение осуществляется либо шаг за шагом, или управление передается другой процедуре или методу, который опять будет выполнять действия шаг за шагом.

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

Давайте, используем пример для дополнительной иллюстрации, что это значит.

В этой программе, мы используем знакомые классы Canvas и ColorImage.

Программа просто пытается отобразить изображения happyface и tcpong на холсте.

Существует еще один метод, называемый moveHappyFace, который перемещает happyface изображение на новое место х, у.

Когда экземпляр класса EventDrivenDemo создается, изображение tcpong будет добавлено на холст с расположением 200, 200, и изображение HappyFace на место 0,0 по умолчанию, как показано здесь.

Пойдем в BlueJ, чтобы увидеть, как эта программа действительно работает.

Вы можете видеть, что это более или менее то же самое, что я только что показал.

Давайте скомпилируем программу и создадим экземпляр объекта.

Два изображения отображаются на холсте, как и ожидалось.

Скажем, если мы хотим, чтобы переместить happyface изображение на верхнюю часть фотографии так, чтобы она смотрелась еще счастливее, мы можем использовать метод moveHappyFace.

Но мы не знаем точно, куда двигаться.

Давайте попробуем 200х200, потому что это место фотографии.

Ну, это не совсем то, что я хочу, потому что это на самом деле изображение не накладывается на лицо.

Но тогда, если вы помните, мы можем на самом деле использовать мышь, чтобы перетащить изображение.

Так вот, мы можем перетащить счастливое лицо на вершину фотографии.

В общем, событийное программирование это парадигма программирования, в которой поток программы определяется событиями, такими как клик мыши, нажатие мыши, сообщениями из другой программы, или событиями сенсорного экрана.

Событийное программирование особенно полезно в графических интерфейсах пользователя.

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

Перетащить мышью, в этом случае, является событием, созданным пользователем.

Хотя, вы можете не знать об этом, программа на самом деле работает за сценой, отслеживая движение мыши при обновлении положения happyface изображения.

Этот вид графических интерфейсов позволяет выполнять такие задачи просто.

И мы собираемся узнать, как это можно сделать, в этой лекции.

В управляемом событиями программировании, программный код выполняется при активации событий.

Событие может быть типом сигнала для программы, что что-то случилось.

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

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

В Java, модель делегации событий используется для обработки событий.

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

Графический компонент называется источником события.

После того, как событие генерируется, событие передается или делегируется другому объекту, который может обработать событие.

Эти объекты называются слушателями событий или обработчиками событий.

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

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

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

Модель делегации событий состоит из трех основных компонентов, а именно источника событий, слушателя событий и объекта событий.

Диаграмма здесь показывает три компонента.

И я буду обсуждать каждый из них более подробно.

Источник события это источник, из которого происходит событие.

Источник события отвечает за предоставление информации о произошедшем событии для своих обработчиков событий или слушателей.

Например, мы можем создать холст, как источник события нажатия мыши.

Объект события содержит всю необходимую информацию, в том числе об источнике события и других данных, описывающих событие.

Например, событие нажатия мыши может включать X, Y координаты позиции мыши на холсте.

Приемник события, также известный как обработчик события, отвечает за генерацию ответов на событие.

Приемник событий ждет, пока не получает событие.

После того, как событие будет получено, слушатель запускает логику, определяющую как событие должно быть обработано.

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

Интерфейс

Позвольте мне отклониться немного в сторону, потому что слушатель событий является Java интерфейсом.

Рассмотрение интерфейса выходит за рамки этого курса, так что я обсужу тему очень кратко.

В основном, интерфейс является группой связанных методов с пустым содержимым.

И эти методы должны быть определены любым классом, который реализует этот интерфейс.

Объявление интерфейса производится с помощью ключевого слова interface. Это похоже на объявление класса, за исключением того, что методы объявлены без тел методов.

Он также не содержит никаких переменных экземпляра или статических переменных, за исключением того, что константы static final допускаются.

Вот пример, показывающий объявление для интерфейса ActionListener.

Как вы можете видеть, метод actionPerfomed объявлен с одним параметром типа ActionEvent, но тело метода отсутствует.

Обратите внимание, что нет даже пары фигурных скобок после метода.

Давайте рассмотрим другой пример интерфейса.

В этом примере, интерфейс Shape описывает функции, которые являются общими для всех форм.

Интерфейс определяет два абстрактных методов, а именно площади и периметра.

Эти методы должны вычислить свойства, общие для всех форм.

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

Здесь реализовано вычисление для прямоугольника.

Как вы можете видеть, что тело методов площади и периметра обеспечивает конкретный расчет.

В случае площади, вы просто умножаете ширину на высоту.

Когда вы вычисляете периметр, вы складываете ширину и высоту вместе, а затем умножаете на 2.

Аналогично, реализация для круга также представлена здесь.

В этом случае площадь круга вычисляется как пи на квадрат радиуса.

Аналогично также может быть реализация для других форм.

Механизм

Давайте вернемся к модели делегации событий и обсудим более детально, как работает этот механизм.

Предположим, у нас есть событие под названием Abc.

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

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

Класс AbcListener будет иметь один или несколько методов с именем типа AbcPerformed, формируемым из типа события и вида выполняемого действия, которое принимает AbcEvent объект в качестве параметра.

Метод должен реализовать логику, как это событие должно быть обработано.

Я вернусь к реализации этих методов позже.

Когда событие Abc происходит, такое как клик мыши или нажатие мыши, метод AbcPerformed будет вызываться классом AbcSource и посылать ему объект AbcEvent, который инкапсулирует всю необходимую информацию об активации.

Например, (х, у) положение курсора мыши, введенный текст, и так далее.

Все слушатели, заинтересованные в событии, должны реализовать прослушиватель событий.

Класс Event Listener представляет собой интерфейс Java, который содержит набор методов, которые будут реализованы.

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

Таким образом, слушатели могут реагировать на эти события должным образом.

В этом примере, прослушиватель события или обработчик называется MyListener и заинтересован в событии Abc. Он должен реализовать интерфейс AbcListener, который содержит метод, называемый AbcPerformed.

Класс MyListener должен обеспечить реализацию внутри определения класса для метода AbcPerformed.

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

В этом примере, имя прослушивателя событий, который мы собираемся использовать это MyListener.

И мы заинтересованы в событии MouseEvent, в частности, в mouseClicked.

Поэтому интерфейс, который мы собираемся реализовать это MouseListener.

Обратите внимание, что мы должны импортировать MouseListener и класс MouseEvent из пакета java.awt.event.

Остальные два выражения импорта для классов Canvas и ColorImage, которые мы использовали много-много раз.

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

В частности, мы заинтересованы в щелчке мыши и есть метод в интерфейсе MouseListener называемый mouseClicked.

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

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

И реализация того, как это событие mouseClicked предполагается быть обработанным, определена в этой программе.

То, что мы пытаемся сделать здесь, это просто попробовать отобразить happyFace изображение на холсте в месте, где произошел щелчок мыши.

Таким образом, мы сначала открываем happyFace изображение.

Расположение клика мыши можно получить из объекта события е с помощью e.getX и e.getY.

Остальная часть выражения image.getWidth/2 и image.getHeight/2 только пытается произвести регулировку положения, так что изображение отображается в центре, где мышь щелкнула, а не в углу.

После того как нужное место получено, изображение отображается на холсте.

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

В случае интерфейса MouseListener, существует четыре другие методы, в дополнение к mouseClicked, а именно mousePressed и mouseReleased, фактически комбинированное действие mousePressed и mouseReleased приведет к щелчку мыши, методы mouseEntered и mouseExited указывают, находится ли мышь в пределах или за пределами области источника событий, в данном случае, на холсте.