ActionScript 3.0: Введение в основы ООП

Объектно-ориентированное программирование — немного горячая тема. Все больше и больше языков программирования начинают поддерживать эту технологию (Ruby, например), и все больше и больше языков, которые ранее не поддерживали ООП выходят с версиями, которые имеют поддержку ООП, например PHP и ActionScript. Некоторые языки работают только если вы используете все особенности ООП, например, Java или Objective-C.

Это продолжалось в течение долгого времени, но пришло в центр внимания в начале 1990-ых из-за преимущества ООП при программировании GUI (графического интерфейса пользователя) и с ростом языков C++ и Objective-C. В Wikipedia есть интересные статьи об истории ООП, которые могут быть прекрасным источником для начала изучения данной технологии.

Введение

Если вы новичок в ООП, то вам предстоит многому научиться. Тем не менее, изучение этой технологии может уменьшить время на разработку, и в тоже время уменьшить количество ошибок в коде. Это приучит вас к организованности и предотвратит ненужные дублирования в коде. Но, пожалуй, более привлекательны, чем те высокие обещания — это факт того, что Adobe безусловно делает ставку на концепцию ООП, когда дело доходит до ActionScript. ActionScript 1 не был объектно-ориентированным языком вообще, а AS2 был только объектно-ориентированным для удобства разработчика. В противоположность этому, AS3 полностью поддерживает объектно-ориентированные особенности, во всяком случае, будет поддерживать все больше в последующие годы. Так что, если вам нравится программировать в Flash и вы не хотите остаться позади, то вам настоятельно рекомендуется принять ООП как способ программирования.

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

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

Главный вопрос

Так что же такое объектно-ориентированное программирование?

Во-первых, позвольте объяснить, что не так. Объектно-ориентированное программирование (ООП) это не только или даже не обязательно лучший способ программирования в ActionScript 3. Кажется, существует миф о том, что с того времени, как ActionScript 3 дебютировал эту технологию, чтобы использовать AS3, вы должны использовать и ООП.

Хотя и правда, что AS3 больше подходит для ООП, чем AS2, и то, что вам предлагается двигаться в этом направлении, но не правда то, что вы должны изучать, как описывать классы и инициализировать объекты, чтобы построить реальное приложение в Flash. Вы могли заметить во многих уроках по ActionScript 3, что довольно часто код ActionScript 3 написан в панели скриптов, а не в файле класса. Это должно помочь проиллюстрировать то, что вполне приемлемо не использовать ООП во время работы в Flash.

Как говорится, ActionScript 3 действительно показывает класс, если начать применять ООП. И не только AS3, но и любой язык, который поддерживает ООП, может быть использован более эффективно, когда применяется технология ООП. На самом деле, это просто потому, что ООП всего лишь технология — большая, сложная с множеством вариантов для рассмотрения, но по-прежнему, всего лишь технология — а не панацея. И это великолепная технология, одна из тех, с которой стоит начать освоение. И вот почему вы здесь, не так ли?

Классы и объекты

Объектно-ориентированное программирование в действительности сводится к двум фундаментальным единицам: классы и объекты. Они неразрывно связаны: класс порождает объект.

Думайте о классе, как о проекте дома, а об объекте, как о фактическом доме. Проект — это больше схема для понимания того, каким будет дом, а не реальный дом, который будет построен (так как в ходе строительства могут быть добавления и изменения). Когда вы описываете объектно-ориентированный код, вы описываете шаблон, т.е. классы. Затем ваш код создает объекты на основе этих классов во время работы программы.

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

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

Термин «экземпляр» — это слово, которое описывает объект. Когда объект создается на основе класса, то должен быть инициализирован и таким образом создается экземпляр класса. Слово «объект» , как правило, ассоциируется со словом «экземпляр».

