Прослушиватели событий

Flash Player 9 и более поздних версий, Adobe AIR 1.0 и более поздних версий

Прослушиватели событий, которых называют также обработчиками событий — это функции, выполняемые Flash Player и AIR в ответ на конкретные события. Добавление прослушивателя событий происходит в два этапа. Во-первых, создается метод функции или класса для Flash Player или AIR, который выполняется в ответ на появление события. Иногда он называется функцией прослушивателя или функцией обработчика событий. Во-вторых, необходимо использовать метод addEventListener() , чтобы зарегистрировать свою функцию прослушивателя в цели события или любом объекте из списка отображения, который находится в соответствующем потоке событий.

Создание функции прослушивателя

Создание функций прослушивателя — это область, где модель событий ActionScript 3.0 отличается от модели событий DOM. В модели событий DOM существует четкое различие между прослушивателем событий и функцией прослушивателя. Прослушиватель событий является экземпляром класса, реализующего интерфейс EventListener, тогда как функция прослушивателя является методом этого класса с именем handleEvent() . В модели событий DOM регистрируется экземпляр класса, содержащий функцию прослушивателя, а не фактическая функция прослушивателя.

В модели событий ActionScript 3.0 прослушиватель события не отличается от функции прослушивателя. ActionScript 3.0 лишен интерфейса EventListener, а функции прослушивателя могут быть определены вне класса или его части. Более того, функции прослушивателя не обязательно называются handleEvent() : в качестве имени может выступать любой действительный идентификатор. В ActionScript 3.0 регистрируется имя фактической функции прослушивателя.

Функция прослушивателя определена вне класса

Следующий код создает простой SWF-файл, который показывает на экране красный квадрат. Функция прослушивателя с именем clickHandler() , которая не принадлежит какому-либо классу, регистрирует события щелчка мыши по красному квадрату.

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, clickHandler); 
    } 
} 
 
function clickHandler(event:MouseEvent):void 
{ 
    trace("clickHandler detected an event of type: " + event.type); 
    trace("the this keyword refers to: " + this); 
}

Когда пользователь взаимодействует с итоговым SWF-файлом, щелкая по квадрату, Flash Player или AIR генерирует следующий вывод трассировки:

clickHandler detected an event of type: click 
the this keyword refers to: [object global]

Учтите, что объект события передается в качестве аргумента методу clickHandler() . Это позволяет функции прослушивателя изучить объект события. В данном примере свойство type используется, чтобы проверить, что событие является событием щелчка.

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

Функция прослушивателя, определенная в качестве метода класса

Следующий пример идентичен предыдущему примеру, определяющему класс ClickExample, за исключением того, что функция clickHandler() определена как метод класса ChildSprite:

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, clickHandler); 
    } 
    private function clickHandler(event:MouseEvent):void 
    { 
        trace("clickHandler detected an event of type: " + event.type); 
        trace("the this keyword refers to: " + this); 
    } 
}

Когда пользователь взаимодействует c итоговым SWF-файлом путем нажатия на красный квадрат, Flash Player или AIR выводят следующие данные трассировки:

clickHandler detected an event of type: click 
the this keyword refers to: [object ChildSprite]

Учтите, что ключевое слово this относится к экземпляру ChildSprite с именем child . В этом состоит отличие от поведения в ActionScript 2.0. Если вы использовали компоненты в ActionScript 2.0, то могли запомнить, что когда метод класса передавался UIEventDispatcher.addEventListener() , область его действия была привязана к компоненту, который выполнял широковещательную рассылку события вместо класса, в котором был определен метод прослушивателя. Иными словами, если вы пользовались этим методом в ActionScript 2.0, ключевое слово this будет относиться к компоненту, осуществляющему широковещательную рассылку события, а не к экземпляру ChildSprite.

Это оказалось значительным препятствием для некоторых программистов, поскольку означало, что они не могут вызвать другие методы и свойства класса, содержащего метод прослушивателя. В качестве обходного пути программисты ActionScript 2.0 могут использовать класс mx.util.Delegate , чтобы изменить область действия метода прослушивателя. Однако это больше не требуется, так как ActionScript 3.0 создает метод привязки при вызове метода addEventListener() . В результате ключевое слово this относится к экземпляру ChildSprite с именем child , и программист имеет доступ к другим методам и свойствам класса ChildSprite.

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

