Руководство по actionscript. часть 4, стр. 023

Public function containerClickListenerOne (e:MouseEvent):void { // Исключаем получение события функциями containerClickListenerTwo( ) // и chi1dClickListener( ) e. stopImmediatePropagation( );

}

С другой стороны, если функция containerClickListenerOne ( ) поглотит событие путем вызова метода stopPropagation ( ) вместо метода stoplmme diatePropagation ( ), то перед остановкой процесса диспетчеризации события будут вызваны оставшиеся приемники события MouseEvent. CLICK объекта container. Следовательно, функция containerClickListenerTwo ( ) получит событие, а функция childClickListener ( ) — нет.

public function containerClickListenerOne (e:MouseEvent):void { // Исключаем получение события только функцией childClickListener( ) e. stopPropagation( );

}

Обратите внимание, что предыдущий пример основывается на условии, что функция containerClickListenerOne ( ) была зарегистрирована перед функцией containerClickListenerTwo ( ). Дополнительную информацию о порядке, в котором вызываются приемники событий, можно найти в гл. 12.

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

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

Для реализации состояния «неактивен» в каждом объекте ToolPanel регистрируется метод clickListener ( ) для уведомления о возникновении события MouseEvent. CLICK в фазе захвата. Когда объект ToolPanel неактивен, метод clickListener ( ) останавливает все события щелчка кнопкой мыши до того, как они достигнут дочерних объектов Tool. В листинге 21.3 представлен класс ToolPanel, который был сильно упрощен, чтобы акцентировать внимание на коде, поглощающем событие (выделен полужирным шрифтом). В этом листинге дочерние элементы управления интерфейса класса ToolPanel являются экземплярами базового класса Tool, который отсутствует в листинге. Однако в реальном приложении эти элементы управления могут быть кнопками, меню или любыми другими видами интерактивных инструментов.

Руководство по actionscript. часть 4, стр. 024

Листинг 21.3. Поглощение события

package { import flash. display. Sprite; import flash. events.*;

public class ToolPanel extends Sprite { private var enabled:Boolean;

public function ToolPanel ( ) { enabled = false;

var tool 1:Tool = new TooK ); var tool2:Tool = new TooK ); var tool3;Tool = new TooK );

tool 2.x = tool 1.width + 10;

tool 3.x = tool 2.x + tool 2.width + 10;

addChild(tooll); addChild(tool2); addChild(tool3);

// Регистрируем приемник в этом объекте для уведомлений // о возникновении события MouseEvent. CLICK в фазе захвата addEventListener(MouseEvent. CLICK, clickListener, true);

}

private function clickListener (e:MouseEvent):void { // Если данный объект ToolPanel неактивен… if (!enabled) {

// …останавливаем процесс диспетчеризации данного события -// щелчка кнопкой мыши, чтобы оно не достигло потомков данного // объекта ToolPanel

e. stopPropagation( );

traceC’Panel disabled. Click event dispatch halted.»);

}

}

}

}

В повседневной разработке приложений метод stopPropagation ( ) используется гораздо более часто, чем stopImmediatePropagation ( ). Тем не менее второй метод применяется в следующих ситуациях:

? когда объект-получатель желает, чтобы его собственные приемники не вызывались в результате возникновения события;

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

Руководство по actionscript. часть 4, стр. 025

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

? GameManager — класс, управляющий процессом игры;

? PlayerShip — класс, который представляет космический корабль игрока.

Класс GameManager определяет собственное событие GameManager. SHIP HIT, диспетчеризация которого осуществляется всякий раз, когда вражеская ракета попадает в корабль игрока. Получателем каждого события GameManager. SHIPHIT является объект PlayerShip. Этот объект регистрирует два приемника, которые реагируют на события GameManager. SHIP HIT. Один приемник проигрывает анимацию, имитирующую взрыв, а другой приемник воспроизводит звук взрыва.

Когда корабль игрока погибает, создается новый корабль, и на протяжении пяти секунд он остается неуязвимым. До тех пор пока корабль остается неуязвимым, приемники события GameManager. SHIP_HIT объекта PlayerShip не должны воспроизводить анимацию или звук «повреждения корабля».

Чтобы исключить выполнение приемников события GameManager. SHIP HIT до тех пор, пока корабль остается неуязвимым, класс PlayerShip регистрирует третий приемник hit Li stener ( ), предназначенный для поглощения событий GameManager. SHIPHIT на основании текущего статуса корабля (неуязвим или уязвим). Регистрация метода hitListener ( ) с приоритетом int, MAX_VALUE происходит в конструкторе класса PlayerShip, как показано в следующем коде:

public class PlayerShip { public function PlayerShip ( ) { addEventl_istener(GameManager. HIT, hitListener, false, int. MAX_VALUE);

}

}

В гл. 12 рассказывалось, что по умолчанию приемники событий объекта вызываются в том порядке, в котором они были зарегистрированы. Мы также знаем, что этот используемый по умолчанию «порядок вызова» может быть перекрыт с помощью параметра priority метода addEventListener ( ).

Руководство по actionscript. часть 4, стр. 026

Поскольку при регистрации метода hitListener ( ) в конструкторе класса PlayerShip используется максимально возможный приоритет, из всех прием-

ников события GameManager. SHIP_HIT класса PlayerShip этот приемник всегда будет вызываться первым. Если объект PlayerShip является уязвимым и возникает событие GameManager. SHIP_HIT, метод hitListener ( ) не выполняет никаких действий. Но если объект PlayerShip не является уязвимым и возникает событие GameManager. SHIP_HIT, метод hitListener ( ) сначала поглощает это событие, а затем выполняет диспетчеризацию нового события PlayerShip. HIT DEFLECTED. После этого приемники, зарегистрированные для события PlayerShip. HIT_DEFLECTED, воспроизводят специальную анимацию и звук, которые сообщают о том, что корабль не был поврежден.

Далее представлен код метода hitListener ( ); обратите внимание на использование метода stopImmediatePropagation ( ):

private function hitListener (e:Event):void { if (invincible) { // Исключаем получение другими приемниками объекта PlayerShip // уведомления о возникновении события e. stopImmediatePropagation( ); // Рассылаем новое событие

dispatchEvent(new Event(PIayerShiр. HIT_DEFLECTED, true));

}

}

В предыдущем сценарии с классом PlayerShip стоит отметить, что, хотя объект PlayerShip может предотвратить вызов своих собственных приемников события GameManager. SHIP HIT, он не может предотвратить вызов приемников события GameManager. SHIP HIT, зарегистрированных в его отображаемых предках. В частности, любые приемники, зарегистрированные для фазы захвата в отображаемых предках объекта PlayerShip, будут всегда получать уведомление о возникновении события GameManager. SHIP_HIT, даже если объект PlayerShip поглотит это событие. Однако после того, как объект PlayerShip поглотит событие GameManager. SHIP_HIT, его предки не получат уведомление в фазе всплытия.

Теперь перейдем ко второму сценарию с использованием метода stopImmediatePropagation ( ), в котором программа желает, чтобы никакие приемники не отвечали на данное событие. Предположим, мы создаем набор компонент пользовательского интерфейса, которые автоматически переходят в неактивное состояние, когда среда выполнения теряет фокус операционной системы, и возвращаются в активное состояние, когда среда получает фокус операционной системы. Чтобы определить момент получения или потери фокуса операционной системы, наши компоненты регистрируют приемники для внутренних событий Event. ACTIVATE и Event. DEACTIVATE (дополнительные сведения об этих событиях можно найти в гл. 22).

Руководство по actionscript. часть 4, стр. 027

Предположим, мы разрабатываем тестовое приложение для выполнения нагрузочных испытаний наших компонентов. Наше приложение программным путем вызывает интерактивное поведение компонентов. В тесте мы должны гарантировать, что внутреннее событие Event. DEACTIVATE не переводит наши тестируемые компоненты в неактивное состояние. В противном случае наше тестовое приложение не сможет работать с ними программным путем. Таким образом, в конструкторе основного класса нашего текстового приложения мы регистрируем приемник для события Event. DEACTIVATE в экземпляре класса Stage. Этот приемник использует

метод stopImmediatePropagation ( ) для поглощения всех внутренних событий Event. DEACTIVATE, как показано в следующем коде:

private function deactivateListener (e: Event):void { e. stopImmediatePropagation( );

}

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

Приоритет и цепочка диспетчеризации событий

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

I Не существует способа сделать так, чтобы приемник одного объекта в цепочке дис-j « петчеризации события вызывался до или после приемника другого объекта в той же ¦^-Щ? цепочке.

Например, представьте объект Sprite, содержащий объект TextField. Объект Sprite регистрирует приемник spriteClickListener ( ) для события MouseEvent. CLICK — параметру useCapture установлено значение false, а параметру priority присвоено значение 2:

o6beKrSpr7′te. addEventLi stener (MouseEvent. CLICK, spriteClickListener, false. 2)

Точно так же объект TextField регистрирует приемник textClickListener ( ) для события MouseEvent. CLICK — значение параметра useCapture установлено в false, а параметру priority присвоено значение 1:

0бъектТехЬПе1с1. addEventLi stener (MouseEvent. CLICK, textClickListener, false. 1)

Когда пользователь щелкает кнопкой мыши на объекте TextField, среда Flash выполняет диспетчеризацию события MouseEvent. CLICK, получателем которого является объект TextField. В результате метод textClickListener ( ) вызывается в фазе получения перед методом spriteClickListener ( ), который вызывается в фазе всплытия. Два приемника события вызываются в порядке, устанавливаемом цепочкой диспетчеризации события, даже несмотря на то, что метод spriteClickListener ( ) был зарегистрирован с более высоким приоритетом, чем textClickListener ( ).

Руководство по actionscript. часть 4, стр. 028

Дополнительную информацию о приоритетах событий можно найти в гл. 12.

Изменение иерархии отображения и цепочка диспетчеризации событий

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

Предположим, у нас есть экземпляр класса TextField, содержащийся в экземпляре класса Sprite, который, в свою очередь, содержится в экземпляре класса Stage. ПустьтaкжeмыpeгиcтpиpyeмпpиeмникstageClickListener ( ) вэкземпляре класса Stage для уведомления о возникновении события MouseEvent. CLICK в фазе захвата, как показано в следующем коде:

stage. addEventLi stener(MouseEvent. CLICK. stageCli ckLi stener, true):

Наконец, предположим, что зарегистрированная функция stageClickListener ( ) содержит код, который удаляет объект TextField из его родительского объекта Sprite, как показано в следующем коде:

private function stageClickListener (e:MouseEvent):void { // Если щелкнули кнопкой мыши на объекте TextField… if (е. target == textField) {

// …то удаляем его

removeChild(textField);

textField = null:

}

}

Когда пользователь щелкает кнопкой мыши в текстовом поле, среда Flash выполняет диспетчеризацию события MouseEvent. CLICK, получателем которого является объект TextField. Перед началом процесса диспетчеризации среда выполнения заранее определяет всю цепочку диспетчеризации события, как показано ниже:

ФАЗА ЗАХВАТА: (1) Объект Stage

(2) Объект Sprite ФАЗА ПОЛУЧЕНИЯ: (3) Объект TextField ФАЗА ВСПЛЫТИЯ: (4) Объект Sprite

(5) Объект Stage

Когда начинается процесс диспетчеризации, среда Flash сначала уведомляет о возникновении события объект Stage (1). В результате этого уведомления вызывается приемник stageClickListener ( ) объекта Stage, который удаляет объект TextField из списка отображения. Далее, несмотря на то, что объект Sprite больше не является потомком объекта TextField, среда выполнения уведомляет о возникновении события объект Sprite (2). Затем, несмотря на то

что объекта Text Field больше нет в списке отображения, среда выполнения уведомляет о возникновении события объект TextField (3). Наконец, в фазе всплытия среда Flash снова уведомляет о возникновении события объекты Sprite (4) и Stage (5). Даже несмотря на то, что иерархия отображения получателя события была изменена в процессе диспетчеризации, событие все равно проходит по всей предопределенной цепочке диспетчеризации события.

Руководство по actionscript. часть 4, стр. 029

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

В листинге 21.4 представлен код для приведенного сценария в контексте тестового класса DisappearingTextField. В этом листинге экземпляр пользовательского класса DisappearingTextField (подкласс класса Sprite) играет роль объекта Sprite из описанного сценария.

Листинг 21.4. Неизменяемая цепочка диспетчеризации события