Если вся эта терминология беспокоит вас, вспомните о взаимоотношении библиотеки символов и экземпляров, которое было в Flash 1. Символ — это один элемент в библиотеке. Экземпляр — конкретное проявление этого символа. Может быть больше одного экземпляра данного символа, и изменения в графике одного символа приведет к изменению всего экземпляра данного символа. Тем не менее, каждый индивидуальный экземпляр может поддерживать некоторые уникальные свойства, такие как позиция, вращение, трансформация цвета, фильтры, и масштаб. Это прямой аналог класса и объектов (экземпляров). На самом деле, это больше, чем просто аналогия, как будет показано в следующей части этого урока.

Встречайте класс Document

Ну, продолжим изучение? Я думаю, что лучший способ начать знакомство в ООП с класса документа (Document Class). Этот класс такой же, как и любой другой в AS3, кроме того, что он имеет очень важное отношение с файлом Flash. Это класс, который представляет SWF, который вы публикуете. Класс Document инициализируется при запуске SWF-приложения. Он аналогичен понятию «основной» функции (main function), если у вас есть опыт работы в C, или «основному» методу (main method) основного класса в Java.

Создаем папку проекта

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

Создаем папку проекта ActionScript 3.0

Теперь создайте Flash-файл (ActionScript 3.0) и сохраните его в эту папку. Название не так важно, но я назвал файл «MeetTheDocumentClass.fla» .

Создаем Flash-файл ActionScript 3.0

Текстовый файл класса Document

Теперь вам нужно создать текстовый файл. Вы можете использовать Flash CS3+ для этого, или Flex/Flash Builder, или любой другой подходящий текстовый редактор, на самом деле. FlashDevelop — прекрасный (и бесплатный) выбор, если работаете в Windows. Есть много других вариантов текстовых редакторов, и нет правильных ответов (хотя, как я говорю своим ученикам, есть один неправильный ответ. Текстовый редактор, встроенный в Flash CS3/4 на самом деле немного ужасный, и чем раньше вы это поймете, тем раньше начнете наслаждаться программирование в настоящем редакторе). Лично я предпочитаю TextMate, но не забываю, что главное это текст в файле, а не только редактор.

Все, что было сказано, это создать новый файл в редакторе, который вы выбрали (если вы используете Flash CS3+ , то перейдите в меню File -> New и выберите «ActionScript file» из списка. Если такого нет, то предполагаю, что вы достаточно знакомы со своим редактором с тем, чтобы сделать это без наставлений и подсказок).

Сохраните файл как «DocumentClass.as» в той же папке, где находится Flash-файл. Это важно: расположение и имя очень важны. Имя не обязательно должно быть «DocumentClass.as» , но я буду использовать его, чтобы предотвратить путаницу, и рекомендую вам просто сделать то же, что и я. Имя может быть любым, какое вы хотите (более или менее), но мое мнение в том, что имя играет важную роль в AS3 ООП, поэтому будьте внимательны. То же самое касается расположения файла, технически оно может быть где угодно, но для удобства просто следуйте моему примеру. Другие варианты будут рассмотрены в других уроках.

Подводя итог, вот моя папка проекта в том виде, как она выглядит сейчас:

Создаем Flash-файл DocumentClass ActionScript 3.0

Описываем класс Document

Теперь вы столкнулись с пустым файлом. Если вы когда-то страдали от творческого кризиса писателя (как у меня, который постоянные читатели должны были заметить…), то вы можете успокоиться, так как первая вещь, которую вы должны написать — это на самом деле шаблон. Вам нужно будет написать следующее:

package {
  import flash.display.MovieClip;
  public class DocumentClass extends MovieClip {
    public function DocumentClass() {

    } 
  }
}

Ничего себе, и что все это такое? Ну, немного больше, чем нужно объяснить прямо сейчас. Я просто отмечу несколько интересных мест.

Во-первых, обратите внимание, что «package» оборачивает всю страницу. Не беспокойтесь об этом, просто помните, что это нужно здесь, и класс должен содержаться в нем.

