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

Обращение к элементам в многокадровых SWF-файлах

Ранее из подразд. «Обращение к загруженному элементу» разд. «Использование класса Loader для загрузки отображаемых элементов на этапе выполнения» мы узнали, что в тех случаях, когда один SWF-файл загружает другой SWF-файл, все отображаемые элементы и объекты, создаваемые программным путем и размещаемые в первом кадре загружаемого SWF-файла, становятся доступными сразу после возникновения события Event. INIT. Таким образом, код в приемнике события Event. INIT может сразу же выполнять действия над этими элементами и объектами. Тем не менее код в приемнике события Event. INIT не может выполнять действия над элементами и объектами, которые размещаются в последующих кадрах загруженного SWF-файла.

Любой код, желающий обратиться к элементам и объектам, которые размещаются во втором или последующих кадрах загруженного SWF-файла, должен сначала убедиться в существовании этих элементов и объектов. Убедиться, что нужные элементы и объекты существуют в загруженном SWF-файле, можно двумя способами. В SWF-файле, из которого происходит обращение, нужно:

? периодически проверять существование элемента или объекта с помощью объекта

Timer;

? зарегистрировать приемник для пользовательского события, генерируемого загруженным SWF-файлом в тот момент, когда элемент или объект становится доступным.

Рассмотрим каждую из перечисленных методик на примере. Мы снова будем использовать сценарий из предыдущего раздела, в котором приложение Main. swf загружает приложение Module. swf. Предположим, что во втором кадре основной временной шкалы приложения Module. swf размещается сценарий, который создает объект TextField t. Приложение Main. swf загружает приложение Module. swf и желает обратиться к объекту t. Рассмотрим сценарий временной шкалы приложения Module. swf:

stop( );

var t:TextField = new TextField( );

t. text = «hello»;

addChild(t);

В листинге 28.10 показано, как приложение Main. swf загружает приложение Module. swf, а затем периодически проверяет существование объекта TextField перед его использованием.

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

Листинг 28.10. Периодическая проверка существования загруженного объекта

package { import flash. display.*; import flash. events.*; import flash. net.*; import flash. utils.*;

public class Main extends Sprite { private var loader:Loader;

public function Main( ) { // Загружаем файл Module. swf loader = new Loader( );

1 oader. contentLoaderlnfo. addEventLi stener(Event. INIT.

initListener);

1oader.1oad(new URLRequest(«Module. swf»));

}

private function initListener (e:Event):void { // Загруженный SWF-файл был проинициализирован, // поэтому начинаем периодическую проверку существования // объекта TextField. var timer:Timer = new TimerdOO, 0); timer. addEventListener(TimerEvent. TIMER, timerListener); timer. start( );

}

private function timerListener (e:TimerEvent):void { // Проверяем, был ли создан объект TextField // загруженного SWF-файла if (loader. content. hasOwnPropertyC’t»)) {

// Объект TextField уже существует, поэтому мы можем благополучно

// обратиться к нему

trace(Object(loader. content).t. text);

// Останавливаем таймер е. target. stop( );

}

}

}

}

Теперь снова предположим, что приложение Main, swf загружает приложение Module. swf и желает обратиться к объекту t. На этот раз, однако, основной класс Module приложения Module. swf рассылает пользовательское событие Module. ASSETS_READY, когда объект t становится доступным. Приложение Main. swf регистрирует приемник для события Module. ASSETS_READY и обращается к объекту t, когда возникает данное событие. Рассмотрим код для класса Module, в котором определена константа события:

package { import flash. display. MovieClip;

class Module extends MovieClip { // Определяем константу события

public static const ASSETS_READY:String = «ASSETS_READY»;

Теперь рассмотрим сценарий, размещаемый во втором кадре основной временной шкалы приложения Module. swf, который осуществляет диспетчеризацию события, обозначающего доступность объекта t:

stop( );

var t:TextF1eld = new TextField( );

t. text = «hello»;

addChild(t);

di spatchEvent(new Event(Module. ASSETS_READY));

Наконец, в листинге 28.11 представлен код для основного класса приложения Main. swf. Предполагается, что на этапе компиляции компилятор языка ActionScript не имеет доступа к определениям классов загружаемого SWF-файла. В итоге этот код ссылается на событие Module. ASSETS_READY по его строковому имени «ASSETS_READY»:

1oader. content. addEventListener(«ASSETS_READY», assetsReadyListener);

Подобным образом в данном коде значение переменной loader. content приводится к типу Ob j ect, поэтому проверка типов откладывается до этапа выполнения:

Object(1oader. content).t. text

Полную информацию о проверке типов загружаемых элементов можно найти в разд. «Проверка типов на этапе компиляции для динамически загружаемых элементов».

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

Листинг 28.11. Обработка события, сообщающего о доступности загруженного объекта

package { import flash. display.*; import flash. events.*; import flash. net.*; import flash. utils.*;

public class Main extends Sprite { private var loader:Loader;

public function Main( ) { // Загружаем файл Module. swf loader = new Loader( );

1oader. contentLoaderlnfo. addEventLi stener(Event. INIT,

initListener);

1oader.1oad(new URLRequest(«Module. swf»));

}

private function initListener (e:Event):void { // Загруженный SWF-файл был проинициализирован, поэтому регистрируем // приемник для события Module. ASSETS_READY. 1oader. content. addEventLi stener(«ASSETS_READY»,

assetsReadyListener);

private function assetsReadyListener (e:Event):void { // Объект TextField уже существует, поэтому мы можем благополучно // обратиться к нему trace(0bject(1oader. content).t. text);

}

}

}

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

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

Создание экземпляра элемента, загружаемого на этапе выполнения

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

Создание экземпляра загруженного SWF-файла

Чтобы создать новый экземпляр загруженного SWF-файла, мы должны сначала получить ссылку на основной класс этого SWF-файла. Как только ссылка на класс будет получена, мы используем оператор new для создания экземпляра. Существуют два основных подхода для получения ссылки на основной класс загруженного SWF-файла:

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

? получить ссылку на класс с помощью метода экземпляра get Definition ( ) класса ApplicationDomain.

Рассмотрим оба подхода на примерах, снова обратившись к сценарию «приложение Main. swf загружает приложение Module. swf» из предыдущих разделов.

Предположим, что мы хотим создать новый экземпляр приложения Module. swf в приложении Main. swf. Сначала мы сделаем так, чтобы класс Module был непосредственно доступен для приложения Main. swf, используя методику путей исходных файлов, методику путей библиотек или методику путей внешних библиотек, которые были рассмотрены ранее. Повторяя изученный материал, напомним, что как только класс Module станет доступен для приложения Main. swf, мы сможем ссылаться на него напрямую, как показано в операции приведения, взятой из кода приемника события Event. INIT, представленного в листинге 28.9:

private function initListener (e:Event):void { traceC’init»);

Module(e. target. content).start( ); // Прямая ссылка на класс Module

}

Точно так же, чтобы создать новый экземпляр класса Module, мы просто используем оператор new:

private function initListener (e:Event):void { var moduleObj:Module = newModule( );

}

Теперь предположим, что на этапе компиляции приложение Main, swf не имеет доступа к классу Module, но мы по-прежнему хотим создать новый экземпляр приложения Module. swf в приложении Ma in. swf. В подобной ситуации мы должны получить ссылку на класс Module, используя метод экземпляра getDefini t ion ( ) класса ApplicationDomain. Когда в данный метод передается имя класса, он возвращает ссылку на указанный класс. Возвращенную ссылку можно присвоить переменной типа Class для использования в последующих операциях создания экземпляров. Следующий код демонстрирует общую методику:

var SomeClass:Class = иекийАрр^ cati onDomai п. де^е^лт^опГИмяИекоегоКласса»): var obj:Object = new SomeClass( );

Здесь некийАрр! icationDomain — ссылка на объект ApplicationDomain SWF-файла, а имяНекоегоКласса — полностью уточненное строковое имя получаемого класса. Таким образом, чтобы получить ссылку на класс Module из приложения Main. swf, необходимо следующее:

? ссылка на объект ApplicationDomain приложения Module. swf;

? полностью уточненное имя класса Module.

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

