Март 2011
Руководство по actionscript. часть 2, стр. 061
Рассмотрим описанные шаги на примере с кнопкой-переключателем. Предположим, мы используем нашу кнопку-переключатель в приложении с панелью управления, которое назначает различные привилегии своим пользователям в зависимости от их статуса. Пользователи-«гости» могут использовать только некоторые
кнопки на панели, в то время как пользователям-«администраторам» доступны все кнопки.
Для реализации различных уровней доступа в приложении мы определяем новый тип события кнопки-переключателя: ToggleEvent. TOGGLE_ATTEMPT. Это событие возникает всякий раз, когда пользователь пытается включить или выключить кнопку-переключатель. Стандартным поведением, характеризующим событие ToggleEvent. TOGGLE_ATTEMPT, является изменение состояния переключателя.
Для упрощения будем считать, что кнопку-переключатель можно включить или выключить только щелчком кнопки мыши (не используя клавиатуру). Всякий раз, когда пользователь щелкает на кнопке-переключателе, выполняется диспетчеризация события ToggleEvent. TOGGLE_ATTEMPT. Затем, если никакой приемник не отменяет стандартного поведения, мы изменяем состояние переключателя. Рассмотрим соответствующий код:
private function clickListener (e:MouseEvent):void { // Пользователь попытался включить или выключить переключатель, поэтому // просим среду Flash выполнить диспетчеризацию события // ToggleEvent. TOGGLE_ATTEMPT. получателем которого является данный объект // ToggleSwitch. Сначала создадим событийный объект… var toggleEvent:ToggleEvent =
new ToggleEvent(ToggleEvent. TOGGLE_ATTEMPT. true, true);
// … затем отправляем запрос на диспетчеризацию события dispatchEvent(toggleEvent);
// Диспетчеризация события Toggl eEvent. TOGGLE_ATTEMPT завершена. // Если никакой приемник не отменил стандартное поведение события… if (ItoggleEvent. isDefaultPrevented( )) {
// …изменяем состояние переключателя
toggle( );
}
}
В нашем приложении с панелью управления мы регистрируем приемник события ToggleEvent. TOGGLE_ATTEMPT для каждого объекта ToggleSwitch. Внутри этого приемника проверяется статус пользователя. Для закрытых переключателей, если пользователь является «гостем», мы отменяем стандартное поведение события. Рассмотрим этот код:
// Приемник выполняется всякий раз. когда возникает событие // ToggleEvent. TOGGLE_ATTEMPT
private function toggleAttemptListener (e:ToggleEvent):void { // Если пользователь является «гостем»… if (userType == UserType. GUEST) {
// …запретить изменение состояния переключателя
e. preventDefaultC );
В листинге 12.5 целиком показан код приложения с панелью управления, включая полнофункциональную, хотя и простую графическую версию кнопки-переключателя. Понять этот код вам помогут подробные комментарии.
Руководство по actionscript. часть 2, стр. 062
Листинг 12.5. Классы приложения с панелью управления
// Класс ToggleEvent package { import flash. events.*;
// Класс, представляющий пользовательское событие «toggle» public class ToggleEvent extends Event {
// Константа для типа события «toggle»
public static const TOGGLE:String = «toggle»;
// Константа для типа события «toggleAttempt»
public static const TOGGLE_ATTEMPT:String = «toggleAttempt»;
// Обозначает текущее состояние переключателя -// включен или выключен public var isOn:Boolean;
// Конструктор
public function ToggleEvent (type:String.
bubbles’.Boolean = false.
cancelable:Boolean = false.
isOn:Boolean = false) { // Передаем параметры конструктора в конструктор суперкласса super(type, bubbles, cancelable);
// Запоминаем состояние переключателя, которое может быть использовано // в приемниках события ToggleEvent. TOGGLE this. isOn = isOn;
}
// Любой класс пользовательского события должен переопределить // метод clone( )
public override function clone( )’.Event { return new ToggleEvent(type, bubbles, cancelable. isOn);
}
// Любой класс пользовательского события должен переопределить // метод toString( )
public override function toString( ):String { return formatToString(«ToggleEvent». «type», «bubbles».
Руководство по actionscript. часть 2, стр. 063
«cancelable». «eventPhase». «isOn»);
}
}
// Класс ToggleSwitch package {
import flash. display.*; import flash. events.*;
// Представляет простую кнопку-переключатель со стандартным поведением public class ToggleSwitch extends Sprite {
// Запоминает состояние переключателя.
private var isOn:Boolean;
// Содержит графическое изображение кнопки-переключателя private var icon.-Sprite;
// Конструктор
public function ToggleSwitch ( ) { // Создаем объект Sprite, который будет содержать графическое // изображение кнопки-переключателя icon = new Sprite( ); addChild(icon);
// По умолчанию переключатель выключен isOn = false; drawOffState( );
// Регистрируем приемник для получения уведомлений всякий раз.
Советы web-дизайнеру
Каждый специалист имеет свои секреты, который он применяет в своей работе. Так и дизайнеры имеют свои маленькие секреты.
Вот некоторые из них:
1. Использование изображений должно быть оправдано, они должны быть дополнением в тему, а не лишь бы что влепить;
2. В изображении должно максимальное значение соотношения качество-размер; Прочитать остальную часть записи »
Руководство по actionscript. часть 2, стр. 064
// Если пользователь щелкнет кнопкой мыши
// на графическом изображении переключателя
icon. addEventLi stener(MouseEvent. CLICK, cli ckLi stener);
}
// Приемник, выполняемый после щелчка кнопкой мыши // на кнопке-переключателе
private function clickListener (e:MouseEvent):void { // Пользователь попытался включить или выключить переключатель. // поэтому просим среду Flash выполнить диспетчеризацию // события ToggleEvent. TOGGLE_ATTEMPT. получателем которого // является данный объект ToggleSwitch. Сначала создадим // событийный объект… var toggleEvent:Toggl eEvent =
new ToggleEvent(ToggleEvent. TOGGLE_ATTEMPT. true, true);
// …затем отправляем запрос на диспетчеризацию события dispatchEvent(toggleEvent);
// Диспетчеризация события ToggleEvent. TOGGLE_ATTEMPT завершена. // Если никакой приемник не отменил стандартное поведение события… if (!toggleEvent. isDefaultPrevented( )) {
// …изменяем состояние переключателя
toggle( );
}
}
// Включает переключатель, если в настоящий момент он выключен, или
// выключает его. если переключатель включен. Стоит отметить, что состояние
// переключателя может быть изменено программным путем, даже если пользователь // не имеет привилегий изменить состояние переключателя вручную, public function toggle ( ):void {
// Изменяем состояние переключателя
isOn = IisOn;
// Рисуем для нового состояния переключателя соответствующее изображение if (isOn) {
drawOnState( ); } else {
drawOffState( );
}
// Просим среду Flash выполнить диспетчеризацию события // ToggleEvent. TOGGLE, получателем которого является данный // объект ToggleSwitch
var toggleEvent:ToggleEvent = new ToggleEvent(ToggleEvent. TOGGLE.
Руководство по actionscript. часть 2, стр. 065
True, false. isOn);
dispatchEvent(toggleEvent);
}
// Рисуем изображение для выключенного состояния private function drawOffState ( ):void {
icon. graphics. clear( );
icon. graphics. lineStyle(l);
icon. graphics. beginFill(OxFFFFFF);
icon. graphics. drawRect(0. 0. 20. 20);
}
// Рисуем изображение для включенного состояния private function drawOnState ( ):void {
icon. graphics. clear( );
i con. g raphi cs.1i neSty1e(1);
icon. graphics. beginFill(OxFFFFFF);
icon. graphics. drawRect(0. 0. 20. 20);
icon. graphics. beginFill(0×000000);
icon. graphics. drawRect(5. 5. 10. 10);
}
}
}
// Класс Control Panel (основной класс приложения) package { import flash. display.*;
// Базовое приложение, которое демонстрирует отмену // стандартного поведения для пользовательских событий public class ControlPanel extends Sprite {
// Присваиваем уровень привилегий для пользователя данного приложения.
Руководство по actionscript. часть 2, стр. 066
// В данном примере только пользователи с привилегиями UserType. ADMIN
// могут использовать кнопку-переключатель.
private var userType:int = UserType. GUEST;
// Конструктор
public function Control Panel ( ) { // Создаем объект ToggleSwitch var toggleSwitch:ToggleSwitch = new ToggleSwitch( ); // Регистрируем приемник для событий // ToggleEvent. TOGGLE_ATTEMPT
toggleSwi tch. addEventLi stener(ToggleEvent. TOGGLE_ATTEMPT.
toggleAttemptListener);
// Регистрируем приемник для событий ToggleEvent. TOGGLE toggleSwi tch. addEventLi stener(ToggleEvent. TOGGLE,
toggleListener); // Добавляем кнопку-переключатель в иерархию отображения // данного объекта addChi1dCtoggleSwitch);
}
// Приемник выполняется всякий раз. когда возникает событие // ToggleEvent. TOGGLE_ATTEMPT
private function toggleAttemptListener (e:ToggleEvent):void { // Если пользователь является «гостем»… if (userType == UserType. GUEST) {
// …запретить изменение состояния переключателя
e. preventDefault( );
}
}
// Приемник выполняется всякий раз. когда возникает событие // ToggleEvent. TOGGLE
private function toggleListener (e:ToggleEvent):void { if (e. isOn) {
traceC’The ToggleSwitch is now on.»); } else {
trace(«The ToggleSwitch is now off.»);
}
}
}
// Класс UserType package {
// Определяет константы, представляющие уровни // пользовательских привилегий в приложении // с панелью управления public class UserType {
public static const GUEST:int =0;
public static const ADMIN:int = 1;
}
} •
Теперь, когда мы познакомились с пользовательскими событиями в ActionScript, рассмотрим две последние темы, связанные с событиями.
Руководство по actionscript. часть 2, стр. 067
Недостаток проверки типов
в событийной модели языка ActionScript
Событийная модель ActionScript, основанная на приемниках, включает несколько различных участников: приемник события, объект, регистрирующий этот приемник, получатель события, событийный объект и имя события. Диспетчеризация определенного события (и его обработка) завершится успешно только в том случае, если все участники будут надлежащим образом взаимодействовать между собой. Для этого должны выполняться следующие основные условия.
? Должен существовать тип события, для которого регистрируется приемник.
? Должен существовать сам приемник.
? Приемник должен знать, как обрабатывать событийный объект, передаваемый в процессе диспетчеризации возникшего события.
? Объект, осуществляющий регистрацию приемника, должен поддерживать указанный тип события.
Когда приемник регистрируется в объекте для получения события, он вступает в соглашение, основанное на типах данных, которое гарантирует выполнение первых трех условий. Если это соглашение не выполняется, компилятор генерирует ошибку типа. Например, рассмотрим следующий код, описывающий и регистрирующий приемник, в котором умышленно допущены три нарушения (выделенные полужирным шрифтом) контракта приемника события:
urlLoader. addEventLi stener(Event. COMPLTE, completeLi stenr);
private function completeListener (e:MouseEvent):void { traceCLoad complete»);
}
В приведенном коде нарушения контракта приемника события заключаются в следующем.
? Константа Event. COMPLTE записана с ошибкой: пропущена буква Е. Компилятор сгенерирует ошибку, которая предупредит программиста о том, что тип события, для получения которого пытается зарегистрироваться приемник, не существует.
Руководство по actionscript. часть 2, стр. 068
? Название приемника события записано с ошибкой: пропущена еще одна буква е. Компилятор сгенерирует ошибку, которая предупредит программиста о том, что регистрируемый приемник не существует.
? Типом данных первого параметра, передаваемого в метод completeListener ( ), является Мои s еЕ ve n t, который не соответствует типу данных событийного объекта для события Event. COMPLETE. На этапе диспетчеризации события среда выполнения Flash сгенерирует ошибку, которая предупредит программиста, что приемник не может обработать переданный в него событийный объект.
Если мы изменим предыдущий код, исправив все указанные ошибки типа, диспетчеризация события и его обработка будут успешно выполнены.
^ I Соглашение между приемником события и объектом, который регистрирует этот при-d, m емник, основанное на типах данных, позволяет гарантировать корректное выполнение нашего кода, обрабатывающего события.
Тем не менее соглашение между приемником и объектом, регистрирующим этот приемник, имеет один недостаток: оно не гарантирует, что объект поддерживает указанный тип события. Например, рассмотрим следующим код, который регистрирует приемник в объекте urlLoader для событий TextEvent. TEXT_INPUT:
url Loader. addEventLi stener (TextEvent. TEXTJNPUT. text InputLi stener);
Хотя с практической точки зрения у нас есть все основания полагать, что объект URLLoader никогда не будет получателем события TextEvent. TEXT_INPUT, приведенный код не вызовет ошибки. В языке ActionScript регистрация приемников для событий осуществляется по любому имени. Например, следующий бессмысленный код также является допустимым:
urlLoader. addEventLi stener(«dlrognw», dlrognwLi stener);
Каким бы очевидным ни казалось то, что объект urlLoader никогда не будет получателем события с именем 11 dl rognw «, программа на самом деле может выполнить диспетчеризацию такого события. Это демонстрирует следующий код:
urlLoader. dispatchEvent(new Event(«dlrognw»));
Учитывая, что программа имеет возможность назначать любой объект в качестве получателя любого события, язык ActionScript намеренно не использует концепцию «поддерживаемых событий». Подобная гибкость является предметом споров, поскольку она может привести к трудновыявляемым ошибкам в коде. Например, предположим, что мы используем класс Loader для загрузки внешнего изображения, как показано в следующем коде:
var loader:Loader = new Loader( );
1oader.1oad(new URLRequest(«i mage. jpg»)):
Предположим также, что объект loader будет являться получателем событий, информирующих о завершении загрузки изображения (во многом аналогично тому, как объект URLLoader является получателем событий о завершении загрузки элемента). Таким образом, мы пытаемся обработать событие Event. COMPLETE для нашего загружаемого элемента, зарегистрировав приемник непосредственно в объекте Loader, как показано в следующем коде:
1oader. addEventLi stener(Event. COMPLETE. completeLi stener);
Запустив код, мы будем удивлены, поскольку, даже несмотря на отсутствие ошибок, метод completeListener ( ) не был вызван ни разу. Так как никаких ошибок не возникло, мы не сможем сразу же определить источник проблемы в нашем коде. Последующий анализ и отладка кода будут стоить нам времени и, по всей вероятности, значительного неудовлетворения. Только прочитав соответствующий раздел документации корпорации Adobe, мы определим проблему: объекты Loader на самом деле не являются получателями событий о завершении загрузки; вместо этого события о завершении загрузки должны обрабатываться
экземпляром класса Loaderlnf о каждого объекта Loader, как показано в следующем коде:
1oader. contentLoaderInfо. addEventLi stener(Event. COMPLETE. completeLi stener);
В будущем язык ActionScript, возможно, позволит классам перечислять события, которые они поддерживают, и генерировать соответствующие предупреждения компилятора на попытки зарегистрировать приемник на события, которые не поддерживаются данным классом. Пока же классы, которые реализуют пользовательские события, путем переопределения метода addEventListener ( ) могут самостоятельно генерировать пользовательские ошибки в тех случаях, когда программа пытается зарегистрировать приемник для неподдерживаемых событий, как показано в следующем коде:
public override function addEventListener(eventType:String.
Руководство по actionscript. часть 2, стр. 069
Handler:Function, capture:Boolean = false, priority:int = 0. weakRef:Boolean = false):void { // Метод canDispatchEv. entC ) (не показан) проверяет наличие // указанного типа eventType в списке поддерживаемых // данным классом событий и возвращает значение типа Boolean. // которое говорит о том. является ли указанный тип eventType // поддерживаемым типом событий if(canDispatchEvent(eventType)) { // Событие поддерживается, поэтому приступаем к регистрации super. addEventListener(eventType. handler, capture, priority. weakRef); } else {
// Событие не поддерживается, поэтому генерируем ошибку throw new ErrorCthis + » does not support events of type ‘» + eventType + );
}
}
Мораль этой истории такова: будьте особенно внимательны при регистрации приемника для события. Всегда убеждайтесь в том, что объект, в котором регистрируется приемник, на самом деле поддерживает требуемое событие.
Теперь рассмотрим последний вопрос, касающийся событийной модели: обработку событий в приложениях, состоящих из нескольких SWF-файлов, которые размещены в различных интернет-доменах. Для изучения следующего раздела необходимс иметь общее представление о методах загрузки SWF-файлов, которые рассматриваются в гл. 28.
Обработка событий между границами зон безопасности
В гл. 19 будет рассмотрено несколько сценариев, в которых ограничения безопас ности не позволяют одному SWF-файлу осуществлять кросс-скриптинг (управ лять программным путем) над другим файлом. Когда два SWF-файла не могу]
осуществлять кросс-скриптинг друг над другом из-за ограничений безопасности приложения Flash Player, к ним применяются следующие ограничения, связанные с обработкой событий.
? Приемники событий из одного SWF-файла не могут регистрироваться для событий в объектах другого SWF-файла.
? Если получателем события является объект в иерархии отображения, любые объекты, недоступные в SWF-файле объекта получателя, не включаются в цепочку диспетчеризации событий.
К счастью, описанные ограничения можно полностью обойти с помощью статического метода allowDomain ( ) класса flash. system. Security. Рассмотрим два примера, которые демонстрируют применение метода allowDomain ( ) для обхода каждого из этих ограничений.
*«, _
*« Информацию по загрузке SWF-файлов можно найти в гл. 28.