Во-вторых, у нас есть оператор «import» . Вы, должно быть, не видели раньше такую строчку кода; если вы застряли и программируете в панели Script, до сих пор так и не пользуясь сторонними библиотеками ActionScropt, то вам не нужно было писать оператор «import». В мире ООП, каждый класс должен импортировать различные классы, которые нужны для того, чтобы делать свое дело. Подробнее об импорте поговорим позже.

В-третьих, следующая «обертка» — это сам класс. Вы можете видеть ключевое слово «class» в третьей строчке. Структура этой строчки больше чем нам нужно сейчас, просто обратите внимание, что слово, следующее за словом «class» — это имя класса. Вы должно быть заметили, что имя, которое я использовал точно такое же, что и имя файла без расширения. Это не совпадение. Для работы с классами в AS3, имя класса должно совпадать с именем файла. Не забывайте об этом.

Мы вернемся к строчке «extends MovieClip» в следующем уроке. А сейчас, просто знайте, что это нужно для класса документа (вы также можете расширять класс Sprite, например, так «extends Sprite» , если вам не нужна временная шкала, и если вы измените строчку импорта на «import flash.display.Sprite;«)

И наконец, у нас есть конструктор.

Конструктор (Constructor)

В предыдущем примере была (почти) обычная функция, определяемая внутри класса. Почти обычная, за исключением слова «public» впереди, и без определенного типа данных. Опять же, не беспокойтесь о слове «public» сейчас, все придет со временем. Тем не менее, обратите внимание на имя функции. Вот именно, оно такое же что и имя файла, и имя класса. К счастью, вы не совсем параноик, потому что это не заговор. Это просто способ, при котором все работает. Называя функцию одинаковый именем, что и класс, мы создаем специальную функцию под названием конструктор (constructor). Конструктор выполняется во время инициализации. Надеюсь, что вы успеваете с новой терминологией, потому что мы просто использовали два новых определения в одном предложении.

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

Hello, World! (Привет, Мир!)

В качестве практического примера напишем небольшую программу «Hello World» . Мы будем не просто выводить слова в панели Output, но еще создадим TextField (текстовое поле), добавим его на сцену, и поместим некоторый текст в него. Раскройте файл DocumentClass.as как показано ниже (изменения выделены полужирным шрифтом):

package {
  import flash.display. MovieClip;
  import flash.text.TextField;
  public class DocumentClass extends MovieClip {
    public function DocumentClass() {
      var tf:TextField = new TextField();
      addChild(tf);
      tf.text = "Hello World";
    }
  }
}

Обратите внимание, что в дополнение к трем строчкам, добавленным в конструктор, теперь есть дополнительная строчка import перед объявлением TextField.

Очевидно, что можно было бы сделать это позже, позиционировать и задать стиль текста, и вы всегда можете сделать это на свое усмотрение, но сейчас это служит в качестве примера. Данный код создает текстовое поле со словами «Hello Word» в нем, и отображает на сцене. За исключением одного: Flash-файл не знает, что его цель класс документа. Если вы попытаетесь запустить Flash-файл сейчас, то получите пустое окно. Давайте исправим это далее.

Назначение класса Document

Как уже упоминалось ранее, Flash-файл (MeetTheDocumentClass.fla в данном случае) еще не знает, что у него есть определенный класс документа, а только старый чистый MovieClip, так что он не собирается делать большего.

Хорошо, что нам это известно, но то, что мы действительно хотим прямо сейчас — это позволить Flash-файлу знать, где находится файл DocumentClass.as , который мы только что написали. Чтобы сделать это, сначала убедитесь, что ничего не выбрано (вы можете нажать мышью в любом месте на сцене, где нет визуальных объектов, или выбрать в меню Edit > Deselect All, или нажать Control-Shift-A).

Далее, откройте панель свойств (Properties). Если вы успешно сняли выделение со всех объектов, то панель свойств отобразит «Document» наверху.

Панель свойств (Properties) отображает Document

