Red Spirit

Блог Алексея Таянчина

RSS 2.0

Массовый загрузчик фотографий на Adobe Flex 4. Урок

Совсем недавно, буквально дней 5 назад я начал изучать одну современную, но пока не очень популярную технологию создания RIA - насыщенных интернет приложений под названием Flex, которая выпускает всем известная Adobe. В прошлом посте я говорил, что для сайта мне понадобился массовый загрузчик фотографий и я пытался для этих целей приспособить готовое решения от ВКонтакте, однако по ряду причин оно мне не подошло, потому то я и взялся за изготовление своего загрузчика на Flex 4. Сейчас я хочу рассказать и показать то, что и как у меня получилось. Поскольку я только-только начал работать с флексом и данный загрузчик это мое первое приложения на нём, то естественно, я не могу претендовать на качество и оптимальность кода. Мне достаточно и того, что на практике моя программа работает отлично и делает в точности то, что мне нужно.

И так, начнем с постановки задачи. Нам нужна flash-программа, в которую посредством диалогового окна открытия файла операционной системы можно за раз добавить произвольное количество изображений. Эти изображения должны показаться в приложении в виде превьюшек. Затем нажатием на кнопку “Загрузить” все изображения загружаются на сервер (с сопровождением индикатора загрузки) после чего страница браузера редиректится на другую страницу (с результатами, или еще чем-нибудь). В моем случае приложение предназначено для аплоада аватарок, а поскольку в большинстве своем это анимированые gif-картинки, каких либо изменений (сжатие, трансформации) с изображениями производить не нужно.

Flex Uploader

Скриншот приложения

Я предполагаю, что вы уже знаете, что такое Flex и для чего он нужен, а так же, что у вас уже установлен Adobe Flash Builder (раньше назывался Flex Builder) и есть компилятор 4-ой версии.

ШАГ 1. Создание проекта.

Запускаем Flesh Builder и создаем новый проект Flex. После создания проекта открываем его свойства. В категории “Компилятор Flex” нужно установить версию Флэш-плеера на 10, а в категории “Сервер Flex” желательно указать технологию сервера, которую вы используете на локальном компьютере, это нужно, чтобы удобства проверки работы приложения на предмет закачки файлов и отправки их на сервер.

ШАГ 2. Разметка визуальных компонентов.

Перейдем в режим дизайна. Растягиваем “рабочую область” до нужных размеров и размещаем на всей её площади Panel, ей желательно задать заголовок, типа: “Загрузка фоток”. Далее на Панель кидаем List (обязательно нужно, чтобы этот List был из пакета Spark, то есть тег назывался как s:List), нужно установить свойство layout на spark.layouts.TileLayout, чтобы элементы списка располагались не вертикально, а замещались по всей области списка. Ниже списка на Панели поставим две кнопочки (Button) – одну для вызова диалогового окна выбора файлов, другая для загрузки уже выбранных файлов. Кнопку для загрузки желательно сделать невидимой (visible = false). Левее кнопок под списком разместим Label, он будет показывать, сколько картинок выбрано и какой объем они занимают. Почти все, осталось разместить еще одну небольшую Panel по центру приложения, а на нее аккуратно поставим ProgressBar – для отображения процесса загрузки. Сделаем эту панельку невидимой. И очень важная деталь, вторую панель с прогрессбаром надо располагать не на первой большой панели, а рядом с ней, то есть внутри тэга Application. В принципе все. Можно еще добавить украшательный Label по центру списка с надписью: “Выберите файлы для загрузки”. Эта метка будет отображаться, пока в списке нет ни одного элемента. Большинству этих элементов нужно добавить свой id и еще ряд дополнительных свойств, но мы это будем делать по мере написания ActionScript-кода.

ШАГ 3. Обработчик элементов списка.