К объекту ApplicationDomain SWF-файла можно обратиться через его объект Loaderlnfo, который доступен через переменную loaderlnfo любого экземпляра класса DisplayObject данного SWF-файла. Полностью уточненное имя для основного класса SWF-файла можно получить с помощью метода flash. utils. getQualifiedClassName ( ). Как только приложение Module. swf будет загружено, внутри приемника события Event. INIT в приложении Main. swf мы можем использовать следующий код для получения ссылки на основной класс приложения Module. swf:

var ModuleClassName:String = getQualifiedClassName(e. target. content); var appDomain:ApplicationDomain =

e. target. content.1oaderInfо. appli cati onDomai n: // После выполнения следующей строки кода переменная ModuleClass будет // ссылаться на основной класс приложения Module. swf var ModuleCl ass:Class = appDomain. getDefinition(ModuleClassName);

Получив ссылку на класс Module, мы можем использовать ее для создания новых объектов:

var newModule:Object = new ModuleClass( );

I Как всегда, обязательно дождитесь завершения процесса инициализации загружаемого SWF-м?; d „ файла перед тем, как обратиться к нему. Метод getDefinition() должен применяться только fffi после того, как среда выполнения Flash осуществит диспетчеризацию события Event. INIT.

Обратите внимание, что в предыдущем коде типом данных переменной newModule является Ob j ect, а не Module, поскольку в данном примере приложение Main. swf не имеет непосредственного доступа к основному классу приложения Module. swf. Таким образом, для любых последующих обращений к методам и переменным класса Module через переменную newModule типы не будут проверяться вплоть до этапа выполнения. Если проверка типов требуется на этапе компиляции, вместо метода getDefinition ( ) используйте методики путей исходных файлов, путей библиотек или путей внешних библиотек.

Стоит отметить, что методики, рассмотренные в этом разделе, можно применять не только для создания нового экземпляра SWI^-файла, но и для создания экземпляра любого символа из этого SWF-файла. Предположим, что мы хотим создать экземпляр символа с именем Ball из приложения Module. swf. Для этого нам придется экспортировать символ Ball для кода на языке ActionScript, а затем выполнить одно из следующих действий:

? получить ссылку на экспортированный класс Ball, используя метод экземпляра getDefinition ( ) класса ApplicationDomain;

? сделать так, чтобы класс Ball был непосредственно доступен для приложения Main. swf, используя методику путей исходных файлов, путей библиотек или путей внешних библиотек.

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

Создание экземпляра загруженного изображения

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

Как мы уже знаем, после завершения загрузки файла изображения загруженные пиксельные данные автоматически помещаются в объект BitmapData. Чтобы создать копию пиксельных данных загруженного изображения, мы вызываем метод BitmapData. clone ( ) над этим объектом BitmapData. Данная методика продемонстрирована в следующем коде. Этот код создает копию данных загруженного изображения и передает созданную копию данных в конструктор нового объекта Bitmap. Новый объект Bitmap будет являться копией загруженного элемента растрового изображения. Обращаться к загруженному элементу, как обычно, можно только после возникновения события Event. INIT.