Теперь, там, где написано «Class:» в разделе «Publish» панели «Properties» , введите «DocumentClass» (или любое другое имя, которое используете для своей версии класса, если настаиваете на своем сформированном пути к файлу). Обратите внимание, что имя должно быть без расширения «.as» — это просто имя класса, а не имя файла.

в текстовом поле Class панели Properties введите DocumentClass

Если вы следовали указаниям до сих пор, то нажмите Enter и все будет в порядке. Если почему-то имя класса неправильное, или вы не сохранили файлы в той же папке, то вы не получите сообщение об ошибке при публикации. Вы получите такое сообщение об ошибке при вводе текста в поле имени класса:

сообщение об ошибке при вводе текста в поле имени класса

Если вы проигнорировали сообщение, или не увидели его, потому что ранее отметили пункт «Don’t show again» (не показывать снова), то затем SWF-файл будет опубликован без ошибок, но вы получите чистый белый экран. Если это происходит, то дважды щелкните по имени класса, которое вводили в панели «Properties» .

Как только свойство «class» документа будет правильно подключено, вы сможете убедиться в этом, щелкнув мышью на маленький значок карандаша рядом с текстовым полем «document class» в панели свойств. Будет открыт файл в Flash CS3+ для редактирования. Не то, чтобы я рекомендовал держать его там, но проверить, что вы подключили правильный файл, будет полезным советом во избежание возникновения неисправностей.

После того, как вы все проверите, направляйтесь и проверьте Flash-приложение (нажмите ctrl + enter). Вы должны будете увидеть простое окно со словами «Hello World » в нем.

проверьте Flash-приложение (нажмите ctrl + enter)

Свойства

Начиная с этого момента, вы устанавливаете логику приложения в классе документа и начинаете создавать более интересный SWF. Тем не менее, вам, вероятно, понадобится больше, чем одна функция конструктора, чтобы это сделать. Как правило, нужно создавать другие объекты, привязывать их к переменным, использовать функции для прослушивания событий и чтобы эти элементы взаимодействовали в значительной степени. Конечно, в ООП есть такие элементы, как переменные и функции, они отличаются различными названиями: свойства и методы (мы займемся методами в следующей главе).

Свойства, по своей сути, это простые переменные. Хотя, есть небольшое отличие между свойствами и переменными. Оно незначительное, и мы должны продемонстрировать его на примере, но есть некоторые причины, чтобы сначала рассмотреть его, а уже потом идти дальше.

Во-первых, свойство записывается также в переменную, с двумя оговорками. Вот пример:

private var tf:TextField;/code>

Первый нюанс должен быть очевиден: есть большой старый «private» перед ключевым словом «var» . Атрибут «private» похож на «public» , о котором мы говорили ранее, и который я просил игнорировать. Я попрошу сделать это и сейчас. Мы не поймем эти атрибуты, пока не перейдем к следующему уроку.

Второй нюанс не так очевиден, потому что выбивается из контекста. Вот так более подходяще:

public class DocumentClass extends MovieClip {
private var tf:TextField;
  public function DocumentClass() {
  // ...
  }
}

Обратите внимание на позицию свойства по отношению к структуре класса. Функция конструктора и свойства находятся на одном «уровне» и «принадлежат» напрямую классу (они вложены в класс соответственно). Такая характеристика делает из переменной свойство (несмотря на то, что объявлена при помощи ключевого слова «var«).

В противоположность этому, переменная с именем «foo» в примере ниже обычная переменная:

public class DocumentClass extends MovieClip {
private var tf:TextField;
  public function DocumentClass() {
    var foo:String = "bar";
  }
}

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

Конечно же есть исключения для правила «фигурных скобок» . Циклы, например, не влияют на видимость переменной, объявленной внутри, поэтому относитесь к этому правилу скептически. Вы не найдете этого правила в книгах по программированию.

Вы, должно быть, задаетесь вопросом,