package { import flash. display.*; import flash. events.*; import flash. text.*;

public class DisappearingTextField extends Sprite { private var textField.-TextField; public function DisappearingTextField ( ) {

// Создаем объект TextField

textField = new TextField( );

textField. text = «Click here»;

textField. autoSize = TextFieldAutoSize. LEFT;

// Добавляем объект TextField в объект DisappearingTextField addChild(textField);

// Регистрируем приемник в экземпляре класса Stage для событий // MouseEvent. CLICK

stage. addEventLi stener(MouseEvent. CLICK, staged ickListener, true);

// Чтобы доказать, что объект TextField получает уведомление

// о возникновении события MouseEvent. CLICK даже после того, как он

// будет удален из данного экземпляра класса DisappearingTextField,

// регистрируем приемник в объекте TextField для событий

// MouseEvent. CLICK

textFi eld. addEventLi stener(MouseEvent. CLICK, textFieldCli ckLi stener);

}

// Эта функция выполняется, когда пользователь щелкает кнопкой мыши

// на любом объекте в списке отображения

private function stageClickListener (e:MouseEvent):void {

// Если щелкнули кнопкой мыши на объекте TextField…

Руководство по actionscript. часть 4, стр. 030

If (е. target == textField) { // …то удаляем его

removeChild(textField); textField = null:

}

}

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

private function textFieldClickListener (e:MouseEvent):void { // На данный момент метод stageClickl_istener( ) // уже удалил объект TextField, // однако приемник все равно вызывается. trace(«textFi eldClickLi stener triggered»);

}

}

}

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

Руководство по actionscript. часть 4, стр. 031

Например, рассмотрим процесс диспетчеризации события MouseEvent. CLICK, получателем которого является объект Sprite, содержащийся в экземпляре класса Stage. Цепочка диспетчеризации события включает в себя три уведомления о возникновении события, как показано ниже:

ФАЗА ЗАХВАТА: (1) Объект Stage уведомлен ФАЗА ПОЛУЧЕНИЯ: (2) Объект Sprite уведомлен ФАЗА ВСПЛЫТИЯ: (3) Объект Stage уведомлен

Предположим, что на этапе первого уведомления (1) код в приемнике объекта Stage регистрирует новый приемник для события MouseEvent. CLICK в объекте Sprite. Поскольку событие еще не было передано в объект Sprite, новый приемник будет вызван на этапе второго уведомления (2).

Теперь предположим, что на этапе первого уведомления (1) код в приемнике объекта Stage регистрирует новый приемник для события MouseEvent. CLICK в экземпляре класса Stage, который будет вызываться в фазе всплытия. Поскольку этап первого уведомления (1) уже начался, список приемников экземпляра класса Stage уже заморожен, поэтому новый приемник не будет вызван на этапе первого уведомления (1). Тем не менее новый приемник появится в цепочке диспетчеризации события и будет вызван на этапе третьего уведомления (3).

Наконец, предположим, что на этапе второго уведомления (2) код в приемнике объекта Sprite отменяет регистрацию существующего приемника для события MouseEvent. CLICK в объекте Sprite. Поскольку этап второго уведомле-

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

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

Пользовательские события

и цепочка диспетчеризации события

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

Руководство по actionscript. часть 4, стр. 032

Обобщенный код, показанный в листинге 21.5, демонстрирует, как пользовательские события, аналогично внутренним событиям, передаются по цепочке диспетчеризации события. В этом листинге тестовый класс CustomEventDemo говорит среде Flash выполнить диспетчеризацию пользовательского события, получателем которого является объект Sprite в списке отображения.

Листинг 21.5. Пользовательское событие, передаваемое по цепочке диспетчеризации

package { import flash. display.*; import flash. events.*; import flash. text.*;

public class CustomEventDemo extends Sprite { public static const SOMEJVENT: String = «SOMEJVENT»;

public function CustomEventDemo ( ) { var sprite:Sprite = new Sprite( ); addChild(sprite);

// Регистрируем приемник someEventListener( ) в экземпляре класса Stage // для уведомлений о возникновении события CustomEventDemo. SOME_EVENT. stage. addEventListener(CustomEventDemo. SOME_EVENT. someEventListener);

// Осуществляем диспетчеризацию события CustomEventDemo. SOME_EVENT,

// получателем которого является объект в списке отображения.

// Второй параметр конструктора класса Event устанавливаем в значение

// true, чтобы у события появилась фаза всплытия.



Полезные ссылки
Случайные записи
  • 21.03.2011">Руководство по actionscript. часть 2, стр. 043
  • 09.03.2011">Руководство по actionscript. часть 4, стр. 061
  • 20.07.2011">Как не обмануться, выбирая CMS (часть 2)
  • 10.03.2011">Руководство по actionscript. часть 4, стр. 018
  • 07.03.2011">Руководство по actionscript. часть 4, стр. 110
  • 23.07.2011">Каждая квартира достойна уникального дизайна
  • 04.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.15
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.107
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 072
  • 15.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.47
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.85
  • 04.09.2011">FastStore Image Viewer
  • 20.03.2011">Руководство по actionscript. часть 2, стр. 077
  • 01.03.2011">Руководство по actionscript. часть 5, стр. 114
  • 19.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.6
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...