Этим шагом я решил показать, как навесить на List обработчик элементов (itemRenderer). По умолчанию список отображает только текстовые данные, а чтобы заставить отображать превьюшки загруженных картинок, нужно вместо текстовых строк установить компонент Image, этим и занимается itemRenderer. Из меню Cоздадим новый MXML-компонент и разместим на нем Image с размерами 100 на 100, а также параметрами x и y определим отступ элементов друг от друга. Далее нужно в свойствах List-а указать параметр itemRenderer=”ava_rend”, где ava_rend это название компонента, который мы только что создали. Все! Конечно, надо будет еще прописать источник данных, но это потом.

ШАГ 4. Подключение необходимых библиотек и объявление переменных.

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

При создании нового проекта Flex сам должен был создать в коде раздел Declarations, он предназначен для объявления невизуальных компонентов. У нас там будут располагаться коллекция (там будут храниться загруженные картинки) и  одна переменная для обозначения общего объема всех картинок. Засунул эту переменную я туда только для того, чтобы сделать её связующей, хотя можно было бы объявить её обычным методом приписав перед var директиву [binable].

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

ШАГ 5. Вызываем окошко выбора файлов.

Теперь начинаем писать собственно код, который будет у нас все обрабатывать. Сразу же определим процедуру инициализации приложения.  В ней мы установим на прослушивание событие выбора файлов в диалоговом окне, а так же занесем в переменные параметры flashvars (адрес скрипта аплоада и страница редиректа), которые должны будут задаваться в HTML.

Чтобы эта процедура срабатывала в момент полной загрузки приложения, нужно в свойствах тэга Application прописать её событие, добавив applicationComplete=”init()”

Из разметки компонентов видно, что к кнопке “Выбрать” к событию клика привязана функция selectPhotos(), её и напишем:

Тут мы просто вызываем диалоговое окно выбора файлов с нужными параметрами масок файлов.

ШАГ 6. Заносим все выбранные файлы в коллекцию.

После того как пользователь выбрал нужные файлы и подтвердил свой выбор, сработает функция addFiles (её указали в прослушивателе при инициализации)

Логика тут проста – последовательно в цикле перебираем все файлы и добавляем каждый из них в коллекцию с помощью вспомогательного обьекта elem. Сам файл будет храниться в свойстве fr, мы можем добавить сколько угодно других свойств для elem (например, имя файла или какие-нибудь атрибуты), и все они будут храниться в коллекции photos. Чтобы мы могли видеть содержимое коллекции в визуальном компоненте List, их надо связать. Для связывания надо указать атрибут source=”{data.fr.data}” комонента Image, который находится в рендерере ava_rend.mxml.

В момент добавления элемента в коллекцию, ставим прослушиватель события окончания загрузки для каждого файла и привязываем к нему функцию onLoad. Эта функция будет выполняться каждый раз, когда файл полностью загрузиться в приложение. Там мы выполняем еще кое-какие действия, а именно добавляем к глобальному счетчику файлов единичку, высчитаем общий размер файлов, а так же поставим условие, которое проверяет, что был загружен последний файл из выбраных, там мы делаем видимой кнопку загрузки файлов на сервер и выполняем один небольшой хак. Дело в том, что по идее, если у визуального компонента обновился (изменился) поставщик данных, то этот компонент должен автоматически отобразить новую информацию, но с List + ava_rend + photos этого не происходит и надо самому каждый раз обновлять этот компонент. Странно то, что я не нашел специального метода для перерисовки List и по этому пришлось выкрутиться тем, что я добавил в коллекцию photos новый пустой элемент и сразу же удалил его, тогда List обновляется и начинает отображаться все картинки, которые были загружены в photos.

ШАГ 7. Загружаем файлы на сервер.

Аплоад изображений на сервер в этом приложении строго последовательный, то есть как только закачивается одна картинка, за ней следует другая. Можно было бы сделать параллельную отправку всех картинок, но при их большом количестве приложение может просто зависнуть (у меня так было, когда я попробовал отправить более сотни файлов за раз). Идеальный вариант, это отправка файлов параллельно, но ограниченой группой, например по 4-5 файлов, таким образом можно добиться максимальной скорости отправки. Но чтобы не усложнять эту учебную программку, я ограничился обычной последовательной отправкой.