Существует третий метод, при выборе которого создается родовой объект со свойством, указывающим на динамически присвоенную функцию прослушивателя, но пользоваться им не рекомендуется. Он обсуждается здесь по причине широкого применения в ActionScript 2.0. Тем не менее, его не следует использовать в ActionScript 3.0. Этот метод не рекомендован, поскольку ключевое слово this будет относиться к глобальному объекту вместо вашего объекта прослушивателя.

Следующий пример идентичен предыдущему примеру класса ClickExample за исключением того, что функция прослушивателя определена как часть родового объекта с именем myListenerObj :

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler); 
    } 
} 
 
var myListenerObj:Object = new Object(); 
myListenerObj.clickHandler = function (event:MouseEvent):void 
{ 
        trace("clickHandler detected an event of type: " + event.type); 
        trace("the this keyword refers to: " + this); 
}

Результаты трассировки выглядят следующим образом:

clickHandler detected an event of type: click 
the this keyword refers to: [object global]

Ожидается, что this будет ссылаться на myListenerObj и что данные о трассировке станут выводиться в формате [object Object] , но вместо этого ключевое слово ссылается на глобальный объект. При передаче имени динамического свойства в качестве аргумента методу addEventListener() Flash Player или AIR не могут создать метод привязки. Это происходит потому, что в качестве параметра listener передается не что иное, как адрес памяти вашей функции прослушивателя. Flash Player и AIR не могут связать этот адрес памяти с экземпляром myListenerObj .

Управление прослушивателями событий

Функциями прослушивателя можно управлять с помощью методов интерфейса IEventDispatcher. Интерфейс IEventDispatcher — это версия интерфейса EventTarget модели событий DOM для ActionScript 3.0. Хотя и кажется, что основная цель имени IEventDispatcher состоит в отправке (или рассылке) объектов событий, методы этого класса фактически используются гораздо чаще для регистрации прослушивателей событий, проверки наличия прослушивателей событий и их удаления. Интерфейс IEventDispatcher определяет пять методов, как указано в следующем коде:

package flash.events 
{ 
    public interface IEventDispatcher 
    { 
        function addEventListener(eventName:String,  
                        listener:Object, 
                        useCapture:Boolean=false, 
                        priority:Integer=0, 
                        useWeakReference:Boolean=false):Boolean; 
 
        function removeEventListener(eventName:String,  
                    listener:Object, 
                    useCapture:Boolean=false):Boolean; 
 
        function dispatchEvent(eventObject:Event):Boolean; 
 
        function hasEventListener(eventName:String):Boolean; 
        function willTrigger(eventName:String):Boolean; 
    } 
}

В Flash Player API интерфейс IEventDispatcher реализуется в классе EventDispatcher, который служит в качестве базового класса для всех классов, которые могут быть целями событий или частью потока событий. Так, например, класс DisplayObject наследует классу EventDispatcher. Это означает, что любой объект в списке отображения имеет доступ к методам интерфейса IEventDispatcher.

Добавление прослушивателей событий

Метод addEventListener() — это основополагающий компонент интерфейса IEventDispatcher. Он используется для регистрации ваших функций прослушивателя. Необходимо обязательно указывать параметры type и listener . Параметр type применяется для определения типа события. Параметр listener указывает на функцию прослушивателя, которая выполняется при наступлении события. Параметр listener может быть ссылкой либо на функцию, либо на метод класса.

При задании параметра listener не используйте скобки. Например, функция clickHandler() указывается без скобок в следующем вызове метода addEventListener() :
addEventListener(MouseEvent.CLICK, clickHandler)

Параметр useCapture метода addEventListener() позволяет управлять фазой потока событий, в течение которой ваш прослушиватель будет активным. Если useCapture присвоено значение true , ваш прослушиватель будет активным во время фазы захвата потока событий. Если useCapture присвоено значение false , ваш прослушиватель будет активным во время фаз цели и восходящей маршрутизации потока событий. Чтобы прослушивать событие в ходе всех фаз потока событий, необходимо дважды вызвать метод addEventListener() . Первый раз сделайте это с помощью параметра useCapture со значением true , а второй раз — с помощью параметра useCapture со значением false .