private function initListener (e:Event):void { // Переменная e. target. content ссылается на объект элемента. // представляющего загруженное растровое изображение var newlmage:Bitmap = new Bitmap(e. target. content. bitmapData. clone( )):

// Переменная newlmage теперь содержит копию загруженного // растрового изображения

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

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

? flash. display. Loader;

? flash. net. Socket, применяемый совместно с методом loadBytes ( ) класса Loader.

Теперь, когда мы освоили применение класса Loader, рассмотрим, как он может быть использован совместно с классом Socket для получения отображаемых элементов непосредственно через сокет TCP/IP. Методика, описываемая в данном разделе, может применяться для загрузки элементов в приложении, в котором широко используются сокеты, например в многопользовательской игре, или просто для того, чтобы предотвратить появление загруженного элемента в кэше конечного пользователя.

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

Общий процесс получения отображаемых элементов непосредственно через сокет TCP/IP заключается в следующем.

1. Подключиться к серверу, который может передавать среде выполнения Flash файлы GIF, PNG, JPEG или SWF в бинарном формате.

2. Получить байты для желаемого элемента.

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

Для выполнения первых двух шагов мы используем класс flash. net. Socket языка ActionScript. Взаимодействие класса Socket с сервером осуществляется посредством формата бинарных данных (необработанных байтов). Для выполнения последнего шага мы используем метод экземпляра loadBytes ( ) класса Loader. Метод loadBytes ( ) преобразует необработанные байты в отображаемый объект языка ActionScript.

Описанный процесс подробно рассматривается в следующих разделах.

Серверная часть: отправка элемента

С помощью класса Socket мы можем получать байты для отображаемого элемента с любого сервера, который знает, как отправлять файлы GIF, PNG, JPEG или SWF в бинарном формате. Например, класс Socket может быть использован для получения изображений с большинства почтовых, новостных и чат-серверов — они все обычно поддерживают передачу изображений в бинарном формате.

Вместо того чтобы изучать процесс загрузки элемента с сервера существующего типа (например, почтового, новостного или чат-сервера), рассмотрим более законченный

сценарий, в котором мы разработаем не только клиента, функционирующего в среде выполнения Flash и получающего элемент, но и сервер, отправляющий данный элемент. Мы назовем наш собственный сервер именем FileSender и напишем его на языке Java. Поведение сервера FileSender чрезвычайно простое: при подключении нового клиента сервер автоматически отправляет этому клиенту один файл, затем передает ASCII-символ 4 (завершение передачи) и закрывает соединение.

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

Отметим, что поведение сервера FileSender полностью автоматизировано: клиенту не требуется запрашивать элемент с сервера или отправлять подтверждение о получении элемента в каком-либо виде. Данная архитектура позволяет сконцентрироваться исключительно на процессе передачи элемента.

В листинге 28.12 представлен исходный код на языке Java для сервера FileSender, любезно предоставленный Дереком Клейтоном (Derek Clayton) для этой книги.

Листинг 28.12. Сервер FileSender

import java. net. ServerSocket:

import java. net. Socket;

import java. io. IOException;

import java. io. InputStream;

import java. io. File;

import java. io. FilelnputStream;

import java. iо. BufferedOutputStream;

/**

* FileSender — это простой сервер, который принимает сокетное соединение

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

* Использование: java FileSender [порт] [имя_файла]

* [порт] = порт, на котором сервер будет ожидать подключения (на всех

* локальных IP-адресах)

* [имя_файла] = путь к передаваемому файлу *

*/

public class FileSender implements Runnable { private int port; private File file; private String filename; private ServerSocket server; private Thread thisThread; private byte[] bytes;

public FileSender(int p, String f) { port = p; filename = f:

}

public void start( ) { InputStream is = null; try {

// — читаем файл в наш массив байтов

file = new File(filename):

is = new FilelnputStream(file);

bytes = new byte[(int)file. length( )+l];

int offset = 0;

int byteRead = 0;

while (offset < bytes.length

&& (byteRead=is. read(bytes, offset, bytes. length-offset)) >= 0) { offset += byteRead;

}

bytes[bytes.1ength-1] = 4;

// — создаем объект ServerSocket server = new ServerSocket(port); } catch (Exception e) { e. printStackTrace( ); System. exit(1); } finally {

if (is!= null) { try {

is. close( ); } catch (Exception e) { e. printStackTrace( ); System. exit(l);

}

}

}

// — запускаем объект Thread, который будет принимать подключения thisThread = new Thread(this); thisThread. start( );

}

public void run( ) {

// — пока сервер активен… while (thisThread!= null) {

BufferedOutputStream ps = null;

Socket socket = null ;

try {

// — …принимаем сокетные соединения

// (выполнение потока блокируется, пока не будет

// установлено соединение)

socket = server. accept( );

// — создаем выходной поток

ps = new BufferedOutputStream(socket. getOutputStream( ));

// — записываем байты и закрываем соединение ps. write(bytes); ps. close( );

ps = null; socket. close( ); socket = null; } catch(Exception e) { thisThread = null; e. printStackTrace( ): } finally {

if (ps!= null) { try {

ps. close( ); } catch (IOException e) { e. printStackTrace( ); System. exit(1);

}

}

if (socket!= null) { try {

socket. close( ); } catch (IOException e) {

e. printStackTrace( );

System. exit(1);

}

}

}

}

// — освобождаем ресурсы, занимаемые сервером if (server!= null) { try {

server. close( ); } catch (IOException e) { e. printStackTrace( ); System. exit(l);

}

}

}

public final static void main(String [] args) { // — проверяем, все ли аргументы указаны if (args. length!= 2) {

System. out. printlnC’usage: java FileSender [port] [file]«); System. exit(l);

}

try {

// — преобразуем аргументы к их соответствующему типу int port = Integer. parselnt(args[0]); String filename = args[l];

// — создаем и запускаем объект FileSender

// (который будет выполняться // в своем собственном потоке) FileSender fs = new FileSender(port, filename); fs. start< ); catch (exception e) { e.printstacktrace( ); system.exit(l);

S*4

Исходный код для сервера FileSender можно загрузить по адресу http://moock. org/eas3/ examples.

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

Чтобы запустить сервер FileSender, мы вводим следующую команду для среды выполнения Java:

java FileSender порт имяФайла

Здесь порт — это порт, на котором сервер будет принимать соединения, а имяФайла — имя файла, передаваемого сервером FileSender любому подключившемуся клиенту. Например, чтобы запустить сервер на порте 3000 и сконфигурировать его на отправку файла с именем photo. jpg, мы вводим следующую команду для среды выполнения Java:

java FileSender 3000 photo. jpg

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

Клиентская часть: получение элемента

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

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

«г»

I В ActionScript невозможно приостановить выполнение программы, ожидая появления м$ d * Данных в сокете. Иными словами, сокетные операции языка ActionScript являются асинхронными, а не синхронными.

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

В языке ActionScript данные могут быть прочитаны из сокета только после того, как возникнет событие Progres sEvent. S ОСКЕ T_D AT А. Данное событие сообщает о том, что клиенту доступен некий произвольный объем новых данных для чтория. Однако как только операция чтения новых данных будет завершена, клиент должен снова дожидаться возникновения следующего события ProgressEvent. SOCKET_DATA, чтобы прочитать дополнительные данные из сокета. Рассмотрим общее описание процесса.

1. Клиент подключается к сокету.

2. Сокет получает некоторые данные.

3. Возникает событие ProgressEvent. SOCKET_DATA.

4. Клиент считывает все доступные данные.

5. Сокет получает дополнительные данные.

6. Возникает событие ProgressEvent. SOCKET_DATA.

7. Клиент считывает все доступные данные.

8. Повторение шагов 5-7 до тех пор, пока не будет закрыт сокет.

Объем данных, которые появляются в сокете с возникновением каждого события ProgressEvent. SOCKET_DATA, полностью произволен. Зачастую данные, доступные клиенту при возникновении события ProgressEvent. SOCKET_DATA, составляют лишь часть большого целого. Таким образом, вы должны проявлять особую осторожность, выполняя ручную сборку всех необходимых данных перед их обработкой. Клиент может получить данные некоторого изображения, скажем, в трех сегментах, каждый из которых вызывает событие Progres sEvent. SOCKET_DATA. Перед тем как обработать все изображение целиком, клиентский код должен собрать эти три сегмента вместе.



Полезные ссылки
Случайные записи
  • 01.03.2011">Руководство по actionscript. часть 5, стр. 110
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 080
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 018
  • 18.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.54
  • 10.03.2011">Руководство по actionscript. часть 4, стр. 023
  • 02.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.98
  • 06.03.2011">Руководство по actionscript. часть 4, стр. 146
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.119
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 045
  • 22.01.2011">Руководство по actionscript. часть 1, стр. 109
  • 03.03.2011">Руководство по actionscript. часть 5, стр. 062
  • 09.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.162
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 049
  • 24.02.2011">Руководство по actionscript. часть 7, стр. 008
  • 06.03.2011">Руководство по actionscript. часть 4, стр. 140
Опрос

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

View Results

Loading ... Loading ...