Весь процесс начинается с нажатия на кнопку отправки и запуска функции UploadAllImages. Она начинает отправлять с помощью пользовательской функции SendMyFile первый файл с индексом 0 в коллекции. SendMyFile извлекает данные по указанному индексу и заносит их в обьект типа FileReference у которого есть метод upload, им и воспользуемся. Сразу же весим прослушку на событие удачной отправки (onFileUploaded) и событие возникновения ошибки (onFilesUploadedErr). Функция onFileUploaded отсчитывает индекс следующего файла и снова вызывает SendMyFile, а если был загружен последний файл, то выполняется navigateToURL для редиректа на другую страницу. Если вдруг случится какая-либо ошибка при отправки файла, то функция onFilesUploadedErr с помощью метода Alert.show покажет сообщение об ошибке  и следовательно вся цепочка отправки файлов прекращается.

Вот вроде бы и все. Самые основные действия это приложение выполняет, даже уже можно пользоваться. Но еще раз предупрежу – код далек от идеала, в одном месте мне даже пришлось применить нестандартный метод обновления List-а. И вообще по мере изучения Флекса бОльшая часть проблем у меня возникала именно с визуальными компонентами, у них много нюансов, которые постигаются разве что на собственном опыте.

Получившеюся программу можно посмотреть в ДЕМО. Исходники к ней там же (правая кнопка). Для разнообразия в демке приложение с тёмным скином. Буду рад любым комментариям, особенно тем, которым укажут на недостатки реализации и советы в поиске наиболее оптимального решения этих недостатков.

Categories: Мои проекты

  • http://mlex.homeip.net Mlex

    Отличная статья! Просто супер! Именно это я искал :)

  • Vasiliy

    попытался поработать с регулярными выражениями

    но чтото ничего не вышло может поправите где не так

    чтото както неработает что ли

  • Vasiliy

    невставляется код
    типа есть текстовое поле
    есть инпут

    вводим в инпут регулярное выражение

    делаем сверку и выводим массив вхождений ругулярки
    s = ToParse.text;
    regEX = regexp.text as RegExp;
    label2.text = s.match(regEX).length as String;

    поидее должно вывести количество вхождений только чтото никак

  • http://redspirit.ru Red Spirit

    Ну я вообще-то я с регекспами во флексе не работал, но могу посоветовать удостоверится в том, что само регулярное выражение точно составлено правильно (можно проверить в программе RegEx Builder). И вместо того, чтобы брать данные из контролов, попробуй присвоить эти данные (выражение и строку) напрямую текстовым переменным а результат посмотреть через Alert.show().

  • Vasiliy

    Разоборался сам…

    уж чтото а регулярки я писать умею.
    распарсить сат плевое дело
    тут билин надо пользоватся специальными методами.
    var regEX:RegExp = new RegExp( regexp.text , regexpoptions.text );

  • http://redspirit.ru Red Spirit

    Да, действительно, надо было создать новый объект… Будем знать.

  • Anaconda

    var elem:Object = new Object;
    elem.fr = FileReference(frList.fileList[i]);
    elem.fr.load();
    elem.fr.addEventListener(Event.COMPLETE,onLoad);
    photos.addItem(elem);судя по всему это не работает .. либо чего то не хватает потмоу что выходят такие ошибки warning: unable to bind to property ‘fr’ on class ‘Object’ (class is not an IEventDispatcher)
    warning: unable to bind to property ‘data’ on class ‘flash.net::FileReference’
    warning: unable to bind to property ‘fr’ on class ‘Object’ (class is not an IEventDispatcher)
    warning: unable to bind to property ‘data’ on class ‘flash.net::FileReference’