Параметр priority метода addEventListener() не является официальной частью модели событий DOM уровня 3. Он включен в ActionScript 3.0 и обеспечивает большую гибкость при организации ваших прослушивателей событий. При вызове метода addEventListener() можно установить приоритет для этого прослушивателя событий, передав целое значение в качестве параметра priority . Значение по умолчанию равно 0, но можно также выбрать положительное или отрицательное целое значение. Чем больше число, тем скорее будет выполнен этот прослушиватель событий. Прослушиватели событий с одним и тем же приоритетом выполняются в порядке добавления. Чем раньше добавляется прослушиватель, тем скорее он будет выполнен.

Параметр useWeakReference позволяет указать, является ли ссылка на функцию прослушивателя слабой или нормальной. Выбор значения true для этого параметра позволяет избежать ситуаций, при которых функции прослушивателя остаются в памяти, хотя они уже больше не нужны. Flash Player и AIR используют метод «сбора мусора» , чтобы убрать из памяти объекты, которые больше не используются. Объект считается неиспользуемым, если на него больше не содержится ссылок. Сборщик мусора не учитывает слабые ссылки. Это означает, что функция прослушивателя, на которую указывает только слабая ссылка, имеет право быть подвергнутой «сбору мусора».

Удаление прослушивателей событий

Метод removeEventListener() можно использовать для удаления неиспользуемых прослушивателей событий. Ненужные прослушиватели рекомендуется удалять. Обязательными являются параметры eventName и listener — как и для метода addEventListener() . Помните, что вы можете прослушивать события на всех фазах события, дважды вызвав метод addEventListener() . Один раз это необходимо сделать с помощью параметра useCapture со значением true , а другой раз с тем же параметром со значением false . Чтобы удалить оба прослушивателя событий, необходимо дважды вызвать метод removeEventListener() . Причем в первый раз это делается с помощью параметра useCapture со значением true , а затем с тем же параметром, которому присвоено значение false .

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

Опытные программисты могут использовать метод dispatchEvent() для отправки заказного объекта события в поток событий. Единственный параметр, принятый этим методом, является ссылкой на объект события, который должен быть экземпляром класса Event или подкласса этого класса. После отправки свойству target объекта события присваивается в качестве значения объект, по отношению к которому вызван метод dispatchEvent() .

Проверка существующих прослушивателей событий

Два последних метода интерфейса IEventDispatcher содержат полезную информацию о наличии прослушивателей событий. Метод hasEventListener() возвращает значение true , если прослушиватель события найден для определенного типа события в том или ином объекте списка отображения. Метод willTrigger() возвращает также true , если найден прослушиватель для определенного объекта списка отображения. Но метод willTrigger() проверяет наличие прослушивателей не только в этом экранном объекте, но и во всех его родительских элемекнтах на всех фазах потока событий.

События Error без прослушивателей

Для обработки событий в ActionScript 3.0 вместо событий применяются исключения, но обработка событий не действует для асинхронных операций (например, загрузки файлов). Если во время подобной асинхронной операции возникает ошибка, Flash Player и AIR отправляют объект события ошибки. Если для события ошибки не создан прослушиватель, отладочные версии Flash Player и AIR выведут на экран диалоговое окно с информацией об ошибке. Например, отладочная версия проигрывателя Flash Player выводит следующее диалоговое окно с описанием ошибки, когда приложение пытается загрузить файл из недействительного URL-адреса:

Большинство событий ошибок основаны на классе ErrorEvent и имеют свойство text , которое используется для хранения сообщения об ошибке, которое выдает Flash Player или AIR. Классы StatusEvent и NetStatusEvent являются двумя исключениями. Оба этих класса обладают свойством level ( StatusEvent.level и NetStatusEvent.info.level ). Когда свойству level присвоено значение "error" , эти типы событий рассматриваются в качестве событий ошибок.

Событие ошибки не приведет к остановке воспроизведения SWF-файла. Оно приведет лишь к появлению диалогового окна в отладочных версиях подключаемых модулей веб-обозревателя и автономных проигрывателей, сообщения на панели вывода в проигрывателе инструмента разработки и записи в файле журнала для Adobe Flash Builder. В рабочих версиях Flash Player или AIR оно никак не проявляется.