«Но постойте, разве функция не существует внутри объекта на том же уровне, что и свойство? Разве она не существует так же постоянно, как и свойство, и, следовательно, переменная внутри этой функции так же не должна будет исчезать?»

У вас есть точка зрения, тем не менее, что различие в том, что функция, которая может быть потенциально вызвана, существует внутри объекта, в то время как фактическая работающая функция существует только на момент вызова. Переменная создается во время запуска, и, следовательно, исчезает, как только работа функции заканчивается. Как я и говорил, различия едва различимы. Но они важны, в чем вы убедитесь далее.

Методы

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

public class DocumentClass extends MovieClip {
  public function DocumentClass() {
  // ...
  }
  public function onButtonClick(e:MouseEvent):void {
    trace("click");
  }
}

Теперь функция onButtonClick() стала довольно знакомой, за исключением надоедливой директивы public в начале. И опять, не будем обращать на нее внимания. В данном случае, вам следует воспринимать эту запись как обычную функцию. Разница лишь в том, что тоже самое понятие «владение» применяется к методам, как и к свойствам, по сравнению с обычными переменными и функциями.

И наконец, давайте рассмотрим все это на рабочем примере.

package {
  import flash.display. MovieClip;
  import flash.text.TextField;
  import flash.events.MouseEvent;

  public class DocumentClass extends MovieClip {

    private var tf:TextField;

    public function DocumentClass() {
      tf = new TextField();
      addChild(tf);
      tf.text = "Hello World";

      stage.addEventListener(MouseEvent.CLICK, onButtonClick);
    }

    private function onButtonClick(e:MouseEvent):void {
      tf.text = "Hey, you clicked!";
    }

  }
}

Обратите внимание на изменения и дополнения: мы добавили свойство «tf» . В конструкторе, мы также создаем текстовое поле TextField, но вместо создания переменной в конструкторе, как мы делали раньше, мы просто используем свойство «tf» . Текстовое поле TextField теперь сохраняется в свойстве, а не в переменной.

Мы также добавили прослушиватель события на нажатие кнопки мыши на сцене (нет, сцена на самом деле не кнопка, но в данном случае это сэкономит время в плане создания объекта MovieClip для поведения в качестве кнопки). И этот прослушиватель — метод с именем «onButtonClick()» , кроме того применяется метод вместо функции, что идентично для любого другого обработчика событий.

Что же делает этот метод таким значительным: он заменяет текст в текстовом поле на другую строчку. Это может произойти, только если «tf» сохраняет значение по прошествии времени. Если приложение работало, то мы знаем, что «tf» все еще ссылается на TextField , созданный в конструкторе, хотя вероятно прошло несколько секунд между созданием TextField и его повторным переназначением.

вывод сообщения в приложении после изменения кода ActionScript

Изучение видимости

Теперь, если вы уберете свойство и вернете создание переменной TextField , то не сможете протестировать приложение, так как компилятор будет выдавать ошибку о том, что не может найти свойство с именем «tf«. Вот код:

package {
  import flash.display.MovieClip;
  import flash.text.TextField;
  import flash.events.MouseEvent;

  public class DocumentClass extends MovieClip {

  //private var tf:TextField;             //we have removed this line!

  public function DocumentClass() {
    var tf:TextField = new TextField();
    addChild(tf);
    tf.text = "Hello World";

    stage.addEventListener(MouseEvent.CLICK, onButtonClick);
  }

  private function onButtonClick(e:MouseEvent):void {
    tf.text = "Hey, you clicked!";
  }

  }
}

Происходит ошибка:

вывод сообщения об ошибке на панели output

Что случилось? Ну, в ActionScript переменная, созданная в одной функции существует во время исполнения этой функции (что больше нескольких строчек позже), и исчезает, как только запускается вторая функция. Так что, если создать переменную «tf» в функции конструктора и попытаться использовать ее в функции onButtonClick(), то будут проблемы, так как переменная «tf» больше не существует, когда запускается функция onButtonClick().

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

В данном случае, переменные иногда ссылаются в качестве локальных, потому что являются локальными по отношению к функции.

И это довольно тонкий вопрос, с которого мы начали. Надеюсь, что все понятно, потому что, как я считаю, этот момент бывает причиной многих «подводных камней» для начинающих изучение ООП.

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

По поводу кнопки…

Хорошо, в предыдущем шаге я пропустил создание кнопки и просто использовал сцену в качестве области для нажатия кнопкой мыши. Мы изменим это, но не потому что нажатие по сцене неправильное (это не так, в некоторых обстоятельствах), но потому что мы можем создать класс кнопки Button для дальнейшего изучения ООП.

Нашей целью будет создание класса кнопки, из которого мы сможем создать множество объектов класса Button. Каждый объект Button будет иметь некоторую основную функциональность, которая будут универсальными для всех кнопок:

  • Наведение курсора и обычные состояния
  • Курсор превращается в значок руки
  • Графический фон с текстовой меткой

В то же время, нужно будет сделать некоторые вещи уникальными для каждой кнопки:

  • Текст метки
  • Действие при нажатии кнопки мыши
  • Расположение кнопки

Мы рассмотрим то, что необходимо для создания второго класса, участвующего в проекте, и включим эти требования во время создания класса.

Создаем класс кнопки Button

Мы создадим класс, который при инициализации будет рисовать прямоугольник, устанавливать текст в метку, обрабатывать состояния кнопки при наведении курсора мыши, и сможет реагировать на нажатия кнопки мыши. Начнем с создания нового текстового файла в редакторе текста. Сохраните его как «Button101.as» в той же папке, где находится Flash-файл. Это важно. Не перепутайте! Я серьезно.

создаем класс кнопки Button и файл класса ActionScript

Пишем шаблон

В новом файле, начнем с шаблона класса:

package {
  import flash.display.Shape;
  import flash.display.Sprite;
  import flash.events.MouseEvent;
  import flash.text.TextField;
  import flash.text.TextFormat;

  public class Button101 extends Sprite {

    public function Button101() {

    }

  }
}

Добавляем некоторые свойства

Далее, добавим некоторые свойства для управления формой фона и меткой:

// ...
public class Button101 extends Sprite {

  private var bgd:Shape;
  private var labelField:TextField;

  public function Button101() {
  // ...

В свойстве bgd будет содержаться ссылка на форму (Shape), которая будет рисоваться программно и заполнять заливкой прямоугольник, и добавлять в качестве ребенка спрайт (Sprite).

Свойство labelField будет содержать ссылку на текстовое поле (TextField), которое будет создаваться в коде, также, и использоваться для отображения текстовой метки поверх фона.

Добавляем логику

А теперь заглянем в настоящую логику. Для конструктора:

public function Button101() {
  bgd = new Shape();
  bgd.graphics.beginFill(0x999999, 1);
  bgd.graphics.drawRect(0, 0, 200, 50);
  addChild(bgd);

  labelField = new TextField();
  labelField.width = 200;
  labelField.height = 30;
  labelField.y = 15;
  var format:TextFormat = new TextFormat();
  format.align = "center";
  format.size = 14;
  format.font = "Verdana";
  labelField.defaultTextFormat = format;
  addChild(labelField);

  addEventListener(MouseEvent.ROLL_OVER, onOver);
  addEventListener(MouseEvent.ROLL_OUT, onOut);

  mouseChildren = false;
  buttonMode = true;
}

Слишком много кода, но ничего удивительного по большому счету. Мы создаем новую форму (Shape) и рисуем прямоугольник в ней. Затем, мы создаем текстовое поле (TextField), устанавливаем ему основное форматирование. Далее, добавляем события на действия мыши при нахождении на кнопке и вне ее (слушатели для каждого события будут добавлены в следующем шаге). И наконец, установим некоторые свойства, чтобы придать объекту поведение больше похожее на кнопку.

Только одна часть может вызвать непонимание, это вызов addChild(), и то, откуда пришли свойства mouseChildren и buttonMode. Я снова попрошу вас подождать более полного ответа, так как мы рассмотрим это в следующем уроке, но нужно многое проделать с «extends Sprite» , который мы описали ранее.

Добавляем некоторые методы

Теперь, мы можем продолжить работу над классом. После конструктора, создайте функцию с именем «setLabel» .

public function setLabel(label:String):void {
  labelField.text = label;
}

И, наконец, создайте два прослушивателя событий:

private function onOver(e:MouseEvent):void {
  bgd.alpha = 0.8;
}
private function onOut(e:MouseEvent):void {
  bgd.alpha = 1;
}

Весь код должен выглядеть вот так:

package {
  import flash.display.Shape;
  import flash.display.Sprite;
  import flash.events.MouseEvent;
  import flash.text.TextField;
  import flash.text.TextFormat;

  public class Button101 extends Sprite {

    private var bgd:Shape;
    private var labelField:TextField;

    public function Button101() {
      bgd = new Shape();
      bgd.graphics.beginFill(0x999999, 1);
      bgd.graphics.drawRect(0, 0, 200, 50);
      addChild(bgd);

      labelField = new TextField();
      labelField.width = 200;
      labelField.height = 30;
      labelField.y = 15;
      var format:TextFormat = new TextFormat();
      format.align = "center";
      format.size = 14;
      format.font = "Verdana";
      labelField.defaultTextFormat = format;
      addChild(labelField);

      addEventListener(MouseEvent.ROLL_OVER, onOver);
      addEventListener(MouseEvent.ROLL_OUT, onOut);

      mouseChildren = false;
      buttonMode = true;
    }
  public function setLabel(label:String):void {
    labelField.text = label;
  }
  private function onOver(e:MouseEvent):void {
    bgd.alpha = 0.8;
  }
  private function onOut(e:MouseEvent):void {
    bgd.alpha = 1;
  }
}
}

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

Надеюсь, что компилятор будет уведомлять о подобных ошибках, но сама ошибка загадочной. Компилятор может выдать «1114: The public/private/protected/internal attribute can only be used inside a package.» . Если вы получаете такое сообщение, то проверьте уровень вложенности методов. Еще один способ помочь предотвратить такие ошибки — это обратить пристальное внимание на проблемы и отступы. «Настоящий» текстовый редактор может помочь вам с этим, но просто убедитесь в том, что все объявления методов имеют один и тот же уровень вложенности (обычно две точки в редакторе).

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

Создаем кнопку

Вернемся к классу документа и добавим кнопку в приложение. Это довольно просто сделать, по сравнению с предыдущими шагами.

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

private var tf:TextField;
private var button:Button101;

Не обязательно располагать все свойства вместе, но для организации файла полезно держать данные в соответствующих местах. Лично я всегда перечисляю свойства с самого верха класса, перед конструктором. Таким образом, я всегда знаю, куда направиться, чтобы найти объявление свойства. Куда разместить свойства в файле не так важно, как ваши собственные стандарты и описания свойств в классе.

Продолжаем, теперь мы можем инициализировать «Button101» в конструкторе класса документа.

public function DocumentClass() {
  tf = new TextField();
  addChild(tf);
  tf.text = "Hello World";

  button = new Button101();
  button.x = 10;
  button.y = 200;
  button.setLabel("Button 1");
  addChild(button);
  button.addEventListener(MouseEvent.CLICK, onButtonClick);

  //stage.addEventListener(MouseEvent.CLICK, onButtonClick);     //we have removed this line
}

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

Теперь, вы возможно удивлены тем, как мы обрабатываем объект «Button101» , как будто он экземпляр класса Sprite или MovieClip (смотрите урок о списке отображения DisplayList, если не были удивлены). Это все, что нужно сделать с директивой extends , чтобы исправить ее сейчас. Я обещаю, что мы рассмотрим этот вопрос (в следующем уроке).

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

Для примера, вот полный класс документа на данный момент, с дополнениями и изменениями, отмеченными полужирным шрифтом:

package {
  import flash.display.MovieClip;
  import flash.text.TextField;
  import flash.events.MouseEvent;

  public class DocumentClass extends MovieClip {

    private var tf:TextField;
    private var button:Button101;

    public function DocumentClass() {
      tf = new TextField();
      addChild(tf);
      tf.text = "Hello World";

      button = new Button101();
      button.x = 10;
      button.y = 200;
      button.setLabel("Button 1");
      addChild(button);
      button.addEventListener(MouseEvent.CLICK, onButtonClick);
    }

    private function onButtonClick(e:MouseEvent):void {
      tf.text = "Hey, you clicked!";
    }
  }
}

Итак, что же выполняется в коде? Самое важное — это то, что мы получаем довольно изящную кнопку, которую могли бы использовать с небольшим усилием (не считая усилия по написанию класса Button101 в самом начале).

создание и вывод кнопки Button1 при помощи ActionScript

Для достижения такой же функциональности без использования классов и ООП, нам пришлось бы написать гораздо больше кода в основном скрипте. Чтобы проиллюстрировать это, давайте создадим вторую кнопку.

Создаем еще одну кнопку

Хорошо, давайте позволим ООП засиять по-настоящему. Мы создадим второй экземпляр кнопки, просто добавив чуть больше строчек кода в класс документа.

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

private var tf:TextField;
private var button:Button101;
private var button2:Button101;

Затем настроим кнопку в конструкторе:

public function DocumentClass() {
  tf = new TextField();
  addChild(tf);
  tf.text = "Hello World";

  button = new Button101();
  button.x = 10;
  button.y = 200;
  button.setLabel("Button 1");
  addChild(button);
  button.addEventListener(MouseEvent.CLICK, onButtonClick);

  button2 = new Button101();
  button2.x = 220;
  button2.y = 200;
  button2.setLabel("Button 2");
  addChild(button2);
  button2.addEventListener(MouseEvent.CLICK, onButtonClick);
}

На самом деле вы можете просто скопировать и вставить строчки кода первой кнопки и изменить имя с button на button2, а также изменить позицию координаты x второй кнопки (иначе button2 будет располагаться прямо поверх button1).

Мы удвоили сложность приложения всего лишь несколькими короткими строчками кода, благодаря возможности повторного использования класса Button101. У нас есть класс, которые, если вы помните, является шаблоном, на основании которого создаются экземпляры. Сейчас у нас есть две различные кнопки, но они имеют общее «наследие» . Даже если есть много характеристик, которые одинаковы между этими двумя кнопками, например, эффект при наведении курсора мыши на кнопку или размер кнопки, есть еще и аспекты индивидуальности, а именно — расположение.

Надеюсь, что это показывает полезность и силу объектно-ориентированного программирования, которое способствует повторному использованию кода.

Проверьте пример, у вас должно быть две кнопки, которые делают одно и тоже.

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

Подводя итоги

Было две главные темы в данном уроке: пример с проектами домов (классы) и фактических домов (экземпляры), и понятие об области видимости.

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

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

Это, тем не менее, всего лишь малая часть, верхушка айсберга. Это все, что есть прямо сейчас, но в следующих уроках мы рассмотрим подробнее данную тему и, наконец, получим разъяснения по всем вопросам, которые я откладывал на потом, например, такие как директивы extends и public. Многие вещи обретут больше смысла. Но когда дело касается сложных тем, таких как, например, объектно-ориентированное программирование, лучше всего продвигаться постепенно. Если вам понравился урок, расскажите о нем в социальных сетях (значки внизу), это поможет продвижению сайта.

Источник: https://code.tutsplus.com/tutorials/as3-101-oop-introduction-basix—active-5789

Комментировать

Почта не публикуется.Обязательные поля отмечены *