Программирование мобильных телефонов
Конфигурация CDC
Конфигурация CDC объединяет в себе ряд устройств имеющих постоянное сетевое соединение, таких как двунаправленные пейджеры, телевизионные приставки, автомобильные системы навигации, интеллектуальные коммуникаторы. Данные устройства характеризуются более мощными системными ресурсами, они имеют обычно 16 или 32-разрядные процессоры и как минимум 2 мегабайт памяти. В этой связи обе конфигурации CDC и CLDC, имеют свой набор свойств, определяющих поддержку библиотек Java API, виртуальную машину, свойства самого языка Java. Эти свойства и отличают разные конфигурации.
Как вы уже знаете, каждая из конфигураций построена на основе блочной схемы в виде надстраиваемых профилей. Профиль ставит определенные требования к аппаратной части устройства, и содержит свой набор API позволяющий создавать на основе имеющихся библиотек различные приложения. Профили созданы для определенной конфигурации, а приложения пишутся под конкретный профиль. Такая блочная модель позволяет любому приложению работать на портативных устройствах, поддерживающих данный профиль.
Конфигурация может содержать несколько профилей. Конфигурация CDC имеет два профиля - это Foundation Profile и Personal Profile и PDA. Смысл и устройство этих профилей мы рассматривать не будем, они не имеют никакого отношения к теме этой книги и были приведены лишь для понимания общей идеи конфигурации. При желании в документации по Java 2 ME вы сможете найти необходимую информацию и изучите ее самостоятельно.
Конфигурация CLDC
Конфигурация CLDC рассчитана на семейство мобильных устройств, таких как телефоны, органайзеры, КПК. Мобильные устройства, для которых предназначена конфигурация CLDC, характеризуются следующими параметрами:
Все перечисленные характеристики, несомненно, накладывает определенные ограничения на создаваемое приложение. Конфигурации CDC и CLDC независимы друг от друга и не могут использоваться вместе. Вся концепция конфигурации CLDC была разработана дочерней группой Java Community Process, компании Sun Microsystems, которая включает в себя множество известных компаний:
Конфигурация CLDC содержит ряд классов, интерфейсов, методов платформы Java 2 SE, но в урезанном виде. Это и не мудрено, компьютерная платформа превосходит по мощности мобильные телефоны во много раз. С другой стороны, та простота, с которой можно за несколько недель создать среднее по сложности приложение, подкупает и даже возвращает нас во времена шестнадцатибитных приставок. На самом деле общая масса игр, написанных на Java 2 ME, по своему игровому процессу напоминает именно те старые добрые времена.
Конфигурация CLDC также определяется своим набором свойств состоящих из языка Java, виртуальной Java машины и библиотек API. В данный момент имеется две версии этой конфигурации - это CLDC 1.0 и CLDC 1.1. Конфигурация CLDC 1.1 имеет больше возможностей, например поддержку чисел с плавающей точкой, что соответственно предъявляет более серьезные требования к аппаратной части телефона. В момент написания книги таких телефонов не было, поэтому вся книга построена на конфигурации CLDC 1.0. К слову сказать, конфигурация CLDC 1.1 построена на первой версии и просто имеет ряд улучшений. Остановимся на каждом свойстве конфигурации CLDC 1.0 подробней. В последствии при упоминании конфигурации, будет иметься в виду CLDC 1.0.
Пакет Javaio
Классы этого пакета отвечают за работу с входными и выходными потоками данных. На рис. 2.5 показана иерархия наследования классов пакета java.io.
Рис2.5. Иерархия пакета java.io
Интерфейсы:
Классы:
Исключения:
Пакет javalang
Этот пакет содержит системные классы или основы языка Java и исключения. Имеется также один единственный интерфейс Runnable. На рис. 2.3 изображена иерархия классов пакета java.lang.
Рассмотрим имеющиеся компоненты пакета java.lang и дадим краткую характеристику каждому из них.
Рис 2.3. Иерархия классов пакета java.lang
Интерфейс:
Классы:
Исключения:
Ошибки:
Пакет Javautil
В этом пакете содержатся классы стандартных утилит упрощающих работу программиста. Пакет сильно урезан по сравнению со стандартным пакетом Java 2 SE. На рис. 2.4 представлена иерархия классов пакета jova.util.
Рис 2.4. Иерархия классов пакета Java.util
Интерфейс:
Классы:
Имеет возможность изменять размер заданного массива.
Исключения:
Пакет javaxmicroeditionio
Этот пакет содержит множество интерфейсов и всего два класса обеспечивающих связь с сетью. На рис. 2.6 и рис. 2.7 приводится общая схема наследования соответственно интерфейсов и классов пакета javax.microedition.io.
Рис 2.6. Иерархия интерфейсов пакета javax.microedition.io
Интерфейсы:
Рис 2.7. Иерархия классов пакета javax.microedition.io
Классы:
Исключение:
Пакет javaxmicroeditionlcdui
Данный пакет имеет разнообразные классы для реализации пользовательского интерфейса в мобильных приложениях. Существует большое количество классов, благодаря которым можно создать действительно красивое интерактивное приложение. На рис. 2.8 изображена иерархия классов пакета javax.microedition.lcdui.
Рис 2.8. Иерархия классов пакета javax.microedition.lcdui
Интерфейсы:
Классы:
Пакет javaxmicroeditionlcduigame
Это новый игровой пакет добавлен в профиль MIDP 2.0. В состав пакета входит пять мощных и хорошо продуманных классовое помощью которых можно достаточно легко создавать игры для мобильных устройств. На рис. 2.9 показана иерархия классов пакета javox.microedition.lcdui.game.
Рис 2.9. Иерархия классов пакета
Классы:
Пакет javaxmicroeditionmedia
Пакет добавлен в профиль MIDP 2.0 и служит для создания звукового сопровождения в приложении. Пакет разработан специальной экспертной группой (MMAPI Expert Group), в состав которой входят такие известные компании:
В профиле MI DP 1.0 отсутствует возможность полноценной работы со звуком, и каждый из производителей предоставлял свои библиотеки для этих целей. В профиле MIDP 2.0 такой необходимости уже нет и можно воспользоваться любым необходимым классом и интерфейсом из пакета javax.microedition.mediu. На рис. 2.10 приводится наследование интерфейсов этого пакета.
Рис 2.10. Иерархия интерфейсов из пакета javax.microedition. media.
Интерфейсы:
Классы:
Исключение:
Пакет javaxmicroeditionmediacontrol
С помощью пакета javax.microedition.media.control определяется контроль над воспроизведением заданных звуковых данных. Это небольшой пакет, имеющий в своем составе всего два интерфейса, а на рис. 2.11 дается схема наследования интерфейсов.
Рис.2.11. Иерархия интерфейсов пакета javax.microedition.media.control
Интерфейсы:
Пакет javaxmicroeditionmidlet
Сам по себе пакет небольшой, но он играет ключевую роль при создании приложений на Java 2 ME. С помощью этого пакета происходит связь между приложением и мобильным информационным профилем устройства (MIDP). Рисунок 2.12 отражает полную иерархию пакета javax.microedition.midlet.
Рис. 2.12. Иерархия пакета javax.microedition.midlet
Класс:
Исключение:
Пакет javaxmicroeditionpki
Пакет javax.microedition.pki сертифицирует информацию для безопасной связи. Рисунок 2.13 содержит иерархию этого пакета.
Рис.2.13. Иерархия пакета javax.microedition.pki
Интерфейс:
Исключение:
Пакет javaxmicroeditionrms
Этот пакет предназначен для создания механизма хранения и извлечения данных из памяти устройства. Хранение и запись данных происходит на основе менеджера системной записи (Record MaAagement System), что дает возможность удалять, добавлять, просматривать, изменять или составлять список всех имеющихся записей. Имеется один класс и несколько интерфейсов реализующих механизм сохранения и извлечения данных. На рис. 2.14 представлена иерархия пакета javax.microedition.rms.
Рис 2.14. Иерархия пакета javax.microedition.rms
Интерфейсы:
Класс:
Исключения:
В этой главе мы рассмотрели состав одиннадцати пакетов, давая краткую характеристику имеющимся интерфейсам, классам и исключениям. В конце книги в приложении 2, вы найдете справочник по Java 2 ME, где рассматриваются более подробно все составляющие CDLC/MIDP.
В следующей главе будет изучены интегрированные средства разработки приложений, бесплатно предоставляемые компанией Sun Microsystems.
Профиль MIDP и конфигурация CLDC
Язык Java самый "библиотечный язык", такого количества продуманных классов, наверное, нет ни в одном языке программирования. С другой стороны, простота в использовании Java, по всей видимости, поспособствовала определенной популярности этого языка. С точки зрения программиста, обилие готовых классов гораздо упрощает разработку программного продукта, и что самое главное, уменьшает сроки создания программ.
Профиль MIDP 2.0 и конфигурация CLDC 1.0, содержит большое количество интерфейсов и классов, использование которых в программировании приложений, пожалуй, сможет удовлетворить любого разработчика. Часть классов было взято из Java 2 SE с некоторыми усечениями, а часть была специально написана под Java 2 ME. Вся библиотека доступная для профиля MIDP 2.0 и конфигурации CLDC 1.0, состоит из одиннадцати пакетов. По традиции каждый отвечает за свою определенную область.
Все пакеты с префиксами javax.microedition.*, написаны специально для Java 2 ME профиля MIDP 2.0. Пакеты с префиксом Java.*, взяты из Java 2 SE версии 1.4, в урезанном виде, и имеет полную совместимость с оригиналом и определенны в конфигурации CLDC 1.0.
Профиль
Как уже не раз отмечалось, профиль содержит предопределенные требования к аппаратной части устройства, а так же включает в себя минимальный набор API используемый в программировании мобильных устройств. Единственно доступный рабочий профиль в конфигурации CLDC имеет название MIDP (Mobile Information Device Profile - информационный профиль мобильных устройств). Спецификация профиля разработана экспертной группой MIDP Expert Group, в состав которой входят следующие компании:
Профиль MIDP был создан специально для поддержки мобильных устройств и задает следующие технические характеристики для мобильных устройств:
Такое сочетание конфигурации и профиля CLDC/MIDP используется в программировании мобильных телефонов и будет основным сочетанием при рассмотрении примеров из книги.
На данный момент профиль MIDP имеет две версии: MIDP 1.0 и MIDP 2.0. До последнего времени первая версия MIDP была основным профилем при создании приложений для телефонов. Все телефоны, поддерживающие Java, имеют совместимость с профилем MIDP 1.0. Этот профиль был сформирован при начальном создании платформы Java 2 ME и имеет в своем составе определенный набор API,
С выходом профиля MIDP 2.0 добавилось ряд новых библиотек, значительно улучшающих создание приложений для мобильных телефонов. Но самое главное это то, что у него имеется полная совместимость с профилем MIDP 1.0. Профиль MIDP 2.0 содержит большое количество новых дополнительных библиотек, отсутствующих в составе MIDP 1.0, но при создании приложений под профиль MIDP 2.0, можно пользоваться библиотеками профиля MIDP 1.0. Если же вы пишите программу под профиль MIDP 1.0, то библиотеки профиля MIDP 2.0 вам будут недоступны. В книге будут рассмотрены оба профиля как единое целое. Подытожив все вышесказанное о профилях и конфигурациях необходимых для программирования мобильных телефонов, можно резюмировать: программный продукт создаваемый разработчиками ориентирован на конкретный профиль, который является, спецификацией устанавливающей определенные требования к аппаратной части телефона, а1 также содержит дополнительные библиотеки. Каждый конкретный профиль надстраивается над своей и только ему доступной конфигурацией. Конфигурация предъявляет требования к виртуальной Java машине и свойствам языка Java, используемым в этой конфигурации. Далее идет плотное взаимодействие с аппаратным обеспечением телефона, через имеющиеся сервисы, которые предоставляются операционной системой либо прошивкой телефона. Благодаря такой цепочке взаимодействий, любое программное обеспечение, написанное на Java под конкретный профиль, будет работать на телефоне с поддержкой Java. На рис. 2.2 хорошо прослеживается общая схема взаимодействия приложения с мобильным телефоном.
Рис 2.2. Схема взаимодействия приложений с аппаратным обеспечением телефона
Такая модульность в построении Java 2 ME дает неограниченную возможность в модернизации всей платформы и написанию действительно аппаратно-независимого кода программы. Люди, знакомые с моей книгой "DirectX 9. Уроки программирования на C++", обязательно найдут много общего в подходе реализации двух платформ DirectX и Java 2 ME. Оставшаяся часть этой главы целиком посвящена рассмотрению пакетов и классов доступных в MIDP 2.0/CLDC 1.0. Будут затронуты практически все имеющиеся компоненты данного профиля и конфигурации.
Свойства языка Java
Все свойства языка Java в конфигурации CLDC должны, насколько это возможно, соответствовать спецификации языка Java, но в силу ограниченности системных ресурсов мобильных устройств, не поддерживаются следующие 'свойства доступные в платформах Java 2 ЕЕ и Java 2 SE:
1) операции с дробными числами (floating point);
2) финализация (finalization);
3) отсутствует восстановление ошибок после сбоя (error handling).
Виртуальная машина
Виртуальная машина, используемая в конфигурации CLDC, несколько отличается от обычной виртуальной машины задействованной в Java, но обязана оставаться совместимой со спецификацией этой виртуальной машины (Java Virtual Machine Specification). Виртуальная машина находится непосредственно в телефоне и за совместимостью с общепринятой спецификацией обязаны следить производители мобильных телефонов. Сама же виртуальная машина носит название Kilobyte Virtual Machine (KVM) из-за своей компактности и также имеет ряд недоступных свойств:
1) не поддерживаются операции с дробными числами (floating point);
2) нельзя создать класс загрузчик (class loader);
3) отсутствует механизм отражения (reflection);
4) не реализован Java Nativ интерфейс (Java Native Interface);
5) не поддерживается финализация (finalization);
6) отсутствует восстановление ошибок после сбоя (error handling);
7) не поддерживается работа с групповыми потоками (Thread group).
Эти недоступные свойства языка Java и виртуальной Java машины, очевидным образом накладывают ощутимые ограничения на создаваемые программы, к сожалению, архитектура аппаратной части телефонов, еще пока не в силах выдержать столь высокую нагрузку и поэтому от перечисленных выше свойств пришлось отказаться.
Файл JAD
Как уже упоминалось, в рабочем каталоге проекта "Demo" будет находиться еще один файл Demo.jad. JAD-файл в мобильных приложениях еще называют дескриптором приложения Qava Application Descriptor). Этот файл используется телефоном во время работы программы для получения информации об имеющихся классах, изображениях, пиктограммах и звуковых файлах всей программы. На основе полученной информации происходит управление внутренними ресурсами приложения. Если вы переместитесь в рабочий каталог проекта "Demo" и найдете сгенерированный файл Demo.jad, то увидите иконку в виде телефона с левой стороны от названия файла. Сделав двойной щелчок левой кнопкой мыши на файле Demo.jad, вы запустите эмулятор телефона вне зависимости от того, открыта ли в данный момент одна из сред программирования или нет. Это еще раз указывает на то, что JAD-файл используется для управления работой программы. Но есть и еще одна интересная особенность JAD-файла. Откройте файл Demo.jad с помощью любого текстового редактора и вы увидите следующие строки:
MIDlet-1: Demo, Demo.png, HelloMIDlet MIDlet-Jar-Size: 30 MIDlet-Jar-URL: Demo.jar MIDlet-Name: Demo MIDlet-Vendor: Unknown MIDlet-Version: 1.0 MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0
JAD-файл тоже содержит описание атрибутов приложения и они во многом дублируются в файле манифеста MANIFEST.MF. В программах Java 2 ME, JAD-файл - это дескриптор приложения и используется для управления работой программы. Сервис телефона перед запуском программы обращается именно к JAD-файлу, определяя тем самым возможность работы всей программы на этом телефоне. Если один из параметров будет не допустимым для этой модели телефона, то приложение не будет запущено. Например, телефон не поддерживает ту или иную версию конфигурации и профиля, или размер JAR-файл, больше допустимой памяти в телефоне выделенной для Java программ (правда в этом случае вы вообще не сможете загрузить приложение в телефон).
Файл JAR
В языке Java существует возможность архивации файлов приложения в один файл с расширением *.jar. Файл JAR - это архив, содержащий сопутствующие классы и графические изображения всего приложения. JAR-архив основан на обыкновенном zip-формате, использующемся повсеместно. При написании программ на Java под различные компьютерные операционные системы, программист волен сам выбирать, будет ли он распространять свое приложение в заархивированном виде или в оригинальном. Ситуация с распространением-переносом программ под мобильные телефоны радикально противоположная. Телефоны ограничены в своих ресурсах и в среднем память, отведенная под Java программу, колеблется от 30 до 80 килобайт. Эти цифры обязательно надо учитывать при создании мобильных приложений. Размер в 40-50 килобайт считается оптимальным. В связи с этим все мобильные программы обязаны распространяться в заархивированном виде, то есть в JAR-файле. Написав программу для телефона необходимо ее упаковать в jar-архив. Вернемся к примеру HelloMIDlet проекта Demo и рассмотрим на практике создание JAR-файла.
При использовании Sun ONE Studio 4 Mobile Edition создание JAR-файла происходит автоматически после компиляции и компоновки всего проекта и созданный архив помещается в рабочий каталог.
В среде J2ME Wireless Toolkit 2.1 после компиляции исходного кода необходимо произвести явную упаковку программы. Выберете в меню среды J2ME Wireless Toolkit опцию Project => Package => Create Package. На несколько секунд в рабочем окне появится небольшое диалоговое окно, показывающее процесс упаковки программы в JAR-файл. После чего в каталоге проекта Demo в папке \Ып появится файл Demo.jar. А теперь перейдите в рабочий каталог проекта Demo и найдите сформированный архив Demo.jar. Затем воспользуйтесь любым архиватором, поддерживающим zip-формат, например WinRar или WinZip и откройте файл Demo.jar. Вы увидите файл HelloMIDlet.class и папку META-INF, открыв которую обнаружите файл манифеста MANIFEST.MF.
Что происходит при создании архива? В момент упаковки приложения в JAR-файл, происходит копирование всех имеющихся откомпилированных и проверенных классов и графических изображений (если таковые имеются) и размещение их в JAR-файл, то есть происходит архивация всей программы. В рассматриваемом примере HelloMIDlet существует всего один класс, но если программа имеет большое количество классов, то все они помещаются в JAR-файл. Также происходит копирование файла манифеста MANIFEST.MF в папку META-INF. После упаковки в рабочем каталоге приложения будут находиться два файла с расширением JAR и JAD и именно в таком виде можно перенести программу в мобильный телефон посредством Интернета или компьютера связанного с мобильным телефоном любым из способов. Все приложения и игры, написанные на Java 2 ME, распространяются именно таким образом. Файл с расширением JAR содержит упакованную программу, а файл с расширением JAD описывает содержимое JAR-файла. При загрузке программ в телефон необходимо указывать путь к JAD файлу, то есть дескриптору приложения и на основании атрибутов JAD-файла происходит работа Java программы. Единственное исключение - это телефоны марки Siemens. При загрузке программ в телефон этой марки нужно указывать путь к JAR-файлу, о чем подробно будет рассказано в следующей главе, в которой будет рассматриваться программное обеспечение, поставляемое производителями мобильных телефонов для эмуляции работы мобильных телефонов различных моделей.
Файл манифеста
Файл манифеста MANIFEST.MF описывает возможные атрибуты создаваемого приложения. Откройте файл манифеста программы HelloMIDlet с помощью любого текстового редактора, например блокнота и вы увидите следующие строки:
MIDlet-1: Demo, Demo.png, HelloMIDlet MIDlet-Name: Demo MIDlet-Vendor: Unknown MIDlet-Version: 1.0 MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0
Эти строки описывают атрибуты приложения. При создании проекта с J2ME Wireless Toolkit в разделе 3.3.2 этой главы упоминалось о диалоговом окне Settings for project "Demo" изображенном на рис. 3.26. Это окно разделено на семь вкладок, в каждой из которых указываются различные атрибуты создаваемого приложения. На основе заданных атрибутов в диалоговом окне Settings for project "Demo", и происходит генерация файла манифеста, а так же JAD-файла.
Компиляция и запуск программ в SUN ONE Studio Mobile Edition
В результате всех вышеперечисленных действий вы получили код простого примера HelloMIDlet выводящего на экран телефона информационную надпись Test string. Но сначала необходимо откомпилировать и собрать программу. Для компиляции исходного кода выберете в меню команду Build => Compile или используйте "горячую" клавишу F9. Откомпилировав рассматриваемый пример, произведите компоновку всего проекта путем выбора команды из меню Build => Build или нажмите клавишу F11. После этих действий у вас появится возможность запуска созданной программы на эмуляторе телефона предоставляемого средой программирования SUN ONE Studio 4 Mobile Edition. Для этого в меню выберете команду Debug => Start или воспользуйтесь сочетанием клавиш Alt+F5. После запуска откомпилированной и скомпонованной программы на экране появится эмулятор телефона изображенный на рис. 3.19.
Рис. 3.19. Эмулятор телефона, демонстрирующий работу примера HelloMIDIet
Эмуляторы телефона, существующие в составе SUN ONE Studio 4 Mobile Edition, представлены встроенной средой программирования J2ME Wireless Toolkit 1.0. Имеется несколько эмуляторов мобильных устройств:
Чтобы подключить любой эмулятор из имеющегося списка для тестирования разработанной программы, необходимо выбрать вкладку Выполнение в окне Explorer, нажав на футуристический ключ с левой стороны каталога Device Emulator Registry, раскрыв тем самым ветку дерева этого каталога, показанную на рис. 3.20.
Рис. 3.20. Вкладка Выполнение Окна Explorer
Для того чтобы посмотреть доступные эмуляторы, откройте подкаталог Installed Emulators каталога Device Emulator Registry, нажав на ключик с левой стороны подкаталога. Раскрыв подкаталог Installed Emulators, вы увидите вложенную папку J2ME Wireless Toolkit 1.0, содержащую выше перечисленные в этом разделе эмуляторы. Для того чтобы выбрать эмулятор из папки J2ME Wireless Toolkit 1.0, щелкните правой кнопкой мыши на необходимом эмуляторе, например Motorola_j85s и в появившемся меню выберете команду Set As Default, назначив этот эмулятор текущим для данного проекта. Чтобы протестировать созданную программу на новом эмуляторе, запустите программу снова, выбрав в меню команду Debug => Start или используйте сочетание клавиш Alt+F5. На рис. 3.21 изображен эмулятор телефона i85s фирмы Motorola.
Рис. 3.21. Эмулятор телефона i85s
Впоследствии при установке эмуляторов и средств программирования сторонних производителей, можно подключать новые эмуляторы в инструментарий SUN ONE Studio 4 Mobile Edition. Для этого необходимо выбрать вкладку Выполнение в окне Explorer и нажать на ключ с левой стороны каталога Device Emulator Registry раскрыв ветку дерева этого каталога и правой кнопкой мыши щелкнуть на подкаталоге Installed Emulators. В появившемся меню выберете команду Add emulators. Затем появится диалоговое окно Select emulator installation directory, где нужно указать директорию, в которой установлен необходимый эмулятор, и нажать на кнопку Add. Некоторые производители телефонов позаботились об интеграции своих программных продуктов в среду SUN ONE Studio 4 Mobile Edition и на начальном этапе установке этих средств, можно указать, желаете ли вы встроить устанавливаемую программу в SUN ONE Studio 4 Mobile Edition или нет. В следующей главе будут рассматриваться множество программ от различных производителей, где мы обязательно рассмотрим возможность добавления эмуляторов в среду программирования SUN ONE Studio 4 Mobile Edition.
Компиляция и запуск программы в JE Wireless Toolkit
В качестве демонстрационного примера мы используем проект Demo, созданный автоматически SUN ONE Studio 4 Mobile Edition в разделе 3.2.3. Найдите исходный код HelloMIDlet проекта Demo в директории, которую вы задали для размещения программ в SUN ONE Studio 4 Mobile Edition или возьмите код HelloMIDlet с компакт диска в папке \Code\ HelloMIDlet, поместите его в директорию C:\WTK21\apps\Demo\src. Затем нажмите кнопку Build на панели инструментов для компиляции и компоновки всего проекта. В рабочее окно J2ME Wireless Toolkit 2.1, добавятся две строчки:
Building "Demo" Build complete
Здесь я, конечно, исключаю возможность появления ошибок при компиляции, но в реальном программировании приложений без этого не обойтись, программист где-нибудь да забудет поставить точку с запятой. После компиляции и компоновки проекта, нажмите кнопку Run, и на экране появится эмулятор по умолчанию DefaultColorPhone, предоставляемый J2ME Wireless Toolkit 2.1 и изображенный на рис. 3.28.
Рис. 3.28. Эмулятор телефона DefaultColorPhone
На экран эмулятора будет выведено имя проекта, нажав на клавишу эмулятора Select или Launch, вы попадете в рабочий цикл программы, и на экране эмулятора появится надпись Test string. Нажав на клавишу Exit можно выйти из приложения. По окончанию работы эмулятора, в консоли рабочего окна J2ME Wireless Toolkit 2.1, появятся примерно следующие надписи:
Running with storage root DefaultColorPhone Execution completed. 493084 bytecodes executed 57 thread switches 487 classes in the system (including system classes) 2844 dynamic objects allocated (92068 byte,s) 2 garbage collections (61976 bytes collected)
Это строки информационного характера, которые знакомят вас 6 произошедшими процессами в момент работы приложения. Для того чтобы протестировать созданную программу на других телефонных эмуляторах, необходимо в поле Device среды разработки приложений J2ME Wireless Toolkit 2.1, выбрать из списка нужный эмулятор. В составе J2ME Wireless Toolkit 2.1 имеются следующие эмуляторы телефонов:
Также существует возможность интеграции телефонных эмуляторов, сторонних производителей, о чем будет рассказано в следующей главе.
Настройка SUN ONE Studio Mobile Edition
После установки среды программирования SUN ONE Studio 4 Mobile Edition на рабочем столе появится иконка быстрого старта, При первом вызове инстру ментария SUN ONE Studio 4 Mobile Edition, необходимо настроить некоторые параметры. В первом появившемся окне, изображенном на рис. 3.4 надо выбрал директорию, где будет располагаться ваш рабочий каталог, содержащий исходные коды создаваемых программ.
Рис. 3.4. Выбор рабочей директории
Выберите любой устраивающий вас каталог, или создайте новый и нажмите кнопку Next. Следующее окно, показанное на рис. 3.5, предложит сохранить настройки от предыдущих версий.
Рис. 3.5. Окно Setting Import Wizard
Если у вас были установлены ранние версии SUN ONE Studio, воспользуйтесь этим мастером, если нет, нажмите кнопку Finish. В cледующем появившемся окне, показанном на рис. 3.6, будет предложено сконфигурировать установленную среду программирования при помощи мастера конфигурации.
Рис. 3. 6. Окно Setup Wizard
Настройка с помощью мастера Setup Wizard происходит в три этапа. На первом этапе, в окне, показанном на рис. 3.6, можно установить режим отображения инструментария, выбрать web-браузер, а также по необходимости задать используемый прокси сервер (Proxy Server). Задайте необходимые настройки и нажмите кнопку Next. Следующее диалоговое окно изображенное на рис. 3.7, показывает перечень инсталлируемых модулей.
Рис. 3.7. Инсталлируемые модули
Настройки по умолчанию в этом окне целесообразно оставить без изменений. Далее, нажав кнопку Next, вы попадете в последнее диалоговое окно Update Center, изображенное на рис. 3.8, с помощью которого можно обновить установленные компоненты через Интернет.
Рис. 3.8. Окно Update Center
Если вы имеете подключение в Интернет, то можно обновить некоторые из компонентов, процедура абсолютно бесплатна. Для отказа от обновления нажмите кнопку Finish. После чего перед вами появиться рабочая поверхность SUN ONE Studio 4 Mobile Edition, а на ее фоне окно Registration Wizard, показанное на рис. 3.9. С помощью этого окна необходимо зарегистрировать установленный продукт на сайте производителя.
Рис. 3.9. Окно Registration Wizard
Рекомендую вам зарегистрировать этот инструментарий, тем более что это бесплатно и в будущем может принести вам немалую пользу, например обновление установленных компонентов. После регистрации вы попадете непосредственно в главное окно SUN ONE Studio 4 Mobile Edition, где перед вами появится диалоговое окно Welcome SUN ONE Studio 4 update 1, Mobile Edition, показанное на рис. ЗЛО, благодаря которому можно создать проект или открыть необходимый файл.
Рис. 3.10. Окно Welcome SUN ONE Studio 4 update 1, Mobile Edition
С помощью окна Welcome можно осуществить так называемый быстрый старт, выбрав необходимое действие. По размеру окно довольнo таки большое и разделено на две части. В его нижней области имеется возможность отключения появления этого окна при открытии среды программирования SUN ONE Studio 4 Mobile Edition. Произведя таким образом настройку инструментария при первом старте, вы получите все рабочее окно SUN ONE Studio 4 Mobile Edition, изображенное на рис. 3.11.
Рис. 3.11. Рабочее окно SUN ONE Studio 4 Mobile Edition
Главное окно инструментария выполнено в лучших традициях подобных средств программирования, предоставляя большое количество разнообразных панелей инструментов, меню, кнопок, текстовых полей, а также окно Explorer (обозреватель), которое находится с левой стороны рабочей поверхности SUN ONE Studio 4 Mobile Edition. Окно Explorer состоит из трех вкладок: Файловые системы, Выполнение и Javadoc. Они находятся в нижней части окна Explorer.
Вкладка Файловые системы дает возможность подключить к проекту рабочую директорию, где, впоследствии, будут находиться исходные коды, то есть произвести монтаж файловой системы. Там же происходит подключение архивов Archive (JAR, Zip), о чем подробно будет рассказано в разделе 3.2.2.
Во вкладке Выполнение можно подключить телефонные эмуляторы и следить за процессами отладки и выполнения программы.
Вкладка Javadoc содержит сгенерированную документацию к проекту в виде HTML страниц.
Линейка меню, в верхней части среды программирования SUN ONE Studio 4 Mobile Edition, содержит множество команд. Щелкнув мышью на одном из названий, откроется выпадающее меню, содержащее список новых команд. Некоторые команды имеют выпадающие подменю. Рассмотрим ряд основных команд среды программирования SUN ONE Studio 4 Mobile Edition. Напротив каждой из команд в скобках находятся названия "горячих клавиш" для быстрой работы с системой.
Меню File
Меню Edit
Меню View
Меню Project
Меню Build
Меню Debug
Меню Help
Создание приложений в SUN ONE Studio Mobile Edition
Завершив создание проекта, можно переходить к написанию кода приложения. Для этого перейдите на закладку созданного проекта Demo, в окне Explorer и выберете команду меню File => New File, либ9 воспользуйтесь горячими клавишами Ctrl+N. На экране появится окно New Wizard, представленное на рис. 3.16, где происходит выбор шаблона создаваемого приложения.
Рис. 3.16. Окно New Wizard
В качестве создаваемой демонстрационной программы произведем выбор шаблона HelloMIDlet, который формирует код простой программы, имеющей название мидлет и позиционирующейся в Java 2 ME как приложение, написанное специально для мобильного устройства. В главе 5 будет дано подробное объяснение сути мидлета. Нажав на кнопку Next, вы попадете в следующее окно New Wizard - HelloMIDlet, где необходимо указать будущую директорию нахождения мидлета и задать имя пакету, либо воспользоваться стандартным пакетом, предоставляемым по умолчанию. На рис. 3.17 показано окно New Wizard -HelloMIDlet с выбранной директорией и пакетом по умолчанию.
Рис. 3.17. Окно New Wizard - HelloMIDIet
Указав пакет и выбрав директорию, нажмите на кнопку Finish. После этого будет автоматически сгенерирован простейший код примера HelloMIDlet проекта Demo, который появится в текстовом редакторе Source Editor, с правой стороны в свободном до этого времени пространстве главного окна среды SUN ONE Studio 4 Mobile Edition, представленного на рис. 3.18.
Рис. 3.18. Окно проекта Demo
Работа с кодом в текстовом редакторе Source Editor, осуществляется обычным образом, характерным практически для всех сред программирования.
Создание проекта в JE Wireless Toolkit
Рабочее окно среды J2ME Wireless Toolkit, выглядит на много проще чем SUN ONE Studio 4 Mobile Edition. Для создания нового проекта нажмите на панели инструментов кнопку New Project, либо выберете в меню команду File => New Project. В появившемся окне New Project, показанном на рис. 3.25, в поле Project Name дайте имя всему проекту, например Demo и в поле MIDlet Class Name, задайте название основному классу мидлета приложения.
Рис. 3.25. Окно New Project
Чтобы было понятно, о чем идет речь, забегая вперед, поясню: мидлет в Java 2 ME - это вся программа в целом, а с основного класса мидлета начинается работа всего приложения. Поэтому названия данное в поле MIDlet Class Name должно соответствовать названию основного класса мидлета, нельзя не задавать название основному классу мидлет либо использовать несуществующее название, иначе при компиляции возникнет масса ошибок. В главе 5, вы найдете более подробное объяснение модели работы и построения программ в Java 2 ME. При знакомстве с инструментарием SUN ONE Studio 4 Mobile Edition, был создан проект Demo, основной класс мидлета имел название HelloMIDlet; воспользуемся этим исходным кодом и дадим название классу мидлета HelloMIDlet в поле MIDlet Class Name, и нажмем после этого кнопку Create Project. Вслед за этим появится диалоговое окно Settings for project "Demo", показанное на рис. 3.26, где нужно произвести ряд установок для настройки нового проекта.
Диалоговое окно Settings for project "Demo" разделено на семь вкладок, в каждой из которых можно задавать различные установки для создаваемого проекта. Первая вкладка API Selection, изображенная на рис. 3.26, позволяет задавать конфигурацию и профиль создаваемого проекта. И здесь необходимо быть аккуратным: если вы планируете разрабатывать приложение только под профиль MIDP 1.0, то в поле Target Platform (выбор платформы), нужно указать соответствующий профиль.
Рис. 3.26. Диалоговое окно Settings for project "Demo"
Вторая вкладка Required (Атрибуты), изображенная на рис. 3.27, содержит мета информацию создаваемой программы в виде семи различных значений, которые можно устанавливать должным образом.
Вся заданная информация для мидлета будет находиться в JAD файле. По ходу работы над проектом имеется возможность изменения заданных атрибутов с помощью кнопки Settings на панели инструментов рабочего окна J2ME Wireless Toolkit 2.1. Подробно о файлах JAD и JAR будет рассказано в конце этой главы' в разделе 3.4. Все оставшиеся вкладки имеют различные дополнительные свойства и заданные на этих вкладках значения почти всегда можно оставлять по умолчанию. Нажав на, кнопку ОК после всех установок, в окне Settings for project "Demo" будет создан новый проект Demo.
Рис. 3.27. Вклакда Required
Среда программирования J2ME Wireless Toolkit 2.1, к сожалению, не имеет своего текстового редактора. Для создания исходного кода приложения вам необходимо написать код программы в любом удобном текстовом редакторе и поместить этот код в директории J2ME Wireless Toolkit 2.1. Как это делается? В тот момент, когда вы нажмете на кнопку ОК, в окне Settings for project -"Demo" будет создан новый проект, в нашем случае это Demo. А в консоли главного окна среды программирования J2ME Wireless Toolkit 2.1 появятся примерно следующие строки:
Creating project "Demo" Place Java source files in "C:\WTK21\apps\Demo\src" Place application resource files in "C:\WTK21\apps\Demo\res" Place application library files in "C:\WTK21\apps\Demo\lib"
Из этих строк следует, что файлы исходного кода (это, как правило, файлы с расширением *.java), необходимо поместить в директорию C:\WTK21\apps\Demo\src. Файлы ресурсов, иконки, изображения и так далее помещаются в директорию C:\WTK21\apps\Demo\res; и файлы библиотек, если таковые используются в C:\WTK21\apps\Demo\lib. То есть, создав исходный код приложения в текстовом редакторе, просто сохраните код в директорию: C:\WTK21\apps\Demo\src. Кроме трех перечисленных папок, созданных в рабочем каталоге проекта Demo, будут автоматически сгенерированно ещё четыре папки:
Создание проекта в SUN ONE Studio Mobile Edition
Для создания проекту в среде SUN ONE Studio 4 Mobile Edition, необходимо выбрать в меню команду Project => Project Manager, в появившемся окне менеджера проектов изображенного на рис. 3.12, нажмите кнопку New.
Рис. 3.12. Окно менеджера проектов
Вместо окна менеджера проектов появится небольшое диалоговое окно Create New Project, где в поле Project Name необходимо задать имя проекту, например Demo и нажать на кнопку ОК. После этих действий на экране появится окно конфигурации созданного проекта показанное на рис. 3.13.
В окне конфигуратора проектов есть два пункта: Java 2 Standard Edition (J2SE) и Mobile Information Device Profile (CLDC\MIDP), выполненные в виде списка выбираемых элементов. Выбрав один из двух пунктов можно сконфигурировать проект для создания стандартной программы на Java 2 SE, либо приложение для мобильных телефонов если избрать пункт Mobile Information Device Profile (CLDC\MIDP). Выбираем пункт для создания мобильных приложений
Рис. 3.13. Окно конфигуратора проекта
и нажимаем кнопку Finish. После чего в нижней части окна Explorer, к вкладкам Файловые системы, Выполнение и Javadoc, добавится еще одна вкладка Project Demo. Затем необходимо произвести монтирование файловой системы для сконфигурированного проекта. В нижней части окна Explorer, перейдите на вкладку Файловые системы и в появившемся окне нажмите правой кнопкой мыши на надписи Файловые системы. В ответ на эти действия появится череда выпадающих меню, выберите команду Mount => Archive (JAR, Zip), изображенную на рис. 3.14.
Рис.3.14. Вкладка Файловые системы
Выбрав команду Archive (JAR, Zip), вы перейдете к окну New Wizard -Archive (JAR, Zip), с помощью которого производится монтаж необходимой для проекта библиотеки Java API. Все библиотеки скомпонованы в виде архивов, например библиотека для профиля MIDP 1.0, содержится в архиве midpapi.zip. Ситуация здесь несколько запутанная. Как уже говорилось в состав инструментария SUN ONE Studio 4 Mobile Edition входит также среда J2ME Wireless Toolkit версии 1.0.4 01, содержащая архив API для профиля MIDP 1.0. На рис. 3.15 показано окно New Wizard -Archive (JAR, Zip) и подключаемый архив API, находящийся в папке lib среды J2ME Wireless Toolkit 1.0.
Рис. 3.15. Окно New Wizard - Archive (JAR, Zip)
При установке более поздней версии этой интегрированной среды вы сможете подключать API и для профиля МШР 2.0, выбрав соответствующий файл из директории, в которую была установлена среда J2ME Wireless Toolkit 2.1 более поздней версии. Также существует возможность Выбора и других API, предоставляемых конкретным производителем телефонов, в том случае, если вы желаете использовать библиотеку сторонних производителей. В следующей главе будет рассмотрена установка и настройка различных телефонных эмуляторов и программного обеспечения для программирования телефонов разнообразных марок.
После монтирования файловой системы., необходимо также произвести монтаж директории, где будет содержаться исходный код созданного проекта. Монтаж директории происходит по той же схеме, что и монтаж файловой системы, но в выпадающем меню нужно выбрать команду Mount => Local Directory и в появившемся окне New Wizard - Local Directory указать место, где будет храниться исходный код программы, поле чего нажмите кнопку Finish. Создав рабочий каталог для приложения, его необходимо добавить в проект. Нажмите правой кнопкой мыши на только что добавленной директории во вкладке Файловые системы окна Explorer и в появившемся меню выберете команду Tools => Add to Project. Для каждого нового создаваемого проекта, необходимо произвести все выше описанные действия из раздела 3.2.2.
Среда программирования JE Wireless Toolkit
Программный продукт J2ME Wireless Toolkit 2.1 компании Sun Microsystems распространяется бесплатно и представляет упрощенную среду программирования. Механизм работы J2ME Wireless Toolkit 2.1 очень прост: вы создаете проект, размещаете файлы исходного кода в директории J2ME Wireless Toolkit 2.1 и компилируете весь проект. Файлы исходного кода могут быть написаны в любом текстовом редакторе. Потом запускаете готовое приложение на эмуляторах доступных в этой среде программирования и тестируете созданную программу.
Среда программирования SUN ONE Studio Mobile Edition
В директории \SDK находится файл ffj_me_win32 - это программа установки интегрированной среды разработки SUN ONE Studio 4 Mobile Edition. После двойного нажатия левой кнопки мыши на этом файле, вы увидите окно с приветствием, нажав на кнопку Next, вы попадете в окошко с лицензионным соглашением. Ознакомившись с соглашением и нажав на кнопку Next, на экране монитора появится диалоговое окно SUN ONE Studio 4 update 1, Mobile Edition Setup, изображенное на рис. 3.2.
Рис. 3.2. Окно SUN ONE Studio 4 update 1, Mobile Edition Setup
В этом и следующем окне необходимо определиться с директорией, в которой будет размещаться устанавливаемый инструментарий, после чего появится диалоговое окно, показанное на рис. 3.3, где перечисляются компоненты установки. Путь, задающий директорию для установки SUN ONE Studio 4 Mobile Edition не должен содержать пробелов.
Окно выбора компонентов содержит элементы для установки. Как видно из рис. 3.3 инсталлируется не только J2ME Wireless Toolkit, но и Java 2iPlatform Micro Edition, которая также может поставляться отдельно и лежит на компакт-диске в каталоге \SDK (в том случае если вы предпочитаете работать с командной строкой).
Рис. 3.3. Окно выбора компонентов к установке
Два последующих окна носят скорее информационный характер, просто на жмите кнопку Next и мастер установки начнет свою работу по инсталляции cреды программирования SUN ONE Studio 4 Mobile Edition на компьютер.
Упаковка программ
При создании проекта и последующей компиляции исходного кода, у вас появятся два файла: JAD-файл и файл манифеста. Если вы работаете с Sun ONE Studio, то оба файла будут находиться в рабочем каталоге проекта. Если вы используете среду программирования J2ME Wireless Toolkit, то JAD-файл и файл манифеста будут помещены в папку \bin рабочего каталога приложения. Давайте отталкиваться от созданного в разделах 3.2.3 и 3.3.2 проекта Demo и мидлета HellpMIDlet. В этом случае в соответствующих директориях двух средах программирования будут находиться два файла: Demo.jad и MANIFEST.MF.
Установка Java SDK SE
Двойной щелчок левой кнопки мышки на файле j2sdk-1_4_2_03-windows-i586-p из каталога \SDK, приведет к распаковке архива. Далее появится окно с лицензионным соглашением, нажав на кнопку Next, вы попадете в окно Java 2 SDK SE vl.4.2_03 - Custom Setup, изображенное на рис. 3.1.
В этом диалоговом окне вам будет предложено выбрать каталог и тип установки. Нам нужны все компоненты, поэтому нажмите кнопку Next. В следующем окне вам необходимо выбрать браузер для интеграции Java, остановите свой выбор на необходимом и подтвердите свои действия, после чего начнется процесс установки, в конце которого вам предложат перезагрузить компьютер. После установки Java 2 SDK, можно приступать к инсталляции SUN ONE Studio 4 Mobile Edition и J2ME Wireless Toolkit.
Сразу хотелось бы остановиться на некоторых особенностях возникающих при инсталляции. Обе среды программирования независимы друг от друга, но в составе, а точнее в комплекте с SUN ONE Studio 4 Mobile Edition, входит J2ME Wireless Toolkit версии 1.0.4 01, но изданный момент уже имеется J2ME Wireless Toolkit версии 2.1. Такая путаница обусловлена как раз тем, что оба продукта независимы друг от друга и развиваются параллельно. Начнем установку с более мощной среды SUN ONE Studio 4 Mobile Edition.
Рис. 3.1. Окно Java 2 SDK, SE v1.4.2_03 - Custom Setup
Установка JE Wireless Toolkit
В папке \SDK находится файл j2me_wireless_toolkit-2_1-windows. Двойной щелчок на этом файле приведет вас в программу установки среды программирования J2МЕ Wireless Toolkit. В первом появившемся окне программы установки Java Virtual Machine Location, показанном на рис. 3.22, необходимо указать путь в директорию, где у вас установлена виртуальная Java машина.
Рис. 3.22. Окно программы установки Java Virtual Machine Location
Если при установке пакета Java 2 SDK SE, вы не изменяли директорию для виртуальной машины, то оставьте прописанный путь, указанный в окне программы установки Java Virtual Machine Location и нажмите кнопку Next. В следующем окне Choose Destination Location, изображенном на рис. 3.23, нужно выбрать место для установки среды программирования J2ME Wireless Toolkit 2.1.
Рис. 3.23. Окно Choose Destination Location
При задании директории нельзя прописывать путь с пробелами, а лучше оставить директорию по умолчанию, выбранную программой установки, иначе в последствии у вас возникнет масса проблем при компиляции исходных кодов. Нажав на кнопку Next в окне Choose Destination Location, подождите конца установки среды программирования J2ME Wireless Toolkit 2.1.
После установки программы, зайдите в меню ПУСК => Все программы => J2ME Wireless Toolkit 2.1 => KToolbar и у вас на экране появится рабочее окно J2ME Wireless Toolkit, показанное на рис. 3.24, где и происходит основная работа над проектами по созданию приложений для мобильных устройств.
Рис. 3.24. Рабочее окно J2ME Wireless Toolkit
Линейка меню среды программирования J2ME Wireless Toolkit, содержит четыре команды, щелкните мышей на названии любой из команд и вы откроете выпадающее меню. Каждое из выпадающих меню содержит ряд команд, разберем основные из них.
Меню File
Меню Edit
Меню Project
Дополнительные пакеты Nokia
В профиле MIDP 1.0 не доступна работа со звуком и рядом других возможностей, поэтому каждый из производителей телефонов поставляет свои пакеты с дополнительными классами. Для телефонов Nokia доступно два дополнительных пакета.
По мере прочтения этой книги вам станет понятно назначение перечисленных классов.
Дополнительные пакеты Siemens
Компания Siemens имеет десять больших пакетов призванных расширить функциональность классов платформы Java 2ME. Существуют следующие пакеты:
Инструментарий Nokia Developer's Suite for JE
Перед тем как вы начнете устанавливать пакет Nokia Developer's Suite 2.2 for J2ME, позаботьтесь о получении серийного номера для этого продукта с сайта компании Nokia: http: //forum.nokia.com. На компакт-диске в папке \Nokia, находится файл nds_jme_v_2_0.zip. Распакуйте этот архив в любую удобную директорию. После распаковки архива найдите файл setup.exe и нажмите на нем два раза левой кнопкой мыши, вызвав тем самым программу установки пакета. В первом появившемся окне Welcome программы установки пакета изображенном на рис. 4.3, от вас потребуют ввода серийного номера.
Рис. 4.3. Окно Welcome программы установки пакета Nokia Developer's Suite 2.2 for J2ME
Окно Welcome программы установки содержит два поля: Forum Nokia Username - для ввода "логина" под которым вы зарегистрированы на сайте компании Nokia и поле Product Serial Number где необходимо ввести серийный номер полученный по электронной почте, Если вы еще не заказывали серийный номер для устанавливаемого пакета, но являетесь зарегистрированным пользователем, то можно указать только свой логин в поле Forum Nokia Username и нажать на кнопку Next. После чего произойдет соединение с сайтом forum.nokia.com, где вы сможете заказать серийный номер. После ввода серийного номера и логина, нажмите кнопку Next для перехода в окно Choose install set, изображенное на рис. 4.4.
Рис. 4.4. Окно Choose install set программы установки пакета Nokia Developer's Suite 2.2 for J2ME
Окно программы установки Choose install set имеет три варианта выбора для последующей установки пакета Nokia Developer's Suite 2.0 for J2ME:
Выберите необходимый вариант установки или комбинацию вариантов, нажав на кнопку возле выбранной надписи, и перейдите в следующее окно после нажатия кнопки Next. Рекомендую выбрать Standard installation и интеграцию в установленную на вашем компьютере среду программирования.
В предыдущей главе были рассмотрены средства программирования от компании Sun Microsystems, поэтому в дальнейшем при установке пакетов всех имеющихся производителей мы будем придерживаться программных средств компании Sun Microsystems. После того, как вы нажмете кнопку Next в окне Choose install set, вы попадете в окно Select the installation directory of your Sun. IDE, показанное на рис. 4.5.
Рис. 4.5. Окно Select the installation directory of your Sun IDE
Убедитесь, что в поле Please choose a directory прописан правильный путь в директорию с инструментарием Sun ONE Studio 4 Mobile Edition и нажмите кнопку Next. Дождитесь конца инсталляции, и не забудьте после всех действий перезагрузить компьютер.
После удачной установки запустите программу из меню ПУСК => Все программы => Nokia Developer Tools => Nokia Developer's Suite2.0 for J2ME => Run as a Standalone и вам откроется основное окно программы, Nokia Developer's Suite2.0 for J2ME, изображенное на рис. 4.6.
Рис. 4.6. Окно Nokia Developer's Suite for the Java™ 2 Platform, Micro Edition
С левой стороны основного окна программы имеется вкладка расположенная вертикально вдоль всего экрана дисплея. Эта вкладка состоит из шести больших интерактивных кнопок:
Нажав на кнопку Start Emulators, вам откроется окно, изображенное на рис. 4.7.
Рис. 4.7. Окно выбора телефонных эмуляторов
В состав пакета Nokia Developer's Suite2.0, входит два эмулятора - это эмулятор телефона Nokia 7210 сороковой серии и эмулятор телефонов шестидесятой серии, который представляет некий собирательный образ телефонов этой серии. Для того чтобы запустить на эмуляторах, приложение, необходимо в поле Application, указать путь до JAR-файла, а в поле Select Emulators, выбрать телефонный эмулятор с помощью галочки с левой стороны названия эмулятора. Здесь нет ограничений и можно выбрать сразу оба эмулятора. После чего нажмите на кнопку Emulate, и на экране появится выбранный эмулятор телефона. На рис. 4.8 показан эмулятор Nokia 7210 сороковой серии показывающий работу проекта Demo, созданного в главе 3 и выводящего на экран строку текста Test string.
В окне Nokia Developer's Suite for the Java™ 2 Platform, Micro Edition, где перечислены доступные эмуляторы, с правой стороны имеется кнопка Configure, нажав на эту кнопку, вы попадете в окно, в котором можно задать ряд установок, осуществляющих конфигурацию доступных на данный момент эмуляторов. В частности в поле Select language, можно выбрать язык для меню телефона, а в поле Emulators, добавить или удалить эмуляторы телефонов с помощью кнопок Add (добавить) и Remove (удалить).
Если при инсталляции пакета Nokia Developer's Sui-te2.0 вы указали интеграцию с визуальной средой программирования Sun ONE Studio в окне Choose install показанное на рис 4.4, то при работе с Sun ONE Studio 4 Mobile Edition, вы сможете запускать соответствующие эмуляторы. Для этого необходимо в Sun ONE Studio 4 Mobile Edition выбрать команду в меню Tools =>Nokia => Developer's Suite for J2ME => Start Emulators, после чего появится диалоговое окно Start Emulators. В этом окне нужно указать путь к приложению в поле Application и в поле Select Emulators выбрать необходимый эмулятор телефона Nokia.
Пакета Nokia Developer's Suite2.0 представляет собой некую базу, в которую в последствии встраивается основная часть имеющихся телефонных эмуляторов и SDK компании Nokia. Проинсталлируйте все имеющиеся SDK находящиеся на компакт-диске в папке \Nokia самостоятельно, теперь этот процесс не должен вызвать никаких трудностей.
Рис 4.8. Телефонный эмулятор Nokia 7210
Пакет Siemens Mobility Toolkit
B папке \Siemens находится файл smtk_0_13_2_59, нажав два раза левой кнопкой мыши на этом файле, вы запустите программу установки пакета Siemens Mobility Toolkit. Установка инструментария достаточно проста и вам необходимо в появляющихся окнах, лишь задавать нужные директории для установки пакета. Сам пакет не содержит телефонных эмуляторов, но является основным и первым пакетом, который необходимо установить на компьютер. Все последующие программные средства компания Siemens, а это телефонные эмуляторы и всевозможная документация, встраиваются в пакет Siemens Mobility Toolkit. На рис. 4.9 показаны все имеющиеся эмуляторы.
Рис 4.9. Эмуляторы телефонов Siemens
Эмуляторы, находящиеся на компакт-диске в папке \Siemens, устанавливаются автоматически встраиваясь в пакет Siemens Mobility Toolkit. После установки всех имеющихся программных средств, на рабочем столе компьютера должны появится два ярлыка: SMTK Emulator Launcher и SMTK Manager. Запустив утилиту SMTK Manager, вы увидите небольшое диалоговое окно, изображенное на рис. 4.9.
Рис. 4.10. Диалоговое окно SMTK Manager
Диалоговое окно SMTK Manager состоит из трех вкладок:
Установленные телефонные эмуляторы фирмы Siemens вы также можете подключить в среду программирования SUN ONE Studio 4 Mobile Edition. Для этого в среде программирования SUN ONE Studio 4 Mobile Edition выберете вкладку Выполнение в окне Explorer и перейдите по каталогам Device Emulator => Registry Installed Emulators, а в появившемся меню изберете команду Add emulators. В следующем диалоговом окне Select emulator installation directory укажите директорию, в которой установлены эмуляторы телефонов компании Siemens. Если вы установили программу Siemens Mobility Toolkit по умолчанию в корневой каталог то, например путь к телефонному эмулятору М55, будет таким: C:\siemens\SMTK\emulators\M55.
Второй ярлык появившейся на рабочем столе запускает непосредственно программу SMTK Emulator Launcher. После запуска программы появится небольшое диалоговое окно, показанное на рис. 4.11.
Рис. 4.11. Диалоговое окно SMTK to Launcher
В диалоговом окне SMTK to Launcher, можно выбрать телефонный эмулятор необходимый вам для работы. После этого появится -эмулятор телефона и окно команд (commands), изображенное на рис. 4.12.
В окне Commands имеется ряд команд, нас интересует команда Start Java Application с помощью которой можно запустить упакованную Java программу. После двойного щелчка на команде Start Java Application, появится диалоговое окно, в котором нужно указать путь к JAR файлу. Замете, что в телефонных эмуляторах Nokia указывался путь к JAD файлу, а в эмуляторах Siemens к JAR файлу. Выбрав JAR-файл нажмите на кнопку ОК и произойдет запуск выбранного приложения на эмуляторе.
Рис. 4.12. Окно Commands
Программа Nokia PC Suite
В качестве приятного бонуса в папке \Nokia на компакт-диске к книге вы сможете также обнаружить бесплатно распространяемую программу Nokia PC Suite 5.1, обеспечивающую связь телефона с компьютером и содержащую в своем составе большое количество разнообразных утилит.
Программа Nokia PC Suite 5.1 русифицирована и вы всегда сможете обратиться к контекстной справке, если возникнут осложнения с использованием одной из утилит.
Программа Siemens Date Suite
В папке \Siemens можно найти программу Siemens Date Suite обеспечивающую связь телефона с компьютером, которая состоит из следующих утилит:
Программное обеспечение телефонов Motorola
Программное обеспечение фирмы Motorola находится в папке \Motorola и состоит всего из одной, но довольно функциональной программы. После ее установки на рабочем столе появится ярлык Motorola Lanchpad. Запустив программу Motorola Lanchpad, вы увидите диалоговое окно, показанное на рис. 4.14.
Рис. 4.14. Программа Motorola Lanchpad for J2ME
В диалоговом окне Motorola Lanchpad for J2ME в поле Handset представлены все имеющиеся телефоны с поддержкой Java 2 ME в виде эмуляторов. Надо сказать, что количество мобильных устройств, где используется Java технология достаточно велико, посмотрите на список доступных моделей:
Выберите из выпадающего списка в поле Handset телефонный эмулятор и далее укажите путь к приложению в поле Application. Путь можно задать вручную, а можно воспользоваться кнопкой Browse, выбрав директорию нахождения JAD и JAR файла, то есть программы написанной на Java. Путь нужно указывать к JAD-файлу. Затем нажмите на кнопку Lanch, на экране монитора появится выбранный телефонный эмулятор, а программа Motorola Lanchpad for J2ME автоматически закроется. Для того чтобы программа Motorola Lanchpad for J2ME не закрывалась каждый раз при запуске нового эмулятора, нужно поставит галочку в поле Keep Launchpad open after MIDlet Launch, после того как вы откроете программу Motorola Lanchpad for J2ME.
Программное обеспечение телефонов Nokia
Компания Nokia имеет, пожалуй, самое впечатляющее количество программного обеспечения. Многие программы даже не поместились на компакт-диск! Если вы не нашли на диске необходимые вам средства программирования, то посетите сайт компании Nokia: http://forum.nokia.com. Все программное обеспечение, находящееся на компакт-диске или на сайте компании Nokia доступно бесплатно, но на основе регистрации, без которой вы не сможете установить ни один программный продукт этой компании. Поэтому первым делом необходимо посетить сайт этой компании, где, перейдя по ссылке Registration, вам будет предоставлена регистрационная форма, изображенная на рис. 4.1.
Заполняя поля регистрационной формы, запомните обязательно свой пароль и "логин" для возможности дальнейшего доступа в систему. И главное, укажите свой адрес электронной почты, на который вам будут высылаться серийные номера отдельных продуктов. Такие серийные номера даются бесплатно, но только для зарегистрированных пользователей.
Весь процесс регистрации происходит в несколько этапов. После того как вы заполните регистрационную форму, изображенную на рис. 4.1, на ваш e-mail придет письмо. Текст письма будет, естественно, на английском языке, в нем вам предложат подтвердить свои намерения в регистрации, для чего необходимо будет перейти по ссылке, имеющейся в этом письме. Перейдя по ссылке, вы попадете на страницу, регистрирующую вас и отсылающую вам еще одни послание. Это письмо будет содержать еще одну ссылку, по которой также надо будет перейти, уже для конечной регистрации в системе. Дальше на ваш домашний адрес, будет выслана бандероль с последней моделью телефона Nokia N-Gage QD (шутка). После двух писем и подтверждений регистрации вы станете зарегистрированным пользователем, и вам будут доступны любые ресурсы с сайта компании Nokia.
Рис. 4.1. Регистрационная форма
Получив доступ в систему, вы сможете заказать необходимый серийный номер, который будет выслан на ваш e-mail, указанный при регистрации. Процесс получения серийного номера очень прост. Зайдя на сайт компании Nokia: http://forum.nokia.com, с правой стороны Интернет страницы вы найдете ряд ссылок. Ссылка Tools&SDK приведет на страницу, отображающую все доступные на этот момент программные средства. Выбрав необходимый вам программный продукт, например Nokia Developer's Suite 2:0 for J2ME, вы попадете на страницу изображенную, на рис. 4.2.
На этой странице вы можете, как скачать этот продукт (в том случае если вы утеряли, подарили или продали компакт диск к книге), так и заказать серийный номер. Под большой, красочно оформленной ссылкой Download now, имеется ссылка Serial number for this product, перейдя по которой вы сможете заказать серийный номер к этому продукту. Заказ серийных номеров других программ происходит таким же образом. Ниже перечислены названия всех имеющихся программных средств компании Nokia находящихся на компакт диске в папке \Nokia:
Рис.4.2. Окно заказа серийного номера
Программная архитектура всех телефонов Nokia делится на серии платформ (Series Developer Platform): серии 40,60,80 и 90. Раньше еще существовала платформа тридцатой серии, но сейчас она объединена в сороковую серию. Запомнить какие из моделей телефонов принадлежат соответствующим сериям тяжело, но очень легко различать модели по сериям с помощью разрешения дисплея, разбив их на четыре категории:
Телефоны, принадлежащие к серии 40, не имеют полноценной операционной системы и работают на основе прошивки. Для этой серии телефонов доступно программирование приложений только на языке Java 2 ME, при условии поддержки самой технологии Java конкретной моделью телефона. Серии 60, 80 и 90 построены на операционной системе Symbian и кроме возможности программирования на языке Java, дают возможность в создании приложений на языке C++. Издательство ДМК Пресс готовит к выходу книгу по программированию мобильных телефонов на базе операционной системы Symbian.
Так как модели телефонов разделены на серии, в свою очередь все имеющиеся программные средства так же подразделены соответствующим образом. Существует большое количество SDK для всех четырех серий телефонов, а также множество отдельно настраиваемых модулей эмулирующих конкретные модели телефонов.
Прежде чем устанавливать эмуляторы телефонов Nokia, необходимо установить основной пакет Nokia Developer's Suite 2.0 for J2ME. Все телефонные эмуляторы встраиваются в этот пакет.
Программное обеспечение телефонов Samsung
В папке \Samsung найдите файл JSDKvl_0 - это программа установки. Инсталлируйте программу SamsungJSDK 1.0 на компьютер, а затем откройте установленную программу. Откроется основное окно Samsung JSDK1.0, изображенное на рис. 4.15.
Рис 4.15. Программа Samsung JSDK 1.0
Для того чтобы запустить упакованную Java программу на телефонном эмуляторе поставляемом в пакете Samsung JSDK 1.0, выберите команду File => Import MIDlet и приложение будет запущенно.
Очевидно, что телефонные эмуляторы значительно упрощают процесс разработки приложений, предоставляя разработчику универсальные средства для тестирования создаваемых программ. Представьте, какое количество денег нужно было потратить, для того чтобы приобрести несколько различных моделей телефонов. Но самое главное, пожалуй, это бесплатно распространяемое программное обеспечение, а также отсутствие дорогого лицензирования при создании программ на Java 2 ME. Любой программист из любого региона может бесплатно скачать необходимое программное обеспечение и заниматься разработкой своих собственных проектов при минимальных материальных затратах.
В главах 3 и 4 вы изучили установку, настройку, работу с интегрированными средствами программирования приложений и инструментальными средствами пяти известных производителей телефонов. Поскольку в этих главах была представлена исчерпывающая информация по созданию, компиляции и запуску приложений с использованием различных программных средств, то в дальнейшем все внимание будет сосредоточено на изучении платформы Java 2 ME. В следующих главах мы перейдем непосредственно к работе с кодом, где будет представлено для изучения большое количество интерфейсов, классов, методов из состава платформы Java 2 ME.
Программное обеспечение телефонов Siemens
Компания Siemens тоже имеет не малое количество моделей телефонов, которые поддерживают технологию Java 2 ME. Все средства программирования распространяются бесплатно, но требуют предварительной регистрации на сайте компании Siemens www.siemens-mobile.com/developer. Вы найдете следующие программы:
В качестве основного пакета выступает программа Siemens Mobility Toolkit for Java Development, в которую происходит интеграция имеющихся телефонных эмуляторов различных моделей.
Программное обеспечение телефонов Sony Ericsson
Множество телефонов компании Sony Ericsson поддерживают технологию Java 2 ME. Пакет инструментальных средств для программирования мобильных телефонов Sony Ericsson выполнен в виде одного файла и включает в себя все имеющиеся телефонные эмуляторы. Кроме того, после установки инструментария необходимо воспользоваться небольшим по размеру патчем. B папке \Sony Ericsson находится следующие бесплатно распространяемые программы:
Копания Sony Ericsson, по всей видимости, удачно сотрудничает с компанией Sun Microsystems. Весь пакет инструментальных средств Sony Ericsson J2ME SDK 2.1 основан на среде программирования J2ME Wireless Toolkit. Причем при инсталляции происходит установка сразу двух версий J2ME Wireless Toolkit. Первая версия J2ME Wireless Toolkit 1 предназначена для написания программ под профиль MIDP 1:0, а вторая версия J2ME Wireless Toolkit 1 для создания приложений под профиль MIDP 2.0. В итоге получается, что весь пакет инструментальных средств Sony Ericsson J2ME SDK 2.1 содержит полноценную среду программирования с набором телефонных эмуляторов. Работа в обеих средах программирования, идентична работе со средой J2ME Wireless Toolkit 2.1 рассмотренной в главе 3.
Установка пакета Sony Ericsson J2ME SDK 2.1 происходит просто: вы должны указать необходимую директорию для инсталляции программы и лучше, если это будет корневой каталог, не содержащий пробелов в названии папки. Единственный возникающий нюанс при инсталляции программы - это выбор устанавливаемых компонентов. На рис 4.13, изображено диалоговое окно Custom Setup.
Рис 4.13. Окно Custom Setup
В этом окне нужно выбрать среду J2ME Wireless Toolkit 1 или J2ME Wireless Toolkit 2, но если вы планируете писать программы под профиль MIDP 1.0 и MIDP 2.0 можно избрать обе среды программирования.
Среда программирования J2ME Wireless Toolkit 1 имеет эмуляторы телефонов поддерживающих создание программ под профиль MIDP 1.0, и содержит следующие модели:
Доступны и нейтральные телефонные эмуляторы, поставляемые вместе со средой программирования J2ME Wireless Toolkit:
В среде программирования J2ME Wireless Toolkit 2 доступно только три эмулятора - это:
Все три эмулятора поддерживают профиль MIDP 2.0, как и сами телефоны этих трех марок компании Sony Ericsson.
Если вы работаете в интегрированной среде программирования SUN ONE Studio 4 Mobile Edition, то можете подключить имеющиеся телефонные эмуляторы компании Sony Ericsson. В среде программирования SUN ONE Studio 4 Mobile Edition, выберите вкладку Выполнение в окне Explorer и нажмите на знак ключа с левой стороны каталога Device Emulator Registry. Раскроется ветка дерева этого каталога, выберите подкаталог Installed Emulators и в появившемся меню изберете команду Add emulators. Затем появится диалоговое окно Select emulator installation directory, где необходимо указать директорию, в которой установлены эмуляторы телефонов компании Sony Ericsson и нажать на кнопку Add. Если вы не изменяли директорию при инсталляции пакета Sony Ericsson J2ME SDK 2.1, то нужно выбрать следующий путь в диалоговом окне Select emulator installation directory для J2ME Wireless Toolkit 1: C:\SonyEricsson\J2ME_SDK\ PC_Emulation\WTKl. И путь для J2ME Wireless Toolkit 2: C:\SonyEricsson\ J2ME_SDK\PC_Emulation\WTK2. Затем выбираете необходимый эмулятор из списка и тестируете создаваемое приложение на телефонах Sony Ericsson. Также в папке \Sony Ericsson находится программа Sony Ericsson Communication Suite осуществляющая связь телефонов Sony Ericsson с компьютером.
Мидлет
Приложение, написанное для мобильного телефона, может состоять из различного количества классов. Одни классы, отвечают за загрузку ресурсов, другие за обработку данных, третьи выполняют еще какие-то дополнительные функции, как программист вы вправе выбирать любую удобную для вас модель построения программы. В итоге, созданные вами классы, объединенные в одно целое, будут составлять одну программу или приложение. Все приложения, сформированные для работы в среде Java мобильных телефонов, носят название мидлет. Мидлет -это программа, написанная для мобильного телефона с использованием платформы Java 2 ME. Определять количество классов программы привилегия программиста, но среди всех классов одной программы существует один основной класс, с которого начинается работа всей программы. Этот основной класс мидлета, сердце приложения, он наследуется от класса javax.microedition.midlet. MI Diet. В этом классе описывается код, отвечающий за управление процессом создания интерфейса пользователя, объявления набора данных необходимых для работы всего приложения, создаются объекты имеющихся классов, и что самое главное, он является отправной точкой в работе приложения. Такой класс в Java 2 ME носит название основной класс мидлета.
Рабочие функции, выполняемые этим классом, практически идентичны методу main (). Помните запись, с которой начинался рабочий процесс приложений написанных на Java 2 SE:
public static void main ( String[] args )
На мобильных устройствах аналогичные действия возложены на подкласс класса MIDlet, производящий управление рабочим процессом всего приложения. В дополнение к основному классу, может создаваться ряд классов необходимых для реализации поставленной перед вами задачи. Также имеется возможность собирать несколько мидлетов в один архив. Такая комплектация программ или мидлетов помещенных в один JAR-файл носит название MIDlet suite (набор мидлетов).
В главе 2, когда объяснялась работа в среде Sun ONE Studio 4 Mobile Edition и J2ME Wireless Toolkit 2.1, в частности момент создания проекта Demo, был сформирован простейший код мидлета с названием HelloMIDlet. Этот код был сгенерирован автоматически Sun ONE Studio 4 Mobile Edition, он очень простой и дает хорошую возможность разобраться в структуре мидлета. Посмотрите на листинг 5.1, где приведен код примера HelloMIDlet проекта Demo, созданный в главе 2.
/** Листинг 5.1 Класс HelloMIDlet.java */ import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class HelloMIDlet extends MIDlet implements CommandListener { private Command exitCommand; private Display mydisplay; public HelloMIDlet() { mydisplay = Display.getDisplay(this); exitCommand = new Command("Выход", Command.EXIT, 1); } public void startApp() { TextBox t = new TextBox(" ", "Строка текста", 256, 0); t.addCommand(exitCommand); t.setCommandListener(this); mydisplay.setCurrent(t); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } public void commandAction(Command c, Displayable s) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } } }
Первое, что бросается в глаза при детальном рассмотрении кода мидлета - это три метода: startApp (), pauseApp () и destroyApp (). Программисты, которые знакомы с аплетами, найдут явное сходство в структуре мидлета и аплета, даже названия в некоторой степени схожие. В аплете также имеются подобные методы: start (), stop () и destroy (). Можно сказать, что основной класс мидлета - это некий симбиоз аплета и метода main(), играющего основную и управляющую роль в приложении для мобильных устройств. Создавая свои классы и реализуя их код, вы должны возложить основные рабочие функции на основной класс мидлета. На рис. 5.1 показан принцип работы мобильных приложений.
Рис. 5.1. Принцип работы приложения
Сейчас мы вкратце разберем код примера HelloMIDlet проекта Demo, а потом перейдем к более детальному анализу схемы работы приложений в Java 2 ME. Первые две строки кода из листинга 5.1 - это библиотеки импорта.
import javax.microedition.midlet.*; import javax.microedition. Icdui.*;
В этих строках происходит импорт двух пакетов платформы Java 2 ME. Первый пакет javax.microedition.midlet.* содержит класс MIDlet, с помощью которого происходит связь с MIDP. Каждый код создающий основной класс мидлета обязан импортировать этот пакет. Второй пакет содержит классы, позволяющие создавать пользовательский интерфейс приложения. В следующей главе будут подробно рассмотрены все классы пользовательского интерфейса. Импорт двух пакетов дает возможность задействовать все имеющиеся в этих пакетах интерфейсы, классы, методы и константы, необходимые для работы всего создаваемого приложения. Следующая строка кода:
public class HelloMIDlet extends MIDlet implements CommandListener
создает основной класс мидлета, наследуемый от суперкласса MIDlet, реализуя при этом методы startApp(), pauseApp() и destroyApp(). Также задействуется интерфейс CommandListener, необходимый для обработки событий происходящих в приложении при помощи метода commandAction(). Далее идут две строки создающие объекты классов Command и Display.
private Command exitCommand; private Display mydisplay;
С помощью переменной exitCommand осуществляется выход из приложения посредством метода commandAction (). Переменная mydisplay будет представлять дисплей телефона при помощи абстрактного класса Display, играющего роль диспетчера телефонных экранов. В конструкторе класса HelloMIDlet инициализируются объекты exitCommand и mydisplay.
public HelloMIDlet() { mydisplay = Display.getDisplay(this); exitCommand = new Command("Выход",Command.EXIT, 2); }
В конструкторе класса HelloMIDlet, переменная mydisplay получает ссылку на объект Display при помощи метода getDisplay (). Давайте разберемся эти действия подробно. Вы наверно заметили, что объект Display явно не создается при помощи ключевого слова new. Если быть совсем точным, вы просто не можете этого сделать. Объект класса Display создается автоматически с помощью сервисов телефона для каждого мидлета. Класс Display играет роль диспетчера телефонных экранов, на которые проецируется в итоге все то, что вы будете видеть на дисплее телефона. В телефоне существует всего один основной экран и поэтому в отдельный промежуток времени может быть отражен только один экран, за который отвечает класс Display. С помощью метода getDisplay (), основной класс мидлета получает ссылку на класс Display и содержит ее в переменной mydisplay. В последствии, для того чтобы отразить содержимое текущего дисплея, необходимо воспользоваться методом setCurrent (), например следующим образом:
mydisplay.setCurrent();
Вторая и последняя строка кода в конструкторе класса HelloMIDlet () создает экземпляр класса Command и инициализирует созданный ранее объект exitCommand. Класс Command создает набор информации или набор команд, которые можно отобразить на экране телефона для обработки событий полученных от пользователя. На основе определенного набора команд с помощью интерфейса CommandListener происходит обработка фактических действий пользователя. Посмотрите на рис. 5.2, где на дисплее показана команда Выход, расположенная под экранной клавишей телефона.
Рис. 5.2. Команда выхода из программы
Такая схема отображения различных команд реализована на всех без исключения мобильных телефонах. Единственное, что может изменяться- это способ отображения этих команд. У некоторых производителей мобильных телефонов команды располагаются под экранными клавишами, а у других, ряд команд формируется в виде меню.
Класс Command имеет два конструктора с тремя и четырьмя параметрами. В примере был использован конструктор из трех параметров, посмотрим, как выглядит прототип конструктора класса Command:
public Command( String label, int commandType, int priority )
Параметры конструктора класса Command:
За конструктором класса HelloMIDlet () следует ключевой метод основного класса мидлета startApp ().
public void startApp() { TextBox t=new TextBox("HelloMIDlet","Текст",256,0); t.addCommand(exitCommand); t.setCommandListener (this) ; mydisplay.setCurrent(t) ; }
Метод startApp() вводит приложение в активное состояние и является своего рода входной точкой для всей программы. В рассматриваемом примере для вывода текста на экран используется класс TextBox. Чтобы разобраться, как это происходит, необходимо рассмотреть конструктор класса TextBox:
public TextBox (String title, String text, int naxSize, int constraints)
Параметры конструктора класса TextBox:
То есть, создав объект класса TextBox, вы задаете область экрана, в которой существует свое название и количество выводимых символов. В следующих двух строках кода:
t.addCommand(exitCommand) ; t.setCommandListener(this) ;
сначала добавляется команда Выход, к текущему экрану телефона представленному классом TextBox, а затем с помощью метода setCommandListener () устанавливается обработка событий для этой команды Выход, используя метод интерфейса GoimandListener . Самая последняя строка кода:
mydi splay. setCurrent (t);
отражает текущую информацию на экране. Этот метод подобен кнопке Обновить в Internet Explorer. Вызывая каждый раз метод setCurrent (), вы будете обновлять информацию на дисплее телефона. Следующий метод в примере:
public void pauseAppf)
Тело этого метода пока отсутствует, но с его помощью можно поместить мидлет в состояние паузы и освободить часть используемых ресурсов приложения. Дальше идет метод destroyApp (), освобождающий захваченные мидлетом ресурсы и удаляющий сам мидлет из памяти, то есть закрывает работу приложения. И самый последний метод основного класса мидлета conimandAction () интерфейса CommandListener обрабатывает назначенные события.
public void commandAction(Command c, Displayable s) { if (c ==? exitCommand) { destroyApp(false); notifyDestroyed(); } }
По сути, этот метод является обработчиком событий приложения для всех имеющихся команд. В нашем примере происходит обработка команды Выход. После чего происходит освобождение всех захваченных ресурсов и мидлет выгружается из памяти с помощью методов destroyApp() и notifyDestroyed(). Рассмотрев вкратце общую модель работы мидлета, давайте разберем более подробно процесс работы приложений, а также жизненный цикл всей программы.
Модель работы мидлета
После успешной компиляции примера HelloMIDlet и запуска на любом понравившемся вам эмуляторе, на дисплее эмулятора в верхнем левом углу появится надпись HelloMIDlet. В нашем случае мидлет всего один, ни возможна ситуация когда будет несколько мидлетов, то есть MIDlet suite (набор мидлетов), тогда сервис телефона автоматически создаст меню выстроив все имеющиеся мидлеты друг под другом, предоставляя возможность в выборе программы. Но это не значит, что после того, как вы войдете в ваше приложение, сервис телефона и далее будет так же создавать за вас меню. Нет, действия по структуризации приложения, созданию списков и меню лежит на плечах программиста. На рис. 5.3 изображено Меню телефона с набором различных программ.
Для того чтобы запустить программу на эмуляторе, необходимо нажать кнопку Select (выбор), после чего вы попадаете непосредственно в рабочий цикл приложения. После нажатия клавиши Select, то есть подачи команды активизации приложения, в мидлете происходит поиск метода startApp(), который является начальной и входной точкой всех программ. И уже в методе startApp () идет обработка соответствующего программного кода и как следствие, выполнение работы приложения. Конечно, код находящийся до метода startApp (): объекты, конструктор и так далее, так же инициализируются, но активизация рабочего процесса мидлета происходит с вызовом метода startApp ().
Рис. 5.3. Меню в телефоне
В рассматриваемом примере мы воспользовались классом TextBox, который создает область для вывода текста. В связи с этим, на экране появится текстовая строка, изначально прописанная в программном коде в параметре text конструктора класса TextBox. Этот . текст на дисплее можно отредактировать как угодно, воспользовавшись клавишами эмулятора телефона. В нижнем левом углу экрана, вы увидите надпись Выход. Нажав на клавишу телефона под этой надписью, вы автоматически выйдете из программы. При нажатии подэкранной клавиши Выход, происходит запуск метода commandAction (), реакция которого на команду ' Выход, равносильна обработке событий для переменной exitCommand. Обработка события в данном случае подразумевает вызов двух методов - destroyApp () и notifyDestroyed(), благодаря которым происходит обнуление ссылок, если таковые имеются, и выгрузка мидлета и всего приложения из памяти телефона, возвращая- вас в меню телефона, откуда производился запуск рассматриваемой программы. В итоге весь жизненный цикл работы приложения сводится к периоду активизации программы до выхода из нее. На рис. 5.4 показана общая модель работы мидлета.
Рис. 5.4. Модель работы мидлета
Основной класс мидлета - это своего рода мотор всего приложения, тогда как функциональную часть лучше разбить на необходимое количество классов. Конечно, возможна интеграция всего программного кода приложения в код основного класса мидлета, но, во-первых, это непрофессионально, а во-вторых, это просто неудобно. Хорошо если вы пишете совсем маленькое приложение подобно нашему примеру, но когда речь идет о более серьезном программном продукте, надо разработать четкую структуру классов, продумать общую модель взаимодействия и в конечном итоге написать код приложения. При рассмотрении примеров этой и следующей главы мы будем пока использовать основной класс мидлета, формируя в этом классе дополнительные объекты рассматриваемых классов платформы Java 2 ME, для того чтобы не путаться в большом количестве исходных файлов. Но, начиная с главы 7, перейдем к профессиональной модели построения приложений.
Навигация
Рассмотренный пример из листинга 5.2 раскрыл суть перехода с одного экрана на другой. Как вы заметили, принцип смены экраны довольно прост - достаточно добавить необходимую команду с помощью метода addCommand (), установить обработчик событий для этого экрана и создать код в методе commandAction () , адекватно реагирующий на заданные действия.
Познакомившись с моделью смены экранов и закрепив свои знания на практике, можно переходить к более осмысленной навигации в приложении. В предыдущем примере происходила последовательная смена экранов без возможности возврата либо перехода на необходимый экран. Такая структура хороша для изучения, но абсолютно не годится для серьезного приложения. Телефоны различных марок имеют собственные механизмы перехода, предоставляемые операционной системой или прошивкой мобильного телефона. Механизм, использованный в Java 2 ME для приложений созданных на этом языке, предоставляет не менее мощные, а главное, простые средства для навигации в программе. Самый простой и, как мне кажется, эффективный способ - это использовать автоматически созданное меню при помощи сервиса телефона. Когда вы добавляете к заданному экрану с присоединенным к нему объектом Displayable команды обработки в виде двух подэкранных клавиш, вы имеете всего два видимых варианта клавиш -слева и справа. Как только вы добавите с помощью функции addCommand () более двух команд, сервис телефона автоматически создаст на правой или левой подэкранной клавише телефона (в зависимости от марки производителя), выпадающее меню. При нажатии клавиши, отвечающей за меню, появится меню, отображающее полный список имеющихся команд. На рис. 5.7 изображено контекстное меню, созданное эмулятором телефона среды программирования J2ME Wireless Toolkit 2.1.
Рис. 5.7. Автоматически созданное меню
Задав нужные команды для конкретного объекта Displayable, и создав код их обработки, вы получаете отличный механизм навигации. Но это не единственный способ перехода с экрана на экран. Каждый из четырех классов Form, List, TextBox и Alert имеет свои встроенные средства для создания списков, меню, таблиц, полей, загрузки изображений и так далее. При знакомстве с каждым из классов мы обязательно рассмотрим имеющиеся возможности. А пока давайте разберем механизм автоматического создания меню и обработки имеющихся команд.
Итак, к каждому из задействованных классов нам надо добавить набор команд для перехода на нужный экран и обработать, а точнее, создать код, реагирующий на назначенные команды. Рис. 5.8 живописно изображает и отчасти решает поставленную перед нами задачу.
Теперь сосредоточимся на одном из вариантов программного кода, решающего проблему с навигацией. Первым делом создадим класс, назвав его Navigator.
public class Navigator extends MIDlet implements CommandListener
Рис. 5.8. Схема перехода с экрана на экран
В исходном коде до строк вызова конструктора класса Navigator, добавим объект, содержащий команду Выход.
private Command exitMidlet = new Command("Выход", Command.EXIT, 1);
Потом необходимо создать четыре объекта для каждого из задействованных классов Form, TextBox, List и Alert, Созданные объекты будут отвечать за обработку команд перехода на экран, представленные соответствующими классами.
private Command perexodTextBox = new Command("В TextBox", Command. SCREEN, 2) ; private Command perexodList = new CommandC'B List", Command.SCREEN, 2); private Command perexodAlert = new CommandC'B Alert", Command.SCREEN, 2) ; private Command perexodForm = new CommandC'B Form", Command.SCREEN, 2) ;
Информативные названия всех объектов понятны, но, естественно, выбранные мною названия ни к чему вас не обязывают. Созданные объекты являются объектами класса Command, отвечающего за создание команд, которые в последствии можно определить для каждого из классов Form, TextBox, List и Alert. Позже, в коде мидлета, мы будем задавать соответствующие блоки обработки событий непосредственно в методе commandAction () при помощи оператора if и созданных объектов.
Теперь нам нужно объявить и инициализировать объекты четырех классов Form, TextBox, List и Alert.
private Form my form = new Рогт.("Это объект класса Form") ; private List mylist = new List("Это объект класса List", List.IMPLICIT); private TextBox mytextbox = new TextBox("Это TextBox", "Текст", 256, 0); private Alert myalert = new Alert("Это Alert","Alert исчезнет",null,null); private Display mydisplay;
В конструкторе класса Navigator происходит инициализация объекта
mydisplay. public Navigator() { mydisplay = Display.getDisplay(this); }
Следующая наша задача - это реализация метода startApp (). Сейчас необходимо решить какой из классов будет первым появляться на экране и добавить к нему команды перехода в другие классы, а также команду выхода из приложения. В предыдущем примере первым появлялся класс Form. Его и определим как основной объект, в который попадет пользователь, запускающий приложение.
public void startApp() { myform.addCommand(exitMidlet); myform.addCommand(perexbdTextBox); myform.addCommand(perexodList); myform.addCommand(perexodAlert); myform.setCommandListener(this); mydisplay.setCurrent(myform); }
Последняя строка метода startApp() отображает объект myform на дисплее со всеми имеющимися командами. Как уже говорилось, командам, которым не хватит телефонных клавиш, будет автоматически создано свое собственное меню.
После того как вы попадете в основное окно приложения, которое мы определили для объекта myform, над левой или правой подэкранной клавишей появится команда выхода из приложения и команда Menu. При нажатии на клавишу Menu, на экране телефона появится всплывающее Меню с добавленными ранее командами перехода на экраны, представленные классами TextBox, List и Alert.
Следующей нашей задачей является написание кода для обработки событий созданных команд в методе commandAction (). Код, обрабатывающий команду Выход из приложения, идентичен коду из примера в листинге 5.2 и в большинстве рассматриваемых впоследствии примеров останется таковым. Дальнейшие действия состоят в обработке команды перехода на экран, представленный классом TextBox.
if (с == perexodTextBox) { mytextbox.addCommand(exitMidlet); mytextbox.addCommand(perexodForm); mytextbox.addCommand(perexodList); mytextbox.addCommand(perexodAlert); mytextbox.setCommandListener(this); mydisplay.setCurrent(mytextbox); }
Сразу после того, как пользователь попадет на экран, представленный классам Form, и в контекстном меню выберет команду Перейти в TextBox, произойдет обработка блока команд perexodTextBox. Добавляются все команды к объекту mytextbox, устанавливается обработчик событий и в итоге отображается текущий экран, содержащий все созданные компоненты объекта mytextbox. Точно так же как и на экране с объектом myform существует меню перехода и кнопка выхода.
Обработка событий для объекта mylist происходит с помощью команды perexodList и аналогично рассмотренному коду для объекта mytextbox. С той лишь разницей, что используются соответствующие команды для объекта mylist. В итоге листинг 5.3 связывает все разрозненные фрагменты кода этого подраздела, собирая воедино очень простую и в то же время, мощную программу отличной системы навигации.
/ * * Листинг 5.3 Навигация в приложении */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class Navigator extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 1); // команда перехода в TextBox private Command perexodTextBox = new Command("B TextBox", Command.SCREEN, 2); // команда перехода в List private Command perexodList = new Command("B List", Command.SCREEN, 2); // команда перехода в Alert private Command perexodAlert = new Command("B Alert", Command.SCREEN, 2); // команда перехода в Form private Command perexodForm= new Command("B Form", Command.SCREEN, 2); // объект класса Form private Form myform = new Form("Это объект класса Form"); // объект класса List private List mylist = new List("Этообъект класса List", List.IMPLICIT); // объект класса TextBox private TextBox mytextbox = new TextBox("Это TextBox", "Текст", 256, 0); // объект класса Alert private Alert myalert = new Alert("Это Alert","Alert исчезнет",null,null); // объект mydisplay представляет экран телефона private Display mydisplay; public Navigator() { mydisplay = Display.getDisplay(this); } public void startApp() { // добавить команды перехода в Form myform.addCommand(exitMidlet); myform.addCommand(perexodTextBox); myform.addCommand(perexodList); myform.addCommand(perexodAlert); У/ установка обработчика событий для Form myform.setCommandListener (this); // отразить текущий дисплей mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if (с = = exitMidlet) { destroyApp(false); notifyDestroyed(); } // переход в TextBox if (с == perexodTextBox) { mytextbox.addCommand(exitMidlet); mytextbox.addCommand(perexodForm); mytextbox.addCommand(perexodList); mytextbox.addCommand(perexodAlert); mytextbox.setCommandListener(this); mydisplay.setCurrent(mytextbox); } // переход в List if (c == perexodList) { mylist.addCommand(exitMidlet); mylist.addCommand(perexodForm); mylist.addCommand(perexodAlert); mylist.addCommand(perexodTextBox); mylist.setCommandListener(this); mydisplay.setCurrent(mylist); } // переход в Alert if (c == perexodAlert) { mydisplay.setCurrent(myalert); } // переход в Form if (c == perexodForm) mydisplay.setCurrent(myform); } }
В следующей главе будут изучаться классы высокоуровневого интерфейса, с помощью которых создаются списки, группы элементов, текстовые поля и множество других элементов пользовательского интерфейса.
Переход с экрана на экран
Прежде чем мы приступим к изучению основ перехода в приложении с одного экрана на другой, хочу обозначить стоящие перед нами задачи в рассмотрении средств по созданию пользовательского интерфейса. Сейчас вы имеете некоторое представление о модели работы программ для мобильных телефонов. Далее вы изучите основной способ перехода от экрана к экрану внутри приложения на простом примере. Потом код несколько усложнится и будет показан механизм навигации в программах на Java 2 ME. И уже в главе 6 будут изучены все классы пользовательского интерфейса для создания действительно красивых программ. Сейчас мы идем от простого к сложному и я хочу предложить вам новый пример кода, на основе которого будет изучена схема перехода с одного экрана на другой. Попутно мы задействуем все четыре высокоуровневых класса TextBox, Form, List и Alert.
Прежде чем коснуться непосредственно программирования любого приложения, нужно уделить внимание теоретической части создаваемой программы. Лично я, когда разрабатываю некую программу для мобильного телефона, беру чистый листок бумаги, карандаш и рисую предполагаемый набор экранов, указывая на связь между ними с помощью стрелочек. Это, конечно, не язык UML, но достаточно просто и эффективно. На рис. 5.6 даются все четыре дисплея и связь между ними.
Рис. 5.6. Переход с экрана на экран
Идея этого показательного примера очень проста. Первым делом после входа в приложение вы попадаете в класс Form, являющимся неким контейнером для элементов пользовательского интерфейса. В этом примере классы Form, List, TextBox и Alert не задействованы в полном объеме, а только показывают информативную надпись названия класса. После попадания на экран представленного классом Form, появятся две кнопки: выхода из программы и переход на следующий экран представленный классом TextBox. После перехода с экрана представленного классом Form в TextBox, на экране появится две кнопки: выход из приложения и переход. Кнопка перехода приведет вас на экран представленный классом List, дав аналогичную возможность выбора перехода. Выбрав переход на экран представленный класс Alert, вы увидите на некоторое время экран с надписью Alert и автоматически возвратитесь в List. По своей специфики класс Alert предназначен для сообщения информации об ошибке или исключительной ситуации, этим объясняются и соответствующие действия этого класса. Приступим к написанию кода этого примера. Первым делом импортируем две библиотеки:
import javax.microedition.midlet.*; import javax.microedition.Icdui.*.
Затем создаем класс Perexod, наследуемый от класса MIDlet.
public class Perexod extends MIDlet implements CommandListener
Теперь необходимо создать объекты класса Command. Объект exitMidlet нужен для выхода из программы. Код, реализующий это событие аналогичен коду из предыдущего примера, рассмотренного в листинге 5.1. И еще три объекта будут служить для перехода от экрана к экрану:
private Command exitMidlet; private Command perexodTextBox; private Command perexodList; private Command,perexodAlert; private Display mydisplay;
Названия этих объектов достаточно информативны и в объяснении не нуждаются. Далее очередь подошла к конструктору класса Perexod. Первым делом сохраним ссылку на Display в переменной mydisplay:
mydisplay = Display.getDisplay(this);
Следующим шагом создадим два объекта класса Command, один для выхода из программы, другой для перехода на экран представленный классом TextBox.
exitMidlet = new Command("Выход",Command.EXIT,1); perexodTextBox = new Command("Перейти",Command.SCREEN,2);
Создание этих объектов в конструкторе - не обязательное условие. Просто я основывался на предыдущем примере и оставил примерную структуру приложения для понимания. На самом деле все четыре объекта класса Command можно было инициализировать еще при их объявлении .в начале класса MainMidlet, что более читабельно. Следующим кодом за конструктором идет метод startАрр (), внутри которого создается объект класса Form. Добавим при помощи метода addCommand () команду Выход - это выход из приложения и команду Переход - это переход на экран представленный классом TextBox. 'Назначим обработчик событий классу Form методом setCommandListener () и присоединим объект myform класса Form к текущему дисплею при помощи метода setCurrent().
public void startApp() { Form myform = new Рогт("Это объект класса Form"); myform.addCommand(exitMidlet); myform.addCommand(perexodTextBox); myform.setCommandListener(this); // отражает текущий экран mydisplay.setCurrent(myform); }
Когда вы запустите программу или войдете в рабочий цикл мидлета, то автоматически инициализируются объекты классов и конструктор класса Perexod, а работа программы начнется с вызова метода startApp (). Теперь необходимо назначить соответствующие действия клавишам перехода в методе commandAction () интерфейса CommandListener для обработки пользовательских команд. Переход по кнопке Выход вам уже знаком из предыдущего примера, поэтому оставим все почти без изменения, за исключением информационной команды exitMidlet.
if (с == exitMidlet) { destroyApp(false); notifyDestroyed(); }
А теперь вплотную займемся командой Перейти. Что от нас требуется? В момент запуска программы мы попадаем на экран представленный классом Form посредством команды perexodTextBox, а требуется прейти на экран представленный классом TextBox. Для создания обработчика событий команды Перейти нужно сформировать объект класса TextBox, позаботиться о следующей кнопке перехода perexodList для перехода на экран, представленый классом List, добавить команду Выход для выхода из программы и команду Перейти. Осталось добавить обработчик событий и присоединить созданный TextBox к текущему экрану. Смотрим, что у нас получилось:
if (с == perexodTextBox) { TextBox tb = new TextBox("TextBox", "Текст", 256, 0); perexodList = new Command("Перейти", Command.SCREEN, 2)*; tb.addCommand(exitMidlet); tb.addCommand(perexodList); tb.setCommandLi'stener (this) ; Display.getDisplay(this).setCurrent(tb); }
Обратите внимание на последнюю строку кода в теле условного оператора:
Display.getDisplay.(this) . setCurrent (tb) ;
В данном случае присоединяется созданный объект tb класса TextBox к текущему экрану. Мы говорим о смене экранов для создания четкого и информативного пользовательского интерфейса, на самом деле смены экранов в буквальном смысле не происходит. Существует только один дисплей, назначенный для класса Displey, который отвечает за то, что будет нарисовано на экране телефона, а именно, какой из объектов Displayable. Только один объект Displayable может быть отображен за один раз на экране. То есть существует всего один физический дисплей, к которому присоединяются необходимые объекты классов пользовательского интерфейса через обработку событий. Имеющийся экран просто постоянно перерисовывается, отображая тот или иной объект востребованного класса, а иначе говоря, к текущему дисплею присоединяется объект класса, создавая иллюзию смены экранов. Системные ресурсы телефонов пока малы, поэтому приходится идти на такие хитрости.
Затем в рассматриваемом примере необходимо перейти на экран представленный классом List. Поскольку мы имеем аналогичные требования к экземпляру этого класса, то обработка событий и создание класса List будут идентичными классу TextBox.
if (с == perexodList) { List mylist = new List("List", List.IMPLICIT); perexodAlert = new Command("Перейти", Command.SCREEN, 2); mylist.addCommand(exitMidlet); mylist.addCoiranand(perexodAlert); mylist.setCommandListener(this); Display.getDisplay(this).setCurrent(mylist); }
Позаботившись о переходе на экран представленный классом Alert и о выходе из приложения, можно создать код для объекта Alert, который впоследствии можно присоединить к текущему экрану. Класс Alert несколько специфичен, это вам станет понятно как только вы откроете окно, отвечающее за отображение объекта. Попробуйте после компиляции рассмотренного примера сделать для Alert команду Выход, и посмотрите, что получится. Теперь соединим рассмотренный код в одно целое, получив готовую программу, представленную в листинге 5.2. Пример также можно найти на прилагаемом к книге компакт-диске в папке \Code\Listing5_2\src.
/** Листинг 5.2 Переход с экрана на экран */ // подключаем пакеты import javax.microedition.midlet.*; import javax.microedition..lcdui. *; // создаем класс Perexod public class Perexod extends MIDlet implements CommandListener { // команда выход из программы private Command exitMidlet; // команда перехода в программе private Command perexodTextBox; private Command perexodList; private Command perexodAlert; // дисплей private Display mydisplay; // конструктор класса Perexod public Perexod() { mydisplay = Display.getDisplay(this); // выход из приложения exitMidlet = new Command("Выход", Command.EXIT, 1); // переход TextBox perexodTextBox = new Command("Перейти", Command.SCREEN, 2); } // входная точка всей программы public void startApp() { // создаем объект класса Form Form myform = new Form("Это объект класса Form"); // добавляем команду выхода из программы myform.addCommandfexitMidlet); // добавляем команду перехода в TextBox myform.addCommand(perexodTextBox); // устанавливаем обработчик событий для команд объекта класса Form myform.setCommandListener(this); // отражаем текущий экран mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} // обработчик событий в программе public void commandAction(Command c, Displayable d) { // обработка команды выход if (с == exitMidlet) { destroyApp(false); notifyDestroyed(); } // обработка команды перехода в TextBox if (с == perexodTextBox) { TextBox tb = new TextBox("TextBox", "Текст", 256, 0); perexodList = new Command("Перейти",Coramand.SCREEN, 2); tb.addCommand(exitMidlet); tb.addCommand(perexodList); tb.setCommandListener(this); Display.getDisplay(this).setCurrent(tb); } // обработка команды перехода в List if (с == perexodList) { List mylist = new List("List", List.IMPLICIT); perexodAlert = new Command("Перейти", Command.SCREEN, 2); mylist.addCommand(exitMidlet); mylist.addCommand(perexodAlert); mylist.setCommandListener(this); Display.getDisplay(this).setCurrent(mylist); } // обработка команды перехода в Alert if (с == perexodAlert) { Alert myalert = new Alert("Alert","Текст",null,null); Display.getDisplay(this).setCurrent(myalert); } } }
После компиляции примера пройдите по всей программе и убедитесь, что вам понятна общая идея и принцип работы смены экранов, на которых строятся все приложения в Java 2 ME.
Пользовательский интерфейс
Когда мы рассматривали механизм работы примера из листинга 5.1, я думаю, вы подметили некий поэкранный принцип отображения информации на дисплее. Первый экран показывал список доступных приложений, после выбора одного из них вы попадали на экран этого приложения. Нажав кнопку Выход, происходило возвращение к экрану выбора. В Java 2 ME программах такая схема поэкранного отображения информации является основной. Если вы никогда не обращали на это внимания при работе со своим телефоном, то самое время взять его и пощелкать джойстиком. В приложениях для мобильных телефонов основанных на экранах в Java 2 ME отсутствуют окна и фреймы в отличие от Java 2 SE. Телефоны ограничены в системных ресурсах и разнообразная красивая роскошь, к сожалению не позволительна для этих маленьких устройств. Поэтому при создании конечного продукта стоит с особой тщательностью продумывать основные составляющие будущего приложения. Основываясь на поэкранном отображении информации, необходимо создавать интуитивно понятную структуру приложения, образуя при этом четкую экранную навигацию. Если пользователь заблудится в вашей программе, он просто удалит ее из памяти телефона и никогда к ней больше не вернется, а вы потеряете потенциального покупателя.
Как уже отмечалось, экран телефона представлен классом Display. Каждый мидлет может иметь только один объект класса Display, возвращаемый мидлету при помощи метода getDisplay (), определяя тем самым текущий дисплей телефона для мидлета.
Платформа Java 2 ME обладает пакетом javax.microedition.lcdui, включающим в себя классы для работы с пользовательским интерфейсом UI (user interface). Большое количество классов, входящих в этот пакет, будут подробно рассматриваться в следующей главе. Самым главным классом пользовательского интерфейса является класс Displayable. С основы абстрактного класса Displayable происходит построение основной части графического интерфейса приложения. На рис. 5.5 показана структура пользовательского интерфейса пакета javax.microedition.lcdui.
Рис. 5.5. Структура пользовательского интерфейса
От класса диспетчера Display зависит, какой из классов Displayable будет отображен на экране. В свою очередь только один класс Displayable может быть единовременно показан на экране. То есть, объект класса TextBox, грубо говоря, существует в своем экране, объект класса List - в своем и оба объекта не могут существовать вместе на одном экране, определяя тем самым правило поэкранного отражения информации на дисплее телефона.
Далее в иерархии структуры пользовательского интерфейса, показанного с помощью рис. 5.5, идут два абстрактных класса: Screen и Canvas. На этой стадии происходит разделение классов пользовательского интерфейса на высокоуровневый класс, назначенный классу Screen и всей его дальнейшей иерархии наследования и низкоуровневый класс Canvas. Оба класса создают структуру интерфейсов, разделенную на высокоуровневый и низкоуровневый пользовательский интерфейсы.
Высокоуровневый интерфейс содержит средства для работы с пользовательским интерфейсом, созданные на основе классов шаблонов, использование которых приводит к построению жестко заданного интерфейса. Например, задействованный в исходном коде HelloMIDlet проекта Demo класс TextBox, не может никаким образом изменить экран телефона. Экран представленный классом TextBox - это текстовый контейнер, в котором можно осуществлять вывод, удаление и редакцию текста и не более того. То есть классы высокоуровневого интерфейса - это жестко заданная модель отображения пользовательского интерфейса на экране телефона, с помощью которых программист организует навигацию, списки, меню, текстовые контейнеры, группы выбираемых элементов и так далее.
Низкоуровневый интерфейс предоставляет графические средства для рисования на экране различных графических элементов и обработку команд, посылаемых с клавиш телефона. Низкоуровневый интерфейс позволяет рисовать на экране телефона, добавляя тем самым в приложение красивые графические элементы в виде таблицы, изображений, полей, заставок и так далее. Такое разделение классов существует сугубо в теоретическом виде и ничто вам не мешает комбинировать элементы обоих интерфейсов в одной программе, создавая красивое интерактивное приложение.
На рис. 5.5 была дана часть пакета javax.microedition.lcdui.*, потому что классы Canvas и GameCanvas будут подробно рассматриваться соответственно в главах 7 и 8. Рассмотрим некоторые характеристики классов Alert, TextBox, Form и List представляющие высокоуровневый интерфейс:
Класс Alert
Использование класса Alert в Java 2 ME приложениях обусловлено возникновением различных внештатных ситуаций. В основном класс Alert применяется для создания экрана, который информирует пользователя об ошибке произошедшей в приложении или любом другом уведомлении информационного характера. Экран, определенный классом Alert может содержать строковое уведомление о произошедшей ошибке либо текстовую строку с заданным изображением. В связи с этим, класс Alert имеет два конструктора, использующихся в создании объектов этого класса. Первый конструктор содержит один параметр типа String, задавая строку текста для уведомления. Рассмотрим первый конструктор класса Alert.
public Alert(String title);
Параметры конструктора public Alert:
Второй конструктор класса Alert имеет уже четыре параметра, представляя более интересный вид создаваемого экрана.
public Alert(String title, String alertText, Image alertlmage, AlertType alertType)
Параметры конструктора public Alert:
Существует пять типов уведомлений:
Создавая объект класса Alert, вы можете выбрать необходимый тип уведомлений или информационных сообщений, формируя органичные, удобные приложения, предусматривающие любые варианты развития событий.
Класс ChoiceGroup
С помощью класса ChoiceGroup можно встраивать в форму группу элементов. Группы элементов делятся на три типа: эксклюзивный (EXCLUSIVE), множественный (MULTIPLE) и всплывающий (POPUP). Посмотрите на рис 6.3, где показан эмулятор мобильного телефона, показывающий все три группы элементов.
Рис 6.3. Типы группы элементов ChoiceGroup
Первый тип группы элементов на рис 6.3, выполнен в виде выпадающего меню и спрограммирован на основе типа POPUP. В данном случае это список из четырех флажков, с помощью которых можно выбрать заданные действия. Четыре флажка в меню были созданы абсолютно произвольно. Количество флажков и как следствие, количество вариантов выбора зависит от задачи поставленной перед программистом. Следующая группа, изображенная на рис. 6.3 представлена типом MULTIPLE. В этой группе элементов пользователь имеет возможность многократного выбора, т.е. можно выбрать сразу несколько вариантов. Обычно такая группа элементов используется при настройке различных опций, где возможно указать сразу несколько вариантов выбора. Третья и последняя группа элементов задается типом EXCLUSIVE, и возможен лишь один вариант выбора заданного флажка. Чтобы создать в приложении необходимую группу элементов нужно воспользоваться конструктором класса ChoiceGroup. Всего имеется два конструктора. Первый конструктор с двумя параметрами:
public ChoiceGroup(String label, int choiceType)
Параметры конструктора ChoiceGroup:
И второй конструктор с четырьмя параметрами, дающий программисту более интересный выбор в использовании графических изображений:
public ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements)
Параметры конструктора ChoiceGroup:
Два последних параметра конструктора класса ChoiceGroup предназначены для создания массива названий и изображений для элементов группы, например, таким образом:
String[] string = {"Флаг 0","Флаг 1","Флаг 2","Флаг 3"}
Для того чтобы добавить в пустую форму класса Form все три имеющиеся группы элементов, нужно создать три объекта класса ChoiceGroup и воспользоваться методом append () класса Form, например:
ChoiceGroup groupMultiple=new ChoiceGroup("Группа Multiple",ChoiceGroup.MULTIPLE); ChoiceGroup groupPopup=new ChoiceGroup("Группа Popup",ChoiceGroup.POPUP); ChoiceGroup groupExclusive=new ChoiceGroup("Группа Exclusive", ChoiceGroup.EXCLUSIVE); Form myform = new,Form("Встроенный ChoiceGroup"); myform.append(groupPopup); myform.append(groupMultiple); myform.append(groupExclusive);
Большой пользы простое статическое отображение элементов группы на дисплее телефона принести не может. Поэтому необходимо познакомится с методами класса ChoiceGroup, с помощью которых можно удалять, добавлять и отслеживать состояние каждого элемента группы.
Методы класса ChoiceGroup
Всего имеется семнадцать методов, ознакомимся с основными и наиболее используемыми методами.
Прежде чем рассматривать практическую часть раздела, давайте разберемся, что именно от нас требуется чтобы воспользоваться компонентами класса ChoiceGroup. Итак, сначала необходимо создать объект класса Form или. пустую форму, куда можно встроить объекты класса ChoiceGroup. Далее необходимо определить, что именно будет происходить при выборе элемента группы. Я предлагаю рассмотреть вариант перехода в новое окно после выбора конкретного элемента группы, где мы выведем простую информационную надпись. Для этого необходимо создать две команды перехода. Одна из команд будет реагировать на выбранный элемент группы, перемещая пользователя в новое окно, а другая команда перехода - возвращать в окно выбора. Пожалуй, это все что от нас 'сейчас требуется, поэтому давайте перейдем к реализации этого примера. Предлагаю не рассматривать по отдельности каждый кусок кода всей программы, а проанализировать весь пример целиком, поле чего остановиться на наиболее непонятных Местах программного кода. В листинге 6.1 показан исходный код рассматриваемого примера.
/** Листинг 6.1 Класс ChoiceGroup */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassChoiceGroup extends MIDlet implements CommandListener { // команда выхода, из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // команда выбора элемента группы private Command vibor = new Command("Выбрать", Command.SCREEN, 1); // команда возврата в главное окно private Command vozvrat = new Command("Назад"; Command.BACK, 0); // объект класса ChoiceGroup private ChoiceGroup groupPopup; // объект класса Form private Form myform; // объект mydisplay представляет экран телефона private Display .mydisplay; public MainClassChoiceGroup() { mydisplay = Display.getDisplayfthis); } // текст для элементов группы private String[] mygroup = {"Флаг 0","Флаг 1","Флаг 2" "Флаг 3"}; public void startApp() { // инициализируем объект groupPopup groupPopup = new ChoiceGroup ("Группа Popup", ChoiceGroup.POPUP,mygroup,null) ; // создаем форму при помощи объекта Form myform = new Form("Встроенный ChoiceGroup ") ; // добавляем группу элементов myform.append(groupPopup); myform.addCoInmand(exitMidlet) ; myform.addCommand(vibor); myform.setCommandListener(this); // отражаем текущий дисплей mydisplay.setCurrent(myform); } public void pauseAppf) {} public void destroyApp(boolean unconditional) {} public void commandAction(Command с, Displayable d) { // выход из приложения if(с == exitMidlet) { destroyApp(false) ; notifyDestroyed() ; } // возврат в myform if(с == vozvrat) { mydisplay.setCurrent(myform); } // обработка выбранного элемента в группе if(с == vibor) { int i = groupPopup.getSelectedlndex(); if(i ==0) { Form formPopup = new Form("Это formPopup"+mygroup[0]); formPopup.append(mygroup[0]); formPopup.addCommand(vozvrat); formPopup.addCommand(exitMidlet); formPopup.setCorranandListener(this); mydisplay.setCurrent(formPopup); } if(i = = 1){ Form formPopup = new Form("Это formPopup"+mygroup[1]); formPopup.addCommand(vozvrat); formPopup.append(mygroup[1]); formPopup.addCommand(exitMidlet); formPopup.setCommandListener(this); mydi splay.setCurrent(formPopup); } if(i == 2) { Form formPopup = new Form("Это formPopup"+ mygroup[2]); formPopup.append(mygroup[2]); formPopup.addCommand(vozvrat); formPopup.addCommand(exitMidlet); formPopup.setCommandListener(this); mydisplay.setCurrent(formPopup); } if(i = = 3) { Form formPopup = new Form("Это formPopup"+mygroup[ 3 ] ) ; formPopup.append(mygroup[3]); formPopup.addCommand(vozvrat); formPopup.addCommandtexitMidlet); formPopup.setCommandListener(this) ; mydisplay.setCurrent(formPopup); } } } }
Вся программа основывается на классе MainClassChoiceGrop. К команде выхода exitMidlet добавлены еще две команды обработки событий - это vozvrat и vibor. Команда vozvrat возвращает,пользователя обратно в главное окно приложения, в которое он попадает при запуске программы. С помощью команды vibor, происходит выбор заданных действий, то есть отклик программы на выбранный элемент группы. Как мы уже договорились, каждый элемент группы POPUP (всего их будет четыре), должен привести пользователя в свой экран, установленный с помощью класса Form. Далее в листинге 6.1 идет объявление необходимых объектов для классов Form, ChoiceGrop и Display. После конструктора идет строка кода создающая текст для элементов группы:
private String[] mygroup = {"Флаг 0","Флаг'1","Флаг2","Флаг3"};
С помощью переменной mygroup создается массив текстовых данных для инициализации всей группы элементов. После создания переменной mygroup следует код метода startApp (). Первой строкой кода в методе startApp () инициализируется объект groupPopup класса ChoiceGroup. Конструктор этого класса мы подробно уже рассматривали, но небольших пояснений требуют два последних параметра. Оба параметра могут быть представлены в виде массива данных. Предпоследний параметр конструктора класса ChoiceGroup, инициализирующий объект mygroup, создает четыре строки текста в виде выпадающего меню (поскольку мы использовали значение POPUP во втором параметре конструктора класса ChoiceGroup). Все четыре строки текста и есть группа элементов, дающая пользователю выбор конкретных действий. Последний параметр в конструкторе класса ChoiceGroup служит для загрузки каждому элементу группы своего изображения или иконки, которая будет отображаться слева от" текста, назначенного для каждого элемента группы. Поскольку изображения вы еще загружать не умеете (чему мы, безусловно, научимся), то надо выставить это значение в null. После инициализации объекта groupPopup создается форма на основе класса Form, добавляются команды выхода и выбора, и самое главное, происходит встраивание объекта groupPopup класса ChoiceGroup в форму класса Form. После чего текущий экран дисплея отображается посредством строки кода:
mydisplay.setCurrent,(myform) ;
Последующие действия всей программы сводятся к обработке событий возникающих при нажатии клавиш телефона. Если посмотреть на эту программу на экране телефона, то мы увидим на дисплее строку текста и выпадающее меню с четырьмя элементами. Выбрав один элемент из группы с помощью кнопки Select, на правой клавише телефона мы получим команду Выбрать, благодаря которой можно будет перейти в новое окно, заданное для выбранного элемента группы.
После того, как произведен выбор элемента группы и нажата клавиша с командой Выбор, программа попадает в обработчик событий этой команды, назначенный для переменной vibor. Далее используется метод getSelectedIndex() класса ChoiceGroup, с помощью которого происходит получение индекса выбранного элемента группы и помещение результата в переменную i. После чего происходит сравнение полученного индекса с четырьмя значениями, заданными для каждого элемента. Соответственно, после совпадения индекса и значения выбранного элемента, происходят действия заданные для этого выбора. В примере происходит создание нового экрана с информационной надписью о выбранном элементе группы, добавлением команд выхода из приложения и возврата в главное окно программы. В этой программе, в ответ на действия по выбору элемента группы, создается новый экран с объектом класса Form. В ваших программах это могут быть любые другие события, необходимые для решения конкретных задач.
Класс DateField
Это, пожалуй, самый простой класс из всех имеющихся в иерархии класса Item. С помощью класса DateField возможно произвести установку необходимой даты и времени. Используемый интерфейс для отображения даты и времени элементарный и практически все действия по установке заданных параметров даты и времени уже реализованы программно. На рис. 6.4 изображен эмулятор телефона, отображающий текущее время.
В составе класса DateField имеется в наличии два конструктора, для создания объектов этого класса, рассмотрим их. Первый конструктор:
public DateField(String label, int mode);
Параметры конструктора класса DateField:
Имеется возможность вывести дату с помощью значения DATE, и время, задав значение TIME. Также можно пользоваться комбинированным способом DATE_TIME для отображения обоих компонентов вместе.
Второй конструктор содержит добавочный параметр и позволяет устанавливать время по часовому поясу.
public DateField(String label, int mode, TimeZone timeZone)
Параметры конструктора класса DateField:
TimeZone v = TimeZone.getTimeZone("GMT");
Класс DateField содержит всего четыре метода:
Рис 6.4. Текущее время на экране телефона
Перейдем к программному коду и рассмотрим пример, реализующий вывод на экран даты и времени одновременно. Все, что сейчас от нас требуется — это написание кода основного класса мидлета, создание пустой формы и встраивание в эту форму класса DateField. Также необходимо проследить наличие команды выхода из приложения. Все остальное за нас сделает Jауа 2 ME, создав кнопки перехода и команду сохранения настроек даты и времени. В листинге 6.2 дается полный код примера к этому разделу.
/** Листинг 6.2 Класс DateField . */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassDateField extends MIDlet implements CoramandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // объект класса DateField private DateField dt; // объект класса Form private Form myform;. // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassDateField() { mydisplay = Display.getDisplay(this); } public void startApp() { //инициализируем объект dt dt = new DateField("Дата и Время", DateField.DATE_TIME); // создаем форму при помощи объекта Form myform = new Form("Встроенный DateField"); // добавить объект dt myform,append(dt); myform.addCommand(exitMidlet); myform.setCommandListener(this); // отразить текущий дисплей mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if(с = = exitMidlet) { destroyApp(false) , notifyDestroyed(); } } } }
В примере создан класс MainClassDateField, соответствующий названию разбираемого класса. Сам по себе пример очень легкий в силу простоты реализации самого класса DateField. Первоначально создается объект dt для класса DateField, после этого происходит его инициализация в методе startАрр (). Создается форма классом Form и объект dt интегрируется в эту форму. Все остальное, а именно: циферблат и календарь, показанные на рис. 6.4, создаются автоматически с помощью эмулятора телефона при выборе одного из элементов класса. В нашем примере был создан объект dt класса DateField, но можно было этого и не делать, а обойтись, например такой простой записью:
Form f = new.Form(new DateField("Дата и Время", DateField.DATE_TIME);
Такая запись используется иногда в профессиональных программах, где это действительно очевидно и не затруднит чтения и понимания всей программы в целом.
После того, как вы откомпилируете этот пример и запустите приложение, на экране появятся два элемента с надписями time и date. Выбрав один из элементов и нажав на кнопку Select, вы попадете, в зависимости от выбора, на экран с календарем или временем, изображенным на рис. 6.4. С помощью джойстика или клавиш перемещения, можно установить необходимые параметры для обоих элементов.
Класс Font
При формировании приложения программисту всегда хочется улучшить его внешний вид и кроме обилия компонентов, создающих списки, таблицы, бегущие строки, еще имеется класс Font; с помощью которого можно задавать шрифт для текста. Телефоны имеют ограниченные системные ресурсы, поэтому доступно всего несколько шрифтов, которые отличаются по размеру, начертанию, стилю и задаются при помощи констант.
Рис 6.13. Загрузка изображения классом image
Размер шрифта устанавливается при помощи трех констант:
Cтиль можно задавать четырьмя константами:
Начертание шрифта определяется тремя константами:
В профиле MIDP 1.0 возможность установки различных шрифтов в приложении имелась только при использовании класса Graphics и метода setFont (). В профиле MIDP 2.0, уже имеется возможность установки шрифта без использования класса Graphics, только при помощи методов из состава классов пользовательского интерфейса. Процесс назначения шрифта текста в программе происходит следующим образом. Вначале создается переменная, которая будет содержать размер, стиль и начертание шрифта, установленные при помощи метода getFont () класса Font например:
Font myFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BQLD, Font. SI ZE_LARGE) ;
Переменная myFont теперь содержит шрифт, который можно назначит любому тексту в программе. В профиле MIDP 2.0 для этого достаточно вызвать метод setFont () с необходимыми параметрами. В профиле MIDP 1.0 для назначения шрифта тексту, необходимо использовать класс Graphics, в главе 6 рассматривается эта возможность.
В примере к этому разделу будет задействован класс List, создающий список элементов. При создании на экране списка из четырех элементов, каждому элементу будет назначен свой шрифт. В листинге 6.12 содержится код примера создающего различные шрифты элементам списка.
/** Листинг 6.12 Класс Font */ import javax.microedition.midlet. *; import* javax.microedition.Icdui.*; public class MainClassFont extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // массив иконок Image[] icon = null; x // объект класса List private List mylist; // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassFont() { mydisplay = Display.getDisplay(this); } public void startApp() { // перехватываем исключительную ситуацию try{ // загрузка изображения Image imaged = Image.createlmage("/icon0.png"); Image imagel = Image.createlmage("/icon1.png"); Image image2 = Image.createlmage("/icon2.png"); Image image3 = Image.createlmage("/icon3.png"); // поместить загруженные изображения в массив icon icon = new Image[]{ image0, image1, image2, image3}; } catch(Java.io.IOException ex){ } // текст для четырех элементов списка String[] stroka = {"Синий","Красный","Зеленый", "Оранжевый"}; // назначается шрифт нулевому элементу списка Font f0 = Font.getFont(Font.FACE_PROP6RTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL); // назначается шрифт первому элементу списка Font f1 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,Font.SIZE_MEDIUM); // назначается шрифт второму элементу списка Font f2 = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_ITALIC,Font.SIZE_LARGE); // назначается шрифт третьему элементу списка Font f3 = Font.getFont(Font.FACE_SYSTEM, Font.STYLEJJNDERLINED, Font.SIZE_LARGE); // инициализация объекта mylist mylist = new List("Класс List", Choice.EXCLUSIVE, stroka, icon); // устанавливается шрифт нулевому элементу списка mylist. setFont (0 , f0), ; // устанавливается шрифт первому элементу списка mylist.setFont(I,f1); // устанавливается шрифт второму элементу списка mylist .setFont.(2 , f 2) ; //устанавливается шрифт третьему элементу списка mylist.setFont(3,f3); // добавить команду выхода mylist.addCommand(exitMidlet); mylist.setCommandListener(this); // отразить текущий дисплей mydisplay.setCurrent(mylist); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) {// выход из приложения if(с == exitMidlet) {destroyАрр(false); notifyDestroyed() ; } } }
Основным классом в программе из листинга 6.13, иллюстрирующей работу со шрифтом, является класс MainClassFont. Весь код программы построен на использовании класса List создающем список элементов. В строке кода:
Image[] icon = null
создается переменная для хранения массива изображений. Конкретно в этом примере будут использованы маленькие иконки, загружаемые каждому элементу списка. Всю группу элементов представляет объект my list класса List. В методе startApp () происходят основные действия по созданию списка элементов, загрузке изображения и назначению шрифта каждом элементу списка. В четырех строках кода:
Image imaged = Image.createlmage("/icond.png"); Image imagel = Image.createlmage("/iconl.png"); Image image2 = Image.createlmage("/icon2.png"); Image image3 = Image.createlmage("/iconS.png");
загружаются четыре различные иконки в виде шариков, окрашенных в синий, красный, зеленый и оранжевый цвет. Все они помещаются в массив:
icon = new Image[]{imaged, image1, image2, image3};
Далее в программном коде создается массив строковых значений:
String[] stroka = {"Синий","Красный","Зеленый","Оранжевый"}.
Теперь пришло время создать шрифты:
Font f0 = Font.getFontfFont.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL); Font f1 = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD, Font.SIZE_MEDIUM); Font f2 = Font.getFont(Font.FACE_MONOSPACE, Font. STYLE_ITALIC, Font. SIZE_LARGE); Font f3 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_UNDERLINED,Font.SIZE_LARGE);
В этих строках создаются четыре переменные f 0...f 3, содержащие различные по стилю, размеру и начертанию шрифты. С помощью созданных переменных впоследствии будет производиться установка шрифтов для каждого элемента списка. Список элементов представлен объектом mylist и выполнен по типу Exclusive (четыре элемента со своими иконками). В классе List имеется метод setFont () доступный в профиле MIDP 2.0, он и используется в примере.
Создав объект класса List, установим шрифт всем элементам списка:
mylist.setFont(0,f0); mylist.setFont(1,f1); mylist.setFont(2,f2); mylist.setFont(3,f3);
С помощью метода setFont () происходит установка заданного шрифта, содержащегося в переменных f 0... f 3. Назначение шрифта происходит по индексам от 0 до 3 в массиве stroka [ ].
В конце кода происходит добавление команды выхода и отображение текущего экрана на дисплее телефона. На рис. 6.14 представлена работа программы из листинга 6.13.
Рис 6.14. Эмулятор телефона, на экране которого представлены разные шрифты
К сожалению, ресурсы мобильных телефонов не позволяют воспользоваться обилием шрифтов компьютерной платформы, но и имеющейся базы вполне достаточно цля создания разнообразных текстовых элементов. Использование шрифтов & программах значительно улучшает пользовательский интерфейс и придает приложению более изящный вид. В следующей главе будет рассматриваться программирование графики в Java 2 ME, с помощью классов низкоуровневого интерфейса.
Класс Form
Основным экранным классом примеров из главы 5 служил экран, представленный классом Form. Как вы понимаете это не обязательное условие, но я выбрал класс Form не случайно. Дело в том, что реализация класса Form выполнена в виде контейнера, позволяющего встраивать в себя различные компоненты пользовательского интерфейса. Это, пожалуй, единственный и самый мощный по своим возможностям класс. Само по себе название Form подразумевает создание некой формы для заполнения экрана телефона. В предыдущих примерах мы использовали,- так называемую, пустую форму этого класса в виде чистого экрана. Впоследствии, при упоминании термина форма, будет подразумеваться экран телефона, представленный объектом класса Form для интеграции классов пользовательского интерфейса.
Класс Form имеет два конструктора, необходимых при создании объекта этого класса. Первым конструктором мы уже пользовались, и выглядит он достаточно просто:
public Form (String title)
Параметры конструктора класса Form:
Второй конструктор класса Form имеет уже два параметра, и позволяет встроить компоненты интерфейса в пустую форму, public Form (String title, Item[] items)
Параметры конструктора класса Form:
В классе Form существует набор методов, с помощью которых можно добавить, удалить или вставить компоненты интерфейса. Класс Form имеет двенадцать методов, с помощью которых можно манипулировать компонентами абстрактного класса Item. Всего насчитывается восемь компонентов пользовательского интерфейса в иерархии класса Item. To есть вы создаете экран, за который отвечает класс Form, и интегрируете имеющиеся в вашем распоряжении компоненты класса Item. О самом классе Item и его иерархии мы поговорим в следующем разделе этой главы, после анализа класса Form.
Класс Gauge
С помощью класса Gauge создается графический измеритель различных процессов. То есть, возможно осуществить графическое отображение, например процесса загрузки файла, сохранения игры, поиска информации и т.д. Представление любого из процессов в графическом виде, дает возможность создать красивое интерактивное приложение. Визуальное отображение процесса осуществляется в виде заданного по размеру горизонтального столбца, который закрашивается слева направо по мере выполнения процесса. К сожалению, определенного стандарта в графическом представлении, скажем того же столбца, не существует и каждый из производителей представляет свой разработанный вид графического контекста. На рис 6.9, изображен эмулятор телефона с графическим измерителем процесса.
Класс Gauge имеет всего один конструктор, необходимый при создании объекта этого класса. Разберем конструктор класса Gauge:
publicGauge(String label, boolean interactive, int maxValue, int initialValue)
Рис 6.9. Эмуляторы телефонов, показывающие использование класса Gauge
Параметры конструктора Gauge:
Методы класса Gauge
Методы, имеющиеся в составе класса Gauge, позволяют настраивать графическое отображение течение процесса на экране телефона, рассмотрим некоторые из методов.
В примере создается простой измеритель течения процесса в виде прямоугольника, максимальный диапазон задан значением десять. В листинге 6.7 показано использование класса Gauge.
/ * * Листинг 6.7 Класс Gauge */import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassGauge extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command!"Выход", Command.EXIT, 1); // объект класса Form private Form myform = new Form("Класс Gauge"); // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassGauge() { mydisplay = Display.getDisplay(this) ; } public void startApp() { // добавить объект класса Gauge myform.append(new Gauge("Прогресс:", true, 10, 5 )); // установка обработчика событий для Form myform.addCommand(exitMidlet); myform.setCommandListener(this); // отразить текущий дисплей mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if (с = = exitMidlet) { destroyApp(false); notifyDestroyed(); } } }
Откомпилировав этот пример, вы увидите на экране прямоугольник, наполовину закрашенный темным цветом. Использование класса Gauge позволяет создавать экранные заставки отображающие, например, процесс загрузки Приложения. Для того чтобы пользователь не наблюдал за черным экраном телефона в момент загрузки очередного процесса, создайте класс Gauge и используйте его по назначению.
Класс Image
При рассмотрении класса ImageItem мы уже использовали объекты класса Image, но тогда был рассмотрен только один метод и способ работы с классом Image. В этом разделе вы более подробно познакомитесь с этим классом. Класс Image необходим для загрузки и хранения изображений в формате PNG. Чаще всего загружаемые изображения находятся в рабочем каталоге приложения. Но могут находиться и где угодно, надо только правильно указать путь местонахождения для загрузки. При упаковке приложения в JAR-файл, все имеющиеся изображения автоматически копируются в архив, и при работе программы на телефоне, загрузка уже осуществляется из JAR-файла. Загружаемые изображения могут использоваться во время работы с классами Alert, Choice, ChoiceGroup, Form, ImageItem и Graphics. Качество воспроизведения изображения на экране всецело зависит от возможностей используемого телефона. Если изображение больше фактического размера дисплея, то сервис телефона организует прокрутку изображения и если это не входит в ваши планы, то следует придерживаться минимальных размеров ширины и высоты при создании изображений.
Класс ImageItem
С помощью класса Imageltem возможна загрузка изображения в форму представленную классом Form. Изображением может быть любая картинка формата PNG (Portable Network Graphics - формат портативной сетевой графики), выполненная в виде иконки, фотографии, заставки, фона и так и далее. Имеются два конструктора класса Imageltem. Первый конструктор содержит четыре параметра, рассмотрим этот конструктор:
public ImageItem(String label, Image img, int layout, String alt Text)
Параметры конструктора ImageItem:
Второй конструктор класса Imageltem имеет на один параметр больше и выглядит следующим образом:
public Imageltem(String label, Image img, int layout, String altText int appearanceMode)
Параметры конструктора Imageltem:
С помощью этих значений можно создать активную ссылку и оформить изображение в виде кнопки или гиперссылки. В разделе 4.9 при рассмотрении класса Stringltem мы уже сталкивались с этими значениями, создавая статический текст в виде кнопки и гиперссылки.
При загрузке изображений с помощью класса ImageItem существует ряд нюансов, на которые необходимо обратить внимание. Класс ImageItem является подклассом класса Image, прежде чем воспользоваться классом ImageItem, необходимо создать объект класса Image. Затем поместить или загрузить в объект класса Image изображение и только потом воспользоваться классом ImageItem для размещения изображения на экране представленного объектом класса Form. Создавая объект класса ImageItem, вы создаете своего рода контейнер для содержания ссылки на объект Image. Рассмотрим небольшой фрагмент кода, иллюстрирующий создание и загрузку изображения:
Image a = Image.createlmage("/ris.png"); Imageltem b = new Imageltem("Рисунок", а, ImageItem.LAYOUT_CENTER,null);
Первым делом создается объект i класса Image, после чего происходит загрузка необходимого изображения посредством вызова метода createlmage () класса Image. Далее создается объект im класса ImageItem, который будет содержать ссылку на объект image.
Изображение, загружаемое в приложение, может находиться в любом месте рабочего каталога. При использовании, например J2ME Wireless Tollkit 2.1, изображение лучше поместить в папку \res. Эта папка по умолчанию для файлов ресурса к разрабатываемому приложению и в этом случае запись /ris.png будет обращаться к папке \res. Если вы хотите использовать другую папку, то необходимо указать весь путь при загрузке изображения, например:
Image ikon1 = Image.createlmage("/Ikon/Leve12/ikon1.png"};
Рассмотрим пример загрузки изображения на экран в виде фона. В качестве изображения послужит фотография автора этой книги, которую мы загрузим и выведем на экран телефона. Код примера содержится в листинге 6.6 .
/** Листинг 6.6 Класс Imageltem */ import javax.microedition.midlet.*; import javax.microedition.Icdui.* ; public class MainClassImageltem extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 1); // объект класса Form private Form myform = new Form("Изображение"); // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassImageItem() { mydisplay = Display.getDisplay(this); } public void startApp() { // перехватываем исключительную ситуацию try{ // загрузка изображения Image image = Image.createlmage("/gornakov.png"); // создаем объект класса ItemImage Imagelfcem im = new ImageItem("Фотография", image, Imageltem.LAYOUT_CENTER,""); // добавляем изображение в форму myform.append(im) ; } catch(Java.io.IOException ex){} // установка обработчика событий для Form myform.addCommand(exitMidlet); myform.setCommandListener(this); // отразить текущий дисплей mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { // выход из приложения if (с == exitMidlet) { destroyApp(false); notifyDestroyed(); } } }
Рис 6.8. Изображение, загруженное при помощи класса Imageltem
Пример достаточно прост: происходит загрузка изображения на экран телефона представленного классом Form с добавлением команды выхода из приложения. Но после компиляции листинга 6.6 и запуска приложения на эмуляторе J2ME Wireless Toolkit 2.1, возникают цветовые дефекты в виде некачественного отображения фотографии. Это вызвано, прежде всего, минимальной цветовой гаммой, представляемой эмулятором J2ME Wireless Toolkit 2.1. Протестируйте код из листинга 6.6 на различных эмуляторах, рассмотренных в главе 4. На рис 6.8 показан эмулятор с изображением на экране фотографии.
Класс Item
Абстрактный суперкласс Item имеет иерархию из восьми подклассов. Каждый подкласс представляет один из элементов пользовательского интерфейса, например, класс Text Field, создает текстовые поля для ввода пароля, адреса электронной почты или просто числовых значений. Все восемь классов, по сути, устанавливают компоненты пользовательского интерфейса, которые встраиваются в форму определенную классом Form. На рис 6.2 изображена иерархия абстрактного суперкласса Item.
Рис. 6.2. Иерархия суперкласса Item
Любой из рассмотренных классов наследуется из суперкласса Item и может быть добавлен на экран, созданный классом Form. Каждый компонент класса Item содержит с левой стороны область; где при желании можно отобразить изображение в виде иконки. При перемещении компонента, иконка также перемещается вместе с компонентом. Класс Item с помощью имеющихся вcего составе директив задает, в основном, формат отображения для любого компонента. Формат определяет заданную ширину, высоту или выравнивание компонентов в форме, а также класс Item имеет множество методов осуществляющих контроль над компонентами.
Методы класса Item
При использовании вышеперечисленных методов можно настраивать и редактировать компоненты класса Item. В иерархии класса Item содержится ряд подклассов, обеспечивающих создание интуитивно понятного пользовательского интерфейса. Давайте рассмотрим эти подклассы.
Класс List
Класс List не входит в иерархию класса Item. Использование класса List дает возможность создавать выбираемый список элементов, отображаемый на экране в виде одной или нескольких строк текста. Класс List наследуется от класса Screen и реализует возможности интерфейса Choice. При создании выбираемого списка элементов необходимо указать тип создаваемого списка. Существует всего три типа списков, реализация которых основана на использовании интерфейса Choiсе:
Конструкция применения типов EXCLUSIVE и MULTIPLE напоминает использование этих типов в классе ChoiceGroup, а вот применение типа IMPLICIT возможно только с использованием класса List. При создании объекта класса List можно воспользоваться двумя видами конструкторов. Рассмотрим их более подробно.
public List(String title, int listType);
Параметры конструктора List:
Этот конструктор с двумя параметрами создает пустой список с заданным типом в параметре listType. Второй конструктор класса List несколько сложнее. Он состоит из четырех параметров и создает многострочный список элементов с загрузкой иконки или изображения для каждого элемента.
public List(String title, int listType, String[] stringElements, Image[] imageElements)
Параметры конструктора List:
Класс Spacer
Класс Spacer подвигает элемент на экране телефона, создавая тем самым свободное пространство с указанными размерами. Именно за создание свободного пространства на экране отвечает класс Spacer. При создании объекта класса используется один конструктор с двумя параметрами, при помощи которых задается создаваемое пространство на экране. Конструктор класса Spacer выглядит следующим образом:
public Spacer(int minWidth,int minHeight);
Параметры конструктора Spacer:
Класс Spacer имеет четыре метода, все они просты и не нуждаются в пояснениях, в приложении 2 находится справочник по платформе Java 2 ME, в котором вы сможете найти описание существующих методов класса Spacer. Чтобы показать работу класса Spacer, рассмотрим простой пример, где создается область в пятьдесят пикселей по ширине и ноль по высоте, благодаря чему элемент, размещенный в форме, сдвигается на указанное пространство вправо. В качестве элемента встроенного .в форму используется класс TextField. В листинге 6.5 дается исходный код примера.
/** Листинг 6.5 Класс Spacer */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassSpacer extends MIDlet implements CorranandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // объект класса DateField private Spacer sp; // объект класса Form private Form myform; // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassSpacer() { mydisplay = Display.getDisplay(this); } public void startApp() { // инициализируем объект sp sp = new Spacer(50,0); // создаем форму при помощи объекта Form myform = new Form("Класс Spacer"); // добавить объект sp myform.append(sp); myform.append(new TextField("Метку","Текст",20,TextField.ANY)); myform.addCommand(exitMidlet); myform.setCommandListener(this); // отразить текущий дисплей mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if(с = = exitMidlet) { destroyApp(false); notifyDestroyed(); } } }
В листинге 6.5 создается рабочий класс MainClassSpacer и форма на основе класса Form. Объявляется объект sp для класса Spacer и инициализируется в методе startApp (). При инициализации объекта sp используются два значения для параметров, создавая тем самым пустое пространство с левой стороны от текстового поля, созданного при помощи класса TextField. Эмулятор изображенный на рис. 6.7 показывает работу программы из листинга 6.5.
Класс Spacer был добавлен в Java 2 ME для профиля MIDP 2.0, нельзя сказать, что этот элемент жизненно необходим, но бывают случаи, когда использование класса Spacer облегчает работу программиста.
Рис 6.7. Пространство созданное классом Spacer
Класс Stringltem
Рассматриваемый класс позволяет интегрировать в форму строку текста, состоящую из двух частей - метки и заданного текста. Строка текста, выводимая на экран, не может быть изменена или отредактирована - это статический текст, жестко заданный в параметрах конструктора класса StringItem при создании объекта этого класса. Имеется два конструктора класса StringItem, разберем их устройство.
public StringItem(String label,String text)
Параметры конструктора класса Stringltem:
Второй конструктор класса Stringltem имеет три параметра и позволяет выбирать способ отображения текстовой информации.
public Stringltem(String label, String text, int appearanceMode)
Параметры конструктора Stringltem:
Значения, устанавливающие выше перечисленные действия содержаться в пакете javax.microedition.lcdui.Item, рассмотрим несколько из них.
При создании примера к классу Stringltem обязательно воспользуемся некоторыми значениями для параметра appearanceMode в конструкторе класса Stringltem.
Методы класса Stringltem
Пример, который будет предложен для класса StringItem, создаст форму при помощи класса Form и разместит в форме текст. Первая строка текста выполнена в виде простой статической надписи, вторая сделана как гиперссылка. Выделив эту строку текста и нажав кнопку на телефоне перейти, вы попадете на экран с новой формой. А последняя третья строка текста выполнена просто в виде кнопки. Рассмотрим листинг 6.4 иллюстрирующий работу данного примера.
/ * * Листинг 6.4 Класс Stringltem */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassStringltem extends MIDlet implements CommandListener, ItemCommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // команда перехода по нажатию кнопки private Command perexodButton = new Command("Дальше",Command.ITEM, 1); // команда перехода по гиперссылке private Command perexodHyperlink = new Command("Перейти", Command.ITEM, 1); // команда возврата в основное окно private Command vozvrat = new Command("Назад", Command.BACK, 1); // объект класса Form private Form myform, // объект mydisplay представляет экран телефона private Display mydisplay; public void startApp() { mydisplay = Display.getDisplay (this) ; myform = new Form("Класс Stringltem"); Stringltem si = new Stringltem("Метку", "Текст"); myform.append(si); // создать гиперссылку Stringltem s2 = new Stringltem("Гиперссылка", "www.dmk.ru",Item.HYPERLINK); s2.setDefaultCommand(perexodHyperlink); s2.setltemCommandListener(this); myform.append(s2); // создать текст в виде кнопки Stringltem s3 = new Stringltem("Кнопка","Опции",Item.BUTTON); s3.setDefaultCommand(perexodButton); s3.setltemCommandListener(this); myform.append(s3); myform.addCommand(exitMidlet); myform.setCommandListener(this); mydisplay.setCurrent(myform); } protected void destroyApp(boolean unconditional) {} protected void pauseAppO {} // обработчик класса ItemCommandListener public void commandAction(Command c, Item i) { // переход в окно опций if (с = = perexodButton) { Form f1 = new Form("Опции"); f1.append("Необходимые Опции"); f1.addCommand(exitMidlet) ; f1.addCommand(vozvrat); f1.setCommandListener(this) ; mydisplay.setCurrent(f1) ; } // переход по гиперссылке if (c = = perexodHyperlink) { Form f2 = new Form("Издательство ДМК"); f2.append("Сайт издательства ДМК"); f2.addCommand(exitMidlet); f2.addCommand(vozvrat); f2.setCommandListener(this); mydisplay.setCurrent(f2); } } public void commandAction(Command c, Displayable d) { // выход из приложения if(с == exitMidlet) { destroyApp(false); notifyDestroyed(); } // возврат в основную форму if(с = = vozvrat) mydisplay.setCurrent(myform); } }
В коде листинга 6.4 для наглядности не использовался конструктор основного класса мидлета MainClassStringltem, но добавлялся, как уже упоминалось новый интерфейс ItemCommandListener для установки обработки команд перехода в приложении. В методе startApp () происходит создание пустой формы для класса Form и интеграция класса Stringltem. В строке кода:
Stringltem si = new Stringltemf"Метку", "Текст");
Создается простой статический текст и выводится на дисплей телефона. Следующий блок кода:
Stringltem s2 =new Stringltem("Гиперссылка", "www.dmk.ru",Item.HYPERLINK); s2.setDefaultCommand(perexodHyperlink); s2.setItemCommandListener(this) ; myform.append(s2) ; Stringltem s3 = new Stringltem("Кнопка","Опции"",Item.BUTTON); s3.setDefaultCommand(perexodButton); s3.setltemCommandListener(this); myform.append(s3);
формирует текст на экране телефона, назначив для него обработчик событий при помощи метода setltemCommandListener(). Можно получить текст в виде активной ссылки. При создании объекта s2 класса Stringltem использовался конструктор с тремя параметрами. Последний параметр этого конструктора как раз и отвечает за вид создаваемой ссылки. Была создана гиперссылка с помощью константы HYPERLINK. Блоком кода с объектом s3 уже создавалась кнопка. Эта кнопка является так же простым статическим текстом, но оформленным в виде прямоугольной кнопки. Объекту s3 так же назначается обработчик событий методом setltemCommandListener (), благодаря чему и получается активная ссылка. Выбрав ее можно перейти в нужное место в приложении.
Теперь наша программа имеет два одноименных обработчика событий с разными параметрами, представленными двумя интерфейсами CommandListener и ItemCommandListener. Обработчик событий созданный при помощи метода commandAction (Command с, Item i), следит за двумя активными ссылками, выполненными в виде гиперссылки и кнопки. Выбрав одну из активных ссылок и воспользовавшись соответственной командой перехода perexodButton - для кнопки и реrexodHyperlink, вы попадете на экран с новой формой и информационной надписью. Оба новых экрана созданы классом Form, где так же имеются две команды: exitMidlet -для выхода из приложения и vozvrat — для возврата в основное окно. Эти две команды обрабатываются своим методом commandAction(Command с, Displayable d) интерфейса CommandListener. Для того, чтобы создать активную ссылку, необходимо воспользоваться интерфейсом ItemCommandListener, реализовав метод commandAction () для обработки необходимых событий. Рис. 6.6 показывает экран эмулятора с несколькими элементами класса Stringltem.
Рис. 6.6. Элементы класса Stringltem
Класс TextField
С помощью этого класса можно создать заданный по размеру контейнер, в который помещается редактируемый текст. Этот класс обычно используется в создании адресных книг или полей для ввода текста. Кроме текста также можно размещать любую числовую информацию. В классе TextField существует всего один конструктор с четырьмя параметрами, рассмотрим этот конструктор.
public TextField(String label, String text, int maxSize, int constraints)
Параметры конструктора класса Text Field:
Как видите, предусмотрены практически все варианты, остается только подставлять требуемые значения и наслаждаться простотой программирования под Java 2 ME. Использование вышеперечисленных директив в Java 2 ME традиционно и, например, для ввода адреса сайта может быть следующая запись:
TextField tf = new TextField("Адрес","",20,TextField.URL);
Методы класса TextField
Класс TextField содержит четырнадцать методов, некоторые из них мы сейчас рассмотрим.
Теперь перейдем непосредственно к примеру, реализующему возможности класса TextField. Создадим пустую форму, и вставим в нее поля в виде адресной книги. В листинге 6.3 дается код всего примера.
/** Листинг 6.3 Класс TextField */ import javax.microedition.midlet.*; -import javax.microedition.Icdui.*; public class MainClassTextField extends MIDlet implements CommandListenef { // команда выхода -из приложения private Command exitMidlet = new Command("Выход",Command.EXIT, 0) ; // объект класса Form private Form myform; // объект mydigplay представляет экран телефона private Display mydisplay; public MainClassTextFieldf) { mydisplay = Display.getDisplay(this); } public void startApp() { // создаем форму при помощи объекта Form myform = new Form("Класс TextField"); // добавить в форму поле для текста myform.append(new TextField( "Введите текст:","",20,TextField.ANY)); // добавить в форму поле для пароля myform.append(new TextField( "Введите пароль:","",20,TextField.PASSWORD)); // добавить в форму поле для e-mail myform.append(new TextField( "Введите E-mail:","",20,TextField.EMAILADDR)); // добавить в форму поле для URL myform.append(new TextField( "Введите URL:","",20,TextField.URL)); // добавить в форму поле для телефонного номера myform.append(new TextField( "Телефонный номер:","",20,TextField.PHONENUMBER)); myform.addCommand(exitMidlet); myform.setCommandListener(this); mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if(с = = exitMidlet) { destroyApp(false); notifyDestroyed() ; } } }
В листинге 6.3 создается пустая форма при помощи класса Form и вставляется несколько текстовых контейнеров для пароля, адреса электронной почты, веб-сайта и любой другой комбинации символов и цифр. Возьмем для наглядности первую строку кода, создающую текстовое поле для размещения символов и цифр:
myform.append(new TextField ("Введите текст:","",20,TextField.ANY));
Здесь используется упрощенная запись без создания объект класса TextField. Первый параметр конструктора TextField задает информационную строку текста - метку, поясняющую назначение данного текстового поля. В следующий параметр конструктора класса TextField, а точнее в переменную, отвечающую за текстовый массив данных, пользователь будет вводить необходимую информацию. Значение этого параметра пустое, но возможно поместить любой текст, который в последствии можно редактировать. Числовое значение 20 задает длину или количество введенных символов. Последний параметр использует константу ANY, дающую возможность вводить любую комбинацию символов и цифр.
Все созданные поля в листинге 6.3 используют, рассмотренную выше конструкцию программного кода и только в последнем параметре конструктора TextField, значение варьируется для пароля, e-mail, веб-сайта и телефонного номера. Задавая различные значения последнему параметру при создании объекта этого класса, вы можете создать набор необходимых полей. На рис. 6.5 изображен эмулятор, показывающий несколько полей класса TextField.
Рис. 6.5. Поля класса TextField
Класс Ticker
Объект класса Ticker служит для создания в приложении подобие бегущей строки, располагающейся в верхней части экрана. Текст, выводимый на экран объектом класса Ticker, перемещается справа налево с одинаковой скоростью. При достижении конца текста бегущая строка появляется заново, обеспечивая тем самым цикличности перемещения текста. На рис. 6.12 изображен эмулятор с бегущей строкой в. верхней части экрана.
Класс Ticker имеет один конструктор, необходимый в создании объекта этого класса, рассмотрим этот конструктор:
public Ticker(String str);
Параметры конструктора класса Ticker:
Создавая объекта класса Ticker с помощью рассмотренного конструктора, вы задаете значение для параметра str и эта строка текста будет циклично прокручиваться в программе.
Рис. 6.12. Объект класса Ticker создает в верхней части экрана бегущую строку
Методы класса Alert
Существует множество методов класса Alert, все они призваны создавать более насыщенные и информационные сообщения. Рассмотрим методы класса Alert.Использовать возможности класса Alert в приложении необходимо. Уведомления об ошибках и различные информационные сообщения улучшают пользовательский интерфейс разрабатываемой программы. В листинге 6.8 приводится простой пример, иллюстрирующий создание и отображении класса Alert на экране телефона.
/** Листинг 6.8 Класс Alert */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassAlert extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 1); // объект класса Alert Alert a1; // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassAlert() { mydisplay = Display.getDisplay(this); } public void startApp() { // перехватываем исключительную ситуацию try{ // загрузка изображения Image image = Image.createlmage("/error.png"); // объект класса Alert a1 = new Alert("Класс Alert",null, image, AlertType.ERROR); } catch(Java.io.IOException ex){ } al.addCommand(exitMidlet); al.setCommandListener(this); mydisplay.setCurrent(al); } public void pauseApp() {} public void destroyApp(boolean.unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if (с == exitMidlet) { destroyApp(false) ; notifyDestroyed() ; } } }
В листинге 6.8 создается класс MainClassAlert, являющийся основным классом мидлета. В самом начале всего кода происходит объявление необходимых переменных ив частности объекта a1 класса Alert. В методе startApp () создается объект класса Image, в котором будет содержаться загружаемое изображение. Изображение выполнено в виде информационной надписи об ошибке. На рис. 6.10 изображена работа класса Alert.
При загрузке изображения используется конструкция try {} catch () {} для обработки исключительных ситуаций. В остальном, я думаю, весь код ясен и каких-либо проблем с пониманием этой простой программы возникнуть не должно.
Рис 6.10. Информационное уведомление, созданное при помощи класса Alert
Методы класса Form
Благодаря вышеперечисленным методам все компоненты находящиеся в форме, могут быть отредактированы надлежащим образом, например:
Form myform = new Form("Пример"); myform.append (iteml); myform.append (item2);
В этом примере в созданную пустую форму добавляются два объекта. Оба объекта, разумеется, должны быть созданы в коде. Точно так же можно воспользоваться всеми методами класса Form для редактирования создаваемой формы. Добавленные в форму компоненты организованны в виде колонок и обычно располагаются по ширине всего экрана. На рис. 6.1 изображен эмулятор с несколькими компонентами интерфейса.
Рис. 6.1. Расположение элементов в форме
Все компоненты, встроенные в форму, жестко закреплены и не перемещаются. Редактировать компоненты можно при помощи методов класса Form, причем присоединенные компоненты располагаются друг под другом, выравниваясь горизонтально. Пользователь может перемещаться по компонентам формы с помощью клавиш Вверх и Вниз. Когда количество добавленных компонентов больше видимой части экрана телефона, то автоматически создается прокрутка. Внизу или вверху экрана появляется стрелочка, сигнализирующая об имеющихся компонентах, выпадающих из зоны видимости. При переходе в нижнюю > часть экрана, как только верхний компонент выйдет из зоны видимости, стрелочка автоматически развернется на 180°, указывая в направлений новых компонентов, выпадающих из зоны видимости. Такой механизм реализован в любом телефоне вне зависимости от производителя. Можно добавлять любое количество компонентов в форму, но очевидно, что необходимо задуматься и о дизайне пользовательского интерфейса и не валить все "в кучу". Наилучшим решением будет продуманная структура переходов с экрана на экран.
Методы класса Image
Все методы класса Image служат для загрузки изображений из файлов, ресурсов, потоков, а в некоторых методах можно задавать размеры и трансформацию изображений. Проанализируем основные методы класса Image.
В листинге 6.11 происходит загрузка изображения в приложение, но без использования объекта класса ImageItem, который использовался при рассмотрений примера в листинге 6.6 из раздела 6.8. В листинге 6.6 применялась ссылка на объект класса Image, в этом примере объект классу Image используется напрямую
/** Листинг 6.11 Класс Image */ import javax.microedition.midlet.*; import javax.microedition.Icdui.*; public class MainClassImage extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 1) ; // объект класса Form, private Form myform = new Form("Класс Image"); // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassImage() { mydisplay = Display.getDisplay(this); } public void startApp() { // перехватываем исключительную ситуацию try { // загрузка изображения Image im = Image.createlmage("Ygornakov.png"); // добавляем загружённый файл в форму myform.append(im); } catch(Java.io.IOException exp{ } // Установка обработчика событий для Form myform.addCommand(exitMidlet); myform.setCommandListener(this); // Отразить текущий дисплей mydisplay .s'etCurrent (myform) ; } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void сommandAction(Command c, Displayable*d) { // Выход из приложения if (с == exitMidlet) { destroyApp(false); notifyDestroyedf); } } }
На рис. 6.13 показан эмулятор телефона, воссоздающий загруженное изображение, посмотрите, насколько больше экран телефона и как разместилось меньшее по размеру изображение на дисплее.
Методы класса List
Класс List имеет множество методов, с помощью которых можно производить редакцию списка элементов, выбор заданного элемента и многое другое. Разберем часть методов класса List.
Теперь давайте создадим пример, описывающий основные возможности класса List. Класс List может создавать три списка элементов: Exclusive, Multiple и Implicit. Используем эту возможность и создадим код, реализующий все три типа. Основная идея создания примера для класса List сводится к следующему: при входе в приложение пользователь попадает в главное окно со списком из двух элементов Multiple и Implicit, а сам список этих двух элементов будет создан на основе типа Exclusive. Ко всем элементам списка будут загружаться свои иконки. Выбрав один из двух элементов списка курсором, пользователь должен нажать клавишу команды Выбор для перехода в программе. Оба элемента списка Multiple и Implicit будут представлять два разных типа списка. Выбрав один из элементов Multiple или Implicit, пользователь попадает на новый экран. Каждый из выбранных списков будет содержать ряд элементов иллюстрирующих работу типов Multiрlе и Implicit. Выбирая элементы из этих списков, пользователь будет получать информационное сообщение. В листинге 6.9 исходный код примера..
/** Листинг 6.9 Класс List */ import javax.microedition.midlet. *; import javax.microedition.Icdui.*; public class MainClassList extends MIDlet implements . CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // команда выбора элемента из списка private Command vibor = new Command!"Выбор", Command.SCREEN, 1); // команда возврата в главное окно private Command vozvrat = new Command("Назад", Command.BACK, 1}; // команда выбора элемента для типов Implicit и Multiple private Command OK = new Command("OK", Command.OK, 1); // массив, иконок для типа EXCLUSIVE Image[] iconEx = null; // массив иконок для типа Multiple Image t ] iconMu = null; // массив иконок для типа Implicit Image[] iconlm = null; // объект класса List для типа EXCLUSIVE private List mylistEx; // объект класса List для типа Multiple private List mylistMu; // объект класса List для типа Implicit private List mylistlm; // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassList() { mydisplay = Display.getDisplay(this); } public void startAppf) { // перехватываем.исключительную ситуацию; try { // загрузка изображения Image imagel = Image.createlmage("/iconMu.png"); Image image2 = Image.createlmage("/iconlm.png"); // поместить загруженные изображения в массив iconEx iconEx = new Image[] { image1, image2 }; // загрузка изображения Image imageB = Image.createlmage("/Multiple.png"); // поместить загруженные изображения в массив iconMu iconMu = new Image[]{image3, image3, image3, image3}; // загрузка изображения Image image4 = Image.createlmage("/Implicit.png"); // поместить загруженные изображения в массив iconIm iconIm = new Image[]{image4, image4, image4}; } catch(Java.io.IOException ex){ } // текст для двух элементов списка String[] st = {"Тип Multiple","Тип Implicit"}; // инициализация объекта mylistEx mylistEx = new List("Тип EXCLUSIVE", Choice.EXCLUSIVE, st, iconEx); // добавить команды mylistEx.addCommand(exitMidlet); mylistEx.addCommand(vibor); mylistEx.setCommandListener(this); // отразить текущий дисплей mydisplay.setCurrent(mylistEx); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if(с == exitMidlet) { destroyApp(false); notifyDestroyedf); } // возврат в главное окно if(с = = vozvrat) Display.getDisplay(this).setCurrent(mylistEx); // обработка команды OK if(с = = OK) { Alert a1 = new Alert(null,"Информационное уведомление", null, null); mydisplay.setCurrent(al); } // обработка команды vibor if(с == vibor) { // взять индекс выбранного элемента int i = mylistEx.getSelectedlndex(); // события для элемента "Тип Multiple" if(i = =0) { // текст для элементов списка String[] string = {"Меч","Щит","Нож","Копье"}; // инициализация объекта mylistMu mylistMu = new List("Тип MULTIPLE", Choice.MULTIPLE, string, iconMu); // добавить команду возврата mylistMu.addCommand(vozvrat); // добавить команду OK mylistMu.addCommand(OK); mylistMu.setCommandListener(this); // отразить текущий дисплей mydisplay. setCurrent (mylistMu) } // события для элемента "Тип Implicit" if (i = = 1) { // текст для элементов списка String[] string = {"Звук","Видео","Управление"}; // инициализация объекта mylistlm mylistlm = new List("Тип IMPLICIT", Choice.IMPLICIT, string, iconlm); // добавить команду возврата mylistlm.addCommand(vozvrat); // добавить команду OK mylistlm.addCommand(OK); mylistlm. setCommandListener (this); // отразить текущий дисплей mydisplay.setCurrent(mylistlm); } } } }
В листинге 6.9 создан класс MainClassList, являющийся основным классом мидлета программы. В начале исходного кода создаются команды для выхода из приложения - exitMidlet, для выбора элемента из списка - vibor, для возврата в главное окно приложения - vozvrat и команда ОК, обрабатывающая выбранный элемент из группы. За командами обработки событий следует объявление трех переменных: iconEx, iconMu и iconIm. Все три переменные будут содержать массив изображений или иконок для трех рассматриваемых в этом примере типов Exclusive, Multiple и Implicit класса List. Затем в коде:
private List mylistEx; private List mylistMu; private List mylistlm; private Display mydisplay;
Создаются три объекта класса List, представляющие три имеющихся типа элементов списка и объект mydisplay класса Display. Метод startApp() производит загрузку всех имеющихся иконок из папки \Code\Listing6_9\res с помощью метода createImage класса Image. Все загруженные иконки содержатся в переменных image1, image2, image3 и image4. При загрузке изображений используется конструкция try{} catch {) {} для перехвата исключительной ситуации. Все иконки размещаются в массивах iconEx, iconMu и iconIm для каждого типа элементов списка. В сроке кода
mylistEx = new List("Тип EXCLUSIVE", Choice.EXCLUSIVE, st, iconEx)
происходит инициализация объекта mylistEx. Используется конструктор класса из четырех параметров. Первый параметр конструктора класса List создает заголовок для всего экрана. Во втором параметре конструктора используется значение Choice.EXCLUSIVE. С помощью этого значения создается список элементов типа Exclusive, позволяющий выбрать только один элемент из всего списка. Третий параметр в конструкторе класса List принимает значение переменной st. Эта переменная содержит две строки текста, создавая тем самым только два элемента списка. Последний параметр загружает две иконки для обоих элементов списка.
В методе commandAction () происходит обработка всех .имеющихся команд созданных в приложении. Команда exitMidlet производит выход из приложения. Команда vozvrat возвращает пользователя в главное окно программы. Команда ОК показывает информационное сообщение, выполненное на основе класса Alert. Команда vibor осуществляет переход в выбранный экран представленный списком элементов двух различных типов Multiple и Implicit класса List. С помощью метода getSelectedIndex() берется индекс выбранного элемента из списка и на его основе в конструкции if /else происходит обработка выбранных событий. Два типа списков Multiple и Implicit создаются подобно списку типа Exclusive. Рис. 6.11 изображает эмулятор, на экране которого воспроизводится список элементов организованный с помощью класса List.
Рис. 6.11. Список элементов созданный классом List
В мобильных приложениях очень часто используются различные списки элементов, поэтому необходимо изучить возможности класса List более внимательно.
Методы класса Ticker
В составе класса Ticker существует всего два метода для получения и установки необходимой строки текста для приложения.
Также имеется возможность воспользоваться еще двумя методами абстрактного класса Displayable. Оба метода выполняют аналогичные действия методам класса Ticker, но при этом позволяют встраивать объект класса Ticker непосредственно в форму, то есть экран представленный классом Form. Разберем эти два метода:
Оба этих метода дублируют по сути методы класса Ticker. В листинге 6.10 приводиться образец применения класса Ticker.
/** Листинг 6.10 Класс Ticker */ import javax.microedition.midlet*; import javax.microedition.Icdui*; public class MainClassTicker extends MIDlet implements CommandListener { // команда выхода из приложения private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // объект класса Form private Form myform; // объект mydisplay представляет экран телефона private Display mydisplay; public MainClassTicker() { mydisplay = Display.getDisplay(this); } public void startApp() { // создаем форму при помощи объекта Form myform = new Form("Класс Ticker"); // создаем объект класса Ticker Ticker myticker = new Ticker("Бегущая строка"); // добавляем бегущую строку в форму myform.setTicker(myticker); // добавить команду выхода myform.addCommand(exitMidlet); myform.setCommandListener(this); mydisplay.setCurrent(myform); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { // выход из приложения if(с == exitMidlet) { destroyApp(false); notifyDestroyed() ; } } }
В листинге 6.10 создается пустая форма с помощью класса Form и объект класса Ticker с заданным текстом. Методом setTicker (), объект класса Ticker добавляется в форму, организовывая тем самым бегущую строку в верхней части экрана телефона.
Циклическое передвижение объекта по экрану
В листинге 7.5 был нарисован синий квадрат и перемещен один раз вдоль оси X горизонтально слева направо. Но иногда в играх необходимо циклично передвигать объект, используя его, например, в качестве мишени.
Возьмем за основу код из листинга 7.5, где перемещается квадрат, и сделаем так, чтобы после пересечения всего экрана и исчезновения, он снова появлялся с другой стороны, создавая подобие циклического перемещения. Алгоритм решения этой задачи заключается в том, чтобы узнать, когда квадрат выйдет из области видимости и в тот же момент нарисовать его с другой стороны экрана и вновь переместить по экрану. Для этого создадим переменную end и присвоим ей значение окончания экрана найденное методом getwidth () (движение происходит по ширине экрана).
int.end = getwidth();
В методе run () в самом начале цикла while будем производить постоянное сравнение позиции квадрата с окончанием экрана:
if (position > end) { position = 0; }
Как только квадрат будет выходить из области экрана, его позиция обнулится и квадрат снова будет нарисован в первоначальной позиции, что зациклит движение квадрата. В листинге 7.6 представлен исходный код решающий эту задачу.
/** Листинг 7.6 Класс Main и luiacq.Draw */ import javax.microedition.lcdui.*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener { // команда выхода из программы private Command exitMidlet = new Command("Выход",Command.EXIT, 0); public void startApp() { // создаем объект класса Draw Draw dr = new Draw(); // запускаем поток dr.start(); // добавляем команду выхода dr.addCommand(exitMidlet); dr.setCommandListener(this); Display.getDisplay(this).setCurrent(dr); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { if (c == exitMidlet) { destroyApp(false); notifyDestroyedt) ; } } } /** класс Draw определен в файле Draw.Java циклическое появление квадрата */ import javax.microedition.Icdui.*; public class Draw extends Canvas implements Runnable { // позиция для перемещения квадрата int position = 10; // узнаем ширину экрана int end = getwidth(); // конструктор public Draw() { super(); } public void start () { // создаем и запускаем поток Thread t = new Thread(this); t.start(); } // метод run интерфейса Runnable public void run() { // бесконечный цикл while (true) { // сравниваем позицию квадрата if(position > end) { // обнуляем позицию квадрата position = 0; } // увеличиваем позицию на 1 position ++; // обновляем экран repaint() ; // останавливаем цикл на 20 миллисекунд try { Thread.sleep(20); } catch (Java. lang. InterruptedException zxz) {} ) } public void paint(Graphics g) { // вычисляем область для перерисовки экрана int x = g.getClipWidth(); int у = g.getClipHeight(); // устанавливаем белый цвет фона g.setColor(0xffffff); // назначаем перерисовку всему экрану g.fillRect(0,0,х,у); //устанавливается синий цвет квадрата g.setColor(0, 0, 200); // рисуем квадрат g.fillRect(position,40, 20, 20); } }
Класс Canvas
Класс Canvas - это абстрактный класс, поэтому необходимо создавать подклассы для работы с классом Canvas. Абстрактный класс Canvas представляет некий обобщенный графический контекст, что позволяет программе производить прорисовку графики при помощи класса Graphics. Кроме этого класс Canvas предоставляет возможность в обработке событий полученных с клавиш телефона. Если классы высокоуровневого интерфейса, рассмотренные в главах 5 и 6, обрабатывают команды перехода, то-с помощью класса Canvas можно получать события с любой нажатой клавиши телефона.
Существует ряд так называемых "ключевых кодов" в виде заданных констант, с помощью которых можно назначать игровые действия для клавиш телефона. Все ключевые коды соответствуют стандарту ITU-T и заданны в виде следующих констант:
Ключевые коды GAME_A, GAME_B, GAME_C, GAME_D и FIRE предназначены специально для игровых действий и обычно задаются клавишам с цифрами соответственно 2,4,8,6 и 5, но зависят от реализации конкретных моделей телефонов.
Класс Graphics
При помощи класса Graphics осуществляется двухмерное представление графики на экране телефона. Класс Graphics существует также в составе Java 2 SE, но в платформе Java 2 ME он сильно урезан, всвязи с ограниченными системными ресурсами телефонов. Поэтому имеется возможность рисовать только линии, прямоугольники, дуги и текст. Для окрашивания этих примитивов предусмотрена работа с цветовой компонентой.
Система координат, используемая для представления графики в Java 2 ME, перевернута по отношению к обычной Декартовой системе координат. Начало системы координат, находится в левой верхней точке экрана телефона. Положительная ость X проходит по верхней кромке экрана слева направо, а положительная ось Y- сверху вниз по левой стороне экрана, как изображено на рис. 7.1.
Такая система координат отнюдь не новшество в программировании двухмерной графики. Идентичная модель координат применяется так же в DirectX и OpenGL для представления двухмерных сцен, но уже в компьютерной графике.
Рис. 7.1. Система координат в Java 2 ME
Механизм создания игрового цикла
Для создания цикла классом Canvas используется интерфейс Runnable и его единственный метод run (), в котором реализуется цикл прорисовки графики. Рассмотрим в качестве примера класс DemoGraphics и проанализируем его.
public class DemoGraphics extends Canvas implements Runnable { public void run() { while(true) { // обновление графических элементов repaint(); // задержка цикла на 20 миллисекунд для обновления состояния дисплея Thread.sleep(20); } } public void paint( Graphics g ) { // код, создающий графические элементы } public void keyPressed( int keyCode ) { // обработка событий с клавиш телефона при помощи ключевых кодов } }
В классе DemoGraphics для упрощения опущен основной код, связанный с прорисовкой графики и обработкой событий, поступающих с клавиш телефона. Весь цикл прорисовки графики состоит из трех методов: run (), paint () и keyPressed().
В методе paint () происходит создание и отрисовка графических элементов программы на экране телефона, а метод run () создает цикл, в котором происходит постоянное обновление экрана телефона, связанное, например, с движением графического элемента. События, полученные в результате нажатия клавиш, поступают в метод key Pressed (), где обрабатываются заданным вами способом. На основании этих событий также может происходить обновление цикла прорисовки графики.
В методе run () создается бесконечный цикл while (true). В реальной программе необходимо, конечно, предусмотреть выход из бесконечного цикла. Метод repaint () постоянно обновляет графические элементы. Метод sleep () класса Thread останавливает системный поток на двадцать миллисекунд, для того чтобы отреагировать на все произошедшие изменения, а именно, произвести обработку событий с клавиш телефона и перерисовать графический элемент на экране телефона. Механизм прорисовки графики в профиле MIDP 1.0 строится именно по такому принципу , связанному с изменением состояния графических элементов и называмому игровым циклом.
Теперь давайте рассмотрим как можно больше примеров, реализующих вывод графики на экран, перемещение графических элементов, обработку событий с клавиш телефона, столкновение графического элемента с препятствием и других хитростей, из которых состоят мобильные игры.
Методы класса Canvas
Большинство методов класса Canvas обеспечивают обработку низкоуровневых событий. Абстрактный метод void paint (Graphics g) является основным методом, с помощью которого происходит прорисовка графики на экране телефона. Класс Graphics определяет, что именно необходимо рисовать на экране телефона. Разберем основную часть методов класса Canvas:
Методы класса Graphics
Основные методы класса Graphics обеспечивают прорисовку двухмерной графики. Есть еще несколько методов, с помощью которых можно произвести перемещение системы координат и произвести отсечение (clipping). Основные методы класса Graphics:
При использовании некоторых методов, очень часто используется параметр int anchor. С помощью этого параметра задаются различные значения для выбора позиции. Посмотрите на рис. 7.2, где изображен механизм прорисовки текста с выбором определенной позиции.
Рис. 7.2. Техника прорисовки текста
Для этих целей в классе Graphics имеются константы, с помощью которых происходит выбор позиции:
Можно использовать две константы для выбора позиции. Например, для того чтобы сдвинуть текст влево и вверх, используется комбинация Graphics. LEFT I Graphics .TOP.
Далее мы перейдем к практике и изучим модель программирования графики в приложении на Java 2 ME, рассмотрим создание и отрисовку линий, прямоугольников, дуг и текста. Главное о чем надо помнить при использовании графических элементов - это о размере экрана телефона. Разные модели телефонов имеют свои размеры дисплея, и если вы будете использовать большой по площади экран, например 128x128 пикселей, то на экране с разрешением 101У80, некоторые части графических элементов будут срезаны. Чтобы этого избежать, надо использовать методы класса Canvas, getwidth () и getHeight (), которые возвращают размеры ширины и высоты экрана и уже на основании этих данных производить построение графических элементов, производя тем самым адаптацию графического контекста к конкретной модели телефона. Например, чтобы нарисовать, горизонтальную линию, не выходящую из зоны видимости, можно воспользоваться следующим кодом:
int w = getWidth.{); drawLine(20, 20, w-20, w-20);
В своих примерах к этой главе я специально не использую оптимизации графики, для того чтобы исходный код был более понятен. Поэтому после компиляции всех примеров обязательно запустите получившиеся программы на максимальном количестве имеющихся эмуляторов. Особенно попробуйте работу этих программ на эмуляторе DefaultColorPhone из состава среды программирования J2ME Wireless Toolkit 2.1, меня лично очень сильно позабавил результат работы этого эмулятора, а вам, я думаю, предоставит некоторую пищу для размышлений.
Перемещение квадрата
Начнем с самого простого - выведем на экран синий квадрат, прорисованный с помощью метода fillRect() и заставим переместиться его через весь экран по горизонтали слева на право. Посмотрите на код из листинга 7.5, производящий перемещение квадрата на экране.
/ * * Листинг 7.5 Класс Main и класс Draw */ import javax.micro-edition. Icdui .*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener { // команда выхода из программы private Command exitMidlet = new Command("Выход", Command.EXIT, 0); public void startApp() { // создаем объект класса Draw Draw dr = new Draw(); // запускаем поток dr.start(); // добавляем команду выхода dr.addCommand(exitMidlet); dr.setCommandListener(this); Display.getDisplay(this).setCurrent(dr); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { if (с == exitMidlet) { destroyApp(false) ; notifyDestroyed() ; } } /** класс Draw определен в файле Draw.Java перемещает квадрат по экрану */ import javax.microedition.lcdui.*; public class Draw extends Canvas implements Runnable { // позиция для перемещения квадрата int position =10; // конструктор public Draw() { super(); } public void start() { // создаем и запускаем, поток Thread t = new Thread(this); t.start(); } // метод run() интерфейса Runnable public void run() { // бесконечный цикл while (true) { // увеличиваем позицию на 1 position ++; // обновляем экран repaint(); // останавливаем цикл на 20 миллисекунд try { Thread.sleep(20); } catch (java.lang.InterruptedException zxz) {} } } public void paint(Graphics g) { // вычисляем область для перерисовки экрана int x = g.getClipWidth(); int у = g.getClipHeight () // устанавливаем белый цвет фона g.setColor(0xffffff); // назначаем перерисовку всему экрану g.fillRect(0,0,х,у); // устанавливается синий цвет квадрата vg.setColor(0, 0, 200); // рисуем квадрат g.fillRect(position,40, 20, 20); } }
Листинг 7.5 содержит два класса Main и Draw, находящиеся в файлах Main.java и Draw.Java. Основной класс мидлета Main содержит код создающий объект dr класса Draw. Затем он запускает системный поток с помощью метода start (), добавляет команду выхода из программы и отображает текущий дисплей с объектом dr. Класс Draw содержит код, создающий синий квадрат и перемещающий его по экрану. Прежде чем мы начнем рассмотрение кода класса Draw, давайте подумаем, как можно произвести перемещение объекта на экране. Самый простейший способ перемещения объекта по экрану вдоль оси X, заключается в постоянном увеличении, допустим на единицу, позиции этого объекта по оси X. При создании квадрата методом fillRect () задаются две координаты по оси X и по оси Y для первоначального вывода квадрата на экран. Поэтому достаточно создать переменную для координаты по оси X и затем в цикле прорисовки увеличивать ее на единицу, перемещая тем самым объект по экрану.
В листинге 7.5 класс Draw наследуется от класса Canvas, что дает возможность воспользоваться Методом paint (). для рисования графических элементов на экране и. реализации метода run () интерфейса Runnable. В методе run () создается цикл, постоянно обновляющий состояние графических элементов.
В начале кода класса Draw создается переменная position, отвечающая за координату по оси X для точки вывода квадрата на экран. Конструктор класса Draw вызывает метод super () для использования конструктора своего суперкласса Canvas.
В методе start () создается системный поток, который будет запущен в методе run (). Кстати, было бы не плохо предусмотреть выход из потока. Этот пример небольшой и проблем с ним не возникнет, а после разбора листинга 7.5, мы рассмотрим простой механизм, останавливающий системный поток и предусматривающий выход из бесконечного цикла while метода run (). В самом методе run () создается бесконечный цикл, в котором происходит постоянное увеличение переменной position на единицу, благодаря чему квадрат перемещается по оси X слева направо.
В методе paint () вас должны заинтересовать следующие строки кода:
int х = g.getClipWidthf); int у = g.getClipHeight(); g.setColor(0xffffff); g.fillRect(0,0,x,y);
Здесь используется отсечение (clipping) необходимое для корректной прорисовки графики. Если не использовать отсечение, то после того как вы нарисуете квадрат и начнете передвигать его, на экране будет рисоваться слева на право одна толстая синяя линия. То есть будет происходить постоянная перерисовка квадрата в новой позиции по оси X, но при этом будет оставаться и предыдущий нарисованный квадрат. Чтобы этого избежать имеется два способа: можно стирать определенный участок экрана, а можно просто перерисовывать цвет фона всего экрана. Такая операция в Java 2 ME называется отсечением, и для произведения этой операции используются методы: getClipWigthf) и getClipHeight (), производящие отсечение поверхности всего экрана и методы getClipX () и getClipY () для более точного указания координат заданной области экрана для отсечения. По сути, использование этих методов приводит к простому обновлению всего экрана либо заданной области экрана. В этом примере мы будем использовать перерисовку всего фона экрана. Ширина и высота экрана узнается с помощью методов getClipWigth () и getClipHeight (), полученные значения сохраняются в переменных х и у. Вызовом метода setColor () устанавливается белый цвет фона и в следующей строке кода задается прямоугольник для области отсечения:
g.fillRect(0, 0, х, у );
В конце метода paint () рисуем синий квадрат:
g.fillRect(position, 40, 20, 20);
С каждым проходом через графический цикл, цвет фона будет перерисовываться и стирать прошлую позицию квадрата, а квадрат постоянно перерисовывается на новом месте в соответствии со значением переменной position, что и создает иллюзию передвижения объекта по экрану телефона.
После компиляции примера из листинга 7.5, на экране появится синий квадрат и пересечет один раз дисплей телефона слева направо. Теперь что касается бесконечного цикла while. В методе run () в реальном приложении необходимо предусмотреть выход из него, а так же позаботиться о прекращений работы потока. Самый простой способ заключается в создании переменной отвечающей за состояние цикла в начале класса Draw, например:
boolean z;
Дальше в методе start () присвоить этой переменной значение true.
public void start() { z = true; Thread t = new Thread(); t.start(); }
А в методе run () использовать значение переменной z для входа в цикл
while while(z) { // код цикла }
Для логического конца создается новый метод stop () в классе Draw, назначая переменной z значения false.
public void stop() { z = false; }
Вызовем этот метод в классе Main в методе destroyApp ():
public void destroyApp(boolean unconditional) { z.stop (); }
Перемещение объекта с помощью клавиш
Перемещение объекта по экрану телефона с помощью клавиш телефона, это, пожалуй, самое главное действие в играх. Для передвижения нужно воспользоваться методом key Pressed () и описать код производящий обработку событий получаемых с клавиш телефона. При реализации метода keyPressed (), сначала необходимо вызвать метод getGameAction () для получения ключевого код"! с последующей его обработкой. Для обработки полученного ключевого кода можно применить оператор switch и тогда метод keyPressed () может принять следующий вид:
protected void keyPressed(int keyCode) { // получаем игровые события int act = getGameAction{keyCode); // обработка событий switch(act) { case Canvas.LEFT: // движение влево break; case Canvas .RIGHT: // движение вправо break; case Canvas.UP: // движение вверх break; case Canvas.DOWN: // движение вниз break; default: break; } } }
Код обработки для клавиш зависит от того, что именно вы желаете сделать с объектом. Давайте возьмем за основу код из листинга 7.5, где был нарисован квадрат, и модернизируем его. Выведем синий квадрат на экран, для этого создадим две переменные positionX и positionY, отвечающие за точку вывода квадрата на экран и присвоим им значения близкие к центру экрана.
int positionX. = getWidth()/2; int positionY = getHeight()/2;
При нажатии клавиш можно воспользоваться значениями переменных positionX и positionY для перемещения квадрата по экрану, увеличивая или уменьшая значения этих двух переменных. Значение, на которое вы будете увеличивать или уменьшать переменные, фактически будет обозначать скорость перемещения квадрата по экрану. В листинге 7.8 дается полный код программы перемещения элемента по экрану с помощью клавиш.
/** Листинг 7.8 Класс Main и класс Draw */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener . { // команда выхода из программы private Command exitMidlet = new Command("Выход", Command.EXIT, 0); public void startApp() { // создаем объект класса Draw Draw dr = new Draw(); // запускаем поток dr.start(); // добавляем команду выхода dr.addCommand(exitMidlet); dr.setCommandListener(this); Display.getDisplay(this).setCurrent(dr); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void сommandAction(Command c, Displayable d) { if (c = = exitMidlet) { destroyApp(false); notifyDestroyed() } } } /** класс Draw определен в файле Draw.Java передвижение квадрата с помощью клавиш телефона */ import javax.microedition.Icdui.*; public class Draw extends Canvas implements Runnable { // устанавливаем квадрат в центр экрана int positionX = getwidth()/2; // устанавливаем квадрат в центр экрана int positionY = getHeight()/2; // конструктор public Draw() { super(); } public void start() { // создаем и запускаем поток Thread t = new Thread(this); t.start(); } // метод run интерфейса Runnable public void run() { // бесконечный цикл while (true) { // обновляем экран repaint(); // останавливаем цикл на 20 миллисекунд try { Thread, sleep (20) ,- } catch (Java.lang.InterruptedException zxz) {} } } public void paint(Graphics g) { // вычисляем область для перерисовки экрана int x = g.getClipWidth(); int у = g.getClipHeight(); // устанавливаем белый цвет фона g.setColor(0xffffff); // назначаем перерисовку всему экрану g.fillRect(0,0,х,у); // устанавливается зеленный цвет квадрату g.setColor(0, 0, 200); 7/ рисуем квадрат g.fillRect(positionX, positionY, 20, 20); projected void keyPressed(int keyCode) // скорость передвижения int speed = 3 ; // получаем игровые события int act = getGameAction(keyCode); // обработка событий switch(act) { // движение влево case Canvas.LEFT: positionX -= speed; break; // движение вправо case Canvas.RIGHT: positionX += speed; break; // движение вверх case Canvas.UP: positionY -= speed; break; // движение вниз case Canvas.DOWN: positionY += speed; break; default: break; } } }
В следующей главе рассматриваются игровые классы, доступные в профиле MIDP 2.0 и значительно упрощающие создание игрового цикла, а также игровом графики.
Рисование дуг
В английском языке слово arc означает дугу, и именно это слово применяется в документации по Java 2 ME. Используя методы drawArc () и fillArc () можно нарисовать как дугу, так и полноценную окружность. Используя оба метода, как вы уже наверно заметили можно нарисовать контур дуги и закрашенную цветом дугу. Методы drawArc () и fillArc () имеют одинаковое количество параметров со сходными действиями. Рассмотрим один из методов - fillArc ().
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
Параметры метода fill Arc():
На рис. 7.5 изображена схематично техника создания дуги.
Рис. 7.5. Техника создания дуги
В листинге 7.3 приведен пример кода создающего три разноцветных сегмента круга, наложенных друг на друга, и дугу в виде контура.
/** Листинг 7.3
Класс Main и класс Arc */ import javax.microedition. Icdui.*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener { // команда выхода из программы private Command exitMidlet = new Command("Выход", Command.EXIT, 0) public void startApp() { // создаем объект класса Arc Arc myarc = new Arc(); // добавляем команду выхода myarc.addCommand(exitMidlet); myarc.setCommandListener(this); Display.getDisplay(this).setCurrent(myarc); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { if (c = = exitMidlet) { destroyApp(false); notifyDestroyed(); } } /** класс Arc определен в файле Arc.Java рисует дуги */ import javax.microedition.Icdui.*; public class Arc extends Canvas { // конструктор public Arc(){ super(); } public void paint(Graphics g) { // устанавливается красный цвет g.setColor(255, 0, 0); // рисуем первую заполненную цветом дугу g.fillArc(15, 15, 60., 60, 45, 360); // устанавливается зеленый цвет g.setColor(0, 255, 0) ; // накладываем вторую дугу поверх первой g.fillArc(15, 15, 60, 60, 45, 180); // устанавливается синий цвет g.setColor(0, 0, 255); // накладываем третью дугу поверх первых двух g.fillArc(15, 15, 60, 60, 45, 90); // устанавливается синий цвет для дуги в виде контура g.setColor(0, 0, 255); // рисуем контур дуги g.drawArc(5, 5, 80, 80, 30, 180); } }
В листинге 7.3 используется тот же самый механизм, что и в примерах из листингов 7.2 и 7.1 - создаются два класса: Main и Arc, находящиеся в файлах Main.java и Arc.java. Все действия по прорисовке дуг осуществляются в методе paint().
g.setColor(255, 0,0); g.fillArc(15, 15, 60, 60, 45, 360);
В этих строках кода происходит установка цвета для рисуемой дуги и происходит прорисовка самой дуги. Первые два значения в методе fillArc () - 15 и 15 пикселей задают координаты точки в пространстве, относительно которой будет происходить прорисовка дуги. Значения 60 и 60 пикселей задают ширину и высоту дуги. Значением 45 устанавливается угол для начала рисования дуги (со значением 360 будет нарисована замкнутая окружность). Затем в примере рисуются еще два сегмента зеленого и синего цвета, наложенные поверх первой нарисованной дуги.
Рисование линий
Для того чтобы нарисовать линию нужно воспользоваться методом draw-Line () класса Graphics. Рассмотрим прототип этого метода:
public void drawLine(int x1, int y1, int x2, int y2)
Параметры метода drawLine ():
Задавая целочисленные координаты точек в методе drawLine () можно нарисовать любую линию заданного размера. Также можно воспользоваться методом setColor() для закрашивания линий цветом и методом setStrokeSty le () -для рисования линии в виде пунктира.
Рассмотрим пример кода находящийся в листинге 7.1, где с помощью линий рисуется система координат используемая в Java 2 ME.
/ * * Листинг 7.1 Класс Main и класс Line */ import javax..microedition.lcdui .*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener { // команда выхода из программы private Command exitMidlet = new Command("Выход",Command.EXIT, 0); public void startApp() { // создаем объект класса Line Line myline = new Line(); // добавляем команду выхода myline.addCommand(exitMidlet); myline.setCommandListener(this); Display.getDisplay(this).setCurrent(myline); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { if (c = = exitMidlet) { destroyApp(false); notifyDestroyed(); } } } /** класс Line определен в файле Line.Java */ import javax.microedition.Icdui.*; public class Line extends Canvas { // конструктор public Line(){ super(); } public void paint(Graphics g) { // устанавливается синий цвет для линий g.setColor(0x0000ff); // рисуется система координат g.drawLine(20, 20, 90, 20); g.drawLine(20, 20, 20, 90) g.drawLine(90, 20, 80, 10) g.drawLine(90, 20, 80, 30) g.drawLine(20, 90, 10, 80) g.drawLine(20, 90, 30, 80) // устанавливается красный цвет для трех линий g.setColor(0xffff0000); // рисуем толстую линию, в три пикселя g.drawLine(30, 30, 70, 30); g.drawLine(30, 31, 70, 31); g.drawLine(30, 32, 70, 32); // устанавливаем пунктир g.setStrokeStyle(Graphics.DOTTED) ; // рисуем линию в два пикселя пунктиром g.drawLine(30, 50, 70, 50); g.drawLine(30, 51, 70, 51); } }
В листинге 7.1 используются два класса: Main, являющийся основным классом мидлета приложения, и класс Line, в котором происходит работа с графикой. Подразумевается, что оба класса находятся в файлах Main.java и Line.java, это характерно для объектно-ориентированного программирования и в дальнейшем мы будем придерживаться именно такой модели построения изучаемых примеров. Основной класс мидлета Main очень прост. В этом классе создается объект класса Line, добавляется команда выхода из приложения и отражается текущий экран. Класс Line, находящийся в файле Line.java листинга 7.1, рисует набор различных линий. Сам класс Line наследуется от абстрактного класса Canvas. В более сложных программах может использоваться интерфейс Run-nable и метод run (). Такая техника программирования обычно используется при создании игр, и будет обсуждаться в конце этой главы.
Конструктор класса Line использует метод super () позволяющий обратиться к конструктору своего суперкласса Canvas. Основные же события происходят в методе paint () класса Canvas.
В строке кода:
g.setColor(OxOOOOff)
происходит назначение цвета для любого последующего отрисованного примитива. То есть вызов метода setColor () с заданным цветом действителен до момента последующего вызова метода setColor (), устанавливающего другой цвет. В этом примере используется метод setColor (RGB), поэтому значение цвета задается восьмеричным значением с помощью нулей и букв. В следующем примере из раздела 7.4 при рисовании прямоугольников будет показана работа метода setColor () с тремя целочисленными параметрами, задающими значение цвета.
В строках кода
g.drawLine(20, 20, 90, 20) g.drawLine(20, 20, 20, 90) g.drawLine(90, 20, 80, 10) g.drawLine(90, 20, 80, 30) g.drawLine(20, 90, 10, 80) g.drawLine(20, 90, 30, 80)
рисуется шесть синих линий, образующих систему координат. Толщина всех линий равна одному пикселю - это значение по умолчанию и изменить его нельзя. Для того чтобы нарисовать широкую линию, придется рисовать несколько соприкасающихся одинаковых по размеру линий.
g.drawLine(30, 30, 70, 30); g.drawLine 30, 31, 70, 31); g.drawLine(30, 32, 70, 32);
Этими строками кода рисуется одна толстая линия шириной в три пикселя.
В конце в методе paint () рисуется линия толщиной в два пикселя в виде пунктирной линии. Для этого используется метод setStrokeStyle () и константа DOTTER. На рис. 7.3 изображен эмулятор телефона с результатом работы программы из листинга 7.1.
Рис. 7.3. Рисование разноцветных линий
Рисование прямоугольников
При создании прямоугольников можно использовать два метода класса Graphics- это drawRect() и fillRect (). При помощи метода drawRect () рисуется только контур прямоугольника, а метод fillRect () позволяет нарисовать прямоугольник уже закрашенным каким-либо цветом (изначально по умолчанию цвет черный). Оба метода абсолютно идентичны по количеству и назначению параметров, поэтому рассмотрим прототип одного из них, а именно метода drawRect ().
public void drawRect(int x, int y, int width, int height)
Параметры метода drawRect ():
В составе класса Graphics имеется еще один метод рисующий прямоугольник, но с закругленными углами - drawRoundRqct (). Этот метод имеет уже шесть параметров, где первые четыре параметра работают в том же ключе что и методы drawRect () и fillRect (), а два последних параметра определяют степень закругленности углов. В листинге 7.2 рисуется три разных по размеру прямоугольника, и закрашиваются тремя цветами: красным, зеленым и синим. Для закрашивания прямоугольников применяется метод setColor (int red, int green, int blue) с тремя параметрами. Выставляя любое целочисленное значение от 0 до 255 для каждого параметра можно создавать разнообразную цветовую гамму, естественно учитывая при этом цветовые возможности телефона, на котором будет работать эта программа. Для того чтобы определить доступную цветность дисплея телефона, необходимо воспользоваться методами класса Display:
/** Листинг 7.2 Класс Main и класс Rectangles */ import javax. micro-edit ion. Icdui.*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener { // команда выхода из программы private Command exitMidlet = new Command("Выход", Command.EXIT, 0); public void startAppO { // создаем объект класса Rectangles Rectangles myrec = new Rectangles(); // добавляем команду выхода myrec. addCommand( exitMidlet); myrec.setCommandListener(this); Display.getDisplay(this).setCurrent(myrec); } public void pauseApp() {} public void destroyApp(boolean unconditional){} } public void coiranandAction(Command c, Displayable d) { if (c == exitMidlet) { destroyApp (false) ,notifyDestroyed(); } } } / * * класс Rectangles определен в файле Rectangles.Java, */ import javax..microedition. Icdui ; public class Rectangles extends Canvas { // конструктор public Rectangles(){ super(); } public void paint(Graphics g) { // устанавливается красный цвет g.setColor(255, 0,0); // рисуем первый прямоугольник g.fillRect(/*x*/ 15,/*у*/ 30,/*ширина*/ 15,/*высота*/ 20); // устанавливается зеленный цвет g.setColor(0, 255, 0); // рисуем второй прямоугольник g.fillRect(30, 30, 15, 45); // устанавливается синий цвет g.setColor(0, 0, 255); // рисуем третий прямоугольник g.fillRect(45, 30, 15, 60); // устанавливается синий цвет g.setColor(255, 0, 0); // рисуем прямоугольник с закругленными углами g.drawRoundRect(70, 30, 40, 40, 10, 10); } }
В этом примере также используются два класса - класс Main, играющий роль основного класса мидлета и класс Rectangles, где происходит отрисовка графики. Оба класса разделены на два файла Main.java и Rectangles.java. В классе Main создается объект класса Rectangles, добавляется команда выхода и показывается текущий экран. Класс Rectangles является подклассом класса Canvas. Прорисовка прямоугольников происходит в методе paint () класса Graphics.
g.setColor(255, 0, 0) ;
В этой строке кода устанавливается красный цвет для прямоугольника размером 15 на 20 пикселей, который рисуется с помощью метода fillRect ().
g.fillRect(/*x*/ 15,/*у*/30,/*ширина*/15,/*высота*/20);
Прямоугольник рисуется закрашенным в красный цвет. Дальше происходит прорисовка еще двух закрашенных в зеленый и синий цвет прямоугольников с размерами соответственно 15x45 и 15x60 пикселей.
В конце всего кода в классе Rectangles рисуется контур прямоугольника с закругленными углами. На рис. 7.4 изображен эмулятор телефона с четырьмя нарисованными прямоугольниками.
Рис. 7.4. Рисование четырех прямоугольников
Столкновение
В предыдущем разделе 7.9 мы выведи на экран синий квадрат, задали ему вектор движения и перемещали квадрат горизонтально через весь экран. После того как квадрат исчезал, достигнув конца экрана, он циклично появлялся вновь с другой стороны. Следующий пример иллюстрирует столкновение круга и квадрата с препятствием, а именно, окончанием экрана телефона. Оба объекта рисуются независимо друг от друга по высоте экрана и перемещаются параллельно по горизонтали слева на право. По достижению конца экрана оба объекта отталкиваются от конца экрана и начинают движение в обратном направлении. Посмотрите на листинг 7.7, где приводится код программы осуществляющий эти действия. Эта программа состоит из двух файлов Main.java и Draw.java./** Листинг 7.7 Класс Main и класс Draw */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; public class Main extends MIDlet implements. CommandListener { //команда выхода из программы private Command exitMidlet = new Command("Выход", Command.EXIT, 0); publicvoid startApp() { // создаем объект класса Draw Draw dr = new Draw(); // запускаем поток dr.start(); // добавляем команду выхода dr.addCommand(exitMidlet) ; dr.setCommandListener(this); Display.getDisplay(this).setCurrent(dr); } public void pauseApp() {} public void destroyApp(boolean unconditional)} public void сommandAction(Command c, Displayable d) { if (c == exitMidlet) { destroyApp(false); notifyDestroyed(); } } } /** класс Draw определен в файле Draw.Java рисует круг и квадрат */ import javax.microedition.Icdui.*; public class Draw extends Canvas implements Runnable { // позиция для перемещения квадрата и круга int position = 0; // узнаем ширину экрана int endX = getWidth(); // конструктор public Draw() { super(); } public void start() { // создаем и запускаем поток Thread t = new Thread(this); t.start(); } //метод run интерфейса Runnable public void run() { // бесконечный цикл while (true) { // сравниваем позицию if(position > endX) { //уменьшаем позицию position = endX; } // увеличиваем позицию на 1 position ++; // обновляем экран repaint(); // останавливаем цикл на 20 миллисекунд try { Thread.sleep(20); } catch (java.lang.InterruptedException zxz) {} } } publie void paint(Graphics g) { // вычисляем область для перерисовки экрана int х = g.getClipWidth() ; int у = g.getClipHeight () ; // устанавливаем желтый цвет фона g.setColor(0xffff00); // назначаем перерисовку всему экрану g.fillRect(0,0,x,y); // устанавливается синий цвет квадрата g.setColor(0, 0, 200); // рисуем квадрат g.fillRect(position, 40, 20, 20); // устанавливается красный цвет круга g.setColor(250, 0,0); // рисуем круг fillArc(position, 10, 20, 20, 45, 360); } }
В файле Main.java создается объект класса Draw, запускается системный поток и отражается текущий экран. Файл Draw.java содержит полную реализацию класса Draw. Начальные позиции квадрата и круга определяются переменной position, которой задано нулевое значение. Для того чтобы определить момент столкновения, необходимо знать точку или координаты препятствия. В этом примере как препятствие применяется конец экрана с правой стороны, поэтому с помощью метода getWidth () находится конец экрана.
int endX = getWidth();
В последствии значение переменной endx будет использовано для определения столкновения.
Конструктор, класса Draw обращается к конструктору своего суперкласса Canvas. В методе run() и цикле while с помощью оператора отношения if происходит сравнение текущей позиции двух объектов и конца экрана.
if (position > endX) { position = endX -; }
После того как позиция обоих объектов становится больше значения переменной endx, то есть квадрат и круг достигают конца экрана, то происходит уменьшение переменной position. Это приводит к движению объектов в обратном направлении.
После компиляции примера на экране появятся два движущихся слева направо объекта. Мы использовали препятствие в виде одной стороны экрана, но точно таким же образом можно определить столкновение для всех сторон экрана или просто для статических объектов. Выполните эти упражнения в качестве домашнего задания, а также внимательно посмотрите на процесс работы примера из листинга 7.7, квадрат и круг все-таки не отталкиваются от кромки экрана, а исчезают. Это происходит, потому что опорная позиция объектов находится в левом верхнем углу и столкновение происходит именно с позицией объектов* Вы знаете размер круга и квадрата, подумайте как можно определить более точную точку столкновения объектов и кромки экрана.
Вывод текста
Для вывода текста на экран телефона можно воспользоваться методами drawstring () и drawChar (), рисующими соответственно строка-текста и любой назначенный символ. Текст можно выводить с любым цветом, а также использовать стили начертания, изученные в главе 6. Прототип метода drawstring () выглядит следующим образом:
public void drawstring (String str, int x, int y, int anchor)
Параметры метода drawstring ():
В листинге 7.4 показан пример вывода текста на экран телефона. Код довольно прост и я думаю, вам не составит труда разобраться в нем самостоятельно.
/** Листинг 7.4 Класс Main и класс Text */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; public class Main extends MIDlet implements CommandListener { // команда выхода из программы private Command exitMidlet = new Command("Выход", Command.EXIT, 0); public void startApp() { // создаем объект класса Text Text mytext = new Text(); // добавляем команду выхода mytext.addCommand(exitMidlet); mytext.setCommandListener(this); Display.getDisplay(this).setCurrent(mytext); } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void сommandAction(Command c, Displayable d) { if (c = = exitMidlet) { destroyApp(false) ; notifyDestroyedf); } } } /** класс Text определен в файле Text.Java рисует текст */ import javax.microedition.lcdui.*; public class Text extends Canvas { // конструктор public Text(){super(); } public void paint(Graphics g) { // устанавливается цвет g.setColor(10, 80, 200); // рисуем строку текста g.drawstring("Java 2 Micro Edition", 80, 40, Graphics.TOP | Graphics.HCENTER); } }
Анимация в игровом процессе
Анимация в игровом процессе строится на основе последовательной цепочки рисунков. Как вы уже знаете, отдельно взятый рисунок из анимационной последовательности в Java 2 ME называется фреймом. Для того чтобы осуществить плавную анимацию в игре, необходимо выполнить ряд сменяющих друг друга рисунков. Посмотрите на рис. 8.3, где изображен матрос с флажками.
Рис. 8.3. Анимационная последовательность
На рис. 8.3 все фреймы выполнены в виде горизонтальной цепочки, но это не обязательное условие, можно расположить фреймы любым удобным образом. Не забывайте о том, что отсчет начинается с нуля и идет слева направо и сверху вниз.
Анимация повсеместно используется в компьютерных и мобильных играх. Вы наверно замечали, что при перемещении в игре персонажа, он производит ряд повторяющихся движений, создавая видимость игрового цикла. Такие элементарные движения следствие перехода" по имеющимся фреймам исходного изображения. Для этих целей в Java 2 ME имеются специальные методы класса Sprite.
Метод nextFrame () позволяет осуществить переход по всем имеющимся фреймам исходного изображения. Как только достигается последний фрейм, то автоматически происходит переход к первому фрейму с последующим переходом по всей имеющейся последовательности, что обеспечивает цикличность анимации.
Давайте рассмотрим пример использующий анимационную последовательность, изображенную на рис. 8.3. В этом примере на экран выводится изображение матроса и осуществляется цикличный переход По всем имеющимся фреймам, создавая эффект движения матроса, который с помощью семафорной азбуки передает слово "анимация".
В листинге 8.3, а так же на компакт-диске в папке \Code\Listing8_3\src дается код примера иллюстрирующего работу анимационной последовательности.
/** Листинг 8.3 класс MainGame */ import javax.microedition.lcdui.*; import javax.microedition.midlet. * ; public class MainGame extends MIDlet implements CornmandListener { // команда выхода private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // объект класса MyGameCanvas private MyGameCanvas mr; public void startApp() { // обрабатываем исключительную ситуацию try{ // инициализируем объект класса MyGameCanvas mr = new MyGameCanvas(); // запускаем поток mr .start(); // добавляем команду выхода mr.addCommand(exitMidlet); mr:setCommandListener{this); /7 отражаем текущий дисплей Display.getDisplay(this).setCurrent(mr); }catch (Java.io.lOException zxz) {}; } public void pauseApp() {} public void destroyApp(boolean unconditional) { // останавливаем потоку if(mr != null) mr.stop(); } public void commandAction(Command c, Displayable d) { if (с == exitMidlet) { destroyApp(false); notifyDestroyedO ; } } } /** файл MyGameCanvas.java класс MyGameCanvas */ import java.io. import javax.microedition.Icdui.*; import javax.microedition.Icdui.game.*; public class MyGameCanvas extends GameCanvas implements Runnable { // создаем объект класса MySprite private Matros matros; // создаем объект класса LayerManager private LayerManager lm; // логическая переменная boolean z; public MyGameCanvas() throws IOException { // обращаемся к конструктору суперкласса Canvas super(true); // загружаем изображение Image im = Image.createlmage("/matros.png"); // инициализируем объект matros matros = new Matros(im, 94, 100); // выбираем позицию matros.setPosition(30, 30); // инициализируем менеджер уровней 1m = new LayerManager(); // добавляем объект матроса к уровню lm.append(matros); } public void start() { { z= true; // создаем и згшускаем поток Thread t = new Thread(this); t.start () ; } // останавливаем поток public void stop() { z = false; } public void run() { // получаем графический контекст Graphics g = getGraphics(); while (z) { // рисуем графические элементы init(g) // останавливаем цикл try { Thread.sleep(250); } catch (Java.lang.InterruptedException zxz) {}; } } private void init(Graphics g) { // белый цвет фона g.setColor(0xffffff); // перерисовываем экран g.fillRect(0, 0, getWidth(),getHeight()); // рисуем уровень в точке 0,0 lm.paint(g, 0 , 0) ; // рисуем анимацию matros.Animation(); // двойная буферизация iluGhGraphics(); } } /* * файл Matros.Java класс Matros * / import- javax .rnicroedition. Icdui .* ; import javax.microedition.lcdui.game.*; public class Matros extends Sprite { // конструктор public Matros(Image image, int fw, int fh) { // обращаемся к конструктору суперкласса super(image, fw, fh) ; } // метод осуществляющий анимацию public void Animation!) { // вызываем следующий фрейм nextFrame(); } }
В листинге 8.3 нам интересно несколько моментов. В классе Matros, являющимся подклассом класса Sprite, создается метод Animation (), который выглядит следующим образом:
public void Animation() { nextFrame(); }
Метод Animation () осуществляет тот самый последовательный переход по имеющимся фреймам исходного изображения. В классе MyGameCanvas происходит создание объекта класса Matros:
private Matros matros;
Затем в конструкторе класса MyGameCanvas загружается изображение матроса и инициализируется объект matros.
Image im = Image.createlmage("/matros.png"); matros = new Matros(im, 94, 100);
Размер одного фрейма с матросом равен 94x100 пикселей, поэтому указывается размер именно одного фрейма. По умолчанию загружается самый первый фрейм изображения, но можно использовать метод setFrame () для установки необходимого фрейма из анимационной последовательности. В методе Graphics () класса MyGameCanvas происходит вызов метода Animation ():
matros.Animation();
Это в итоге приводит к цикличному перебору всех имеющихся фреймов. Откомпилируйте код из листинга 8.3 и посмотрите работу этого примера. На экране телефона матрос с помощью семафорной азбуки передает слово "анимация".
Класс GameCanvas
Абстрактный класс GameCanvas составляет основу интерфейса всей создаваемой игры. Этот класс отвечает за прорисовку экрана, улучшая механизм работы игрового цикла и не используя при этом входные системные потоки. Весь игровой процесс может быть сосредоточен в одном цикле метода run () интерфейса Runnable.
Игровой цикл, используемый классом GameCanvas, отличается от аналогичного цикла применяемого классом Canvas. Типичная проблема игрового цикла класса Canvas заключается в том, что он разбит на несколько потоков. Вывод графики происходит в одном методе, обработка событий с клавиш — в другом, а изменение состояния игрового процесса в третьем. Такая модель работы может давать сбои, поэтому в классе GameCanvas была придумана более изящная конструкция игрового цикла, располагающаяся в одном единственном цикле.
public void run() { Graphics g = getGraphics(); while(true) { // метод, обрабатывающий нажатия клавиш с телефона inputKey(); // метод, прорисовывающий графику GameGraphics(); // копирует графические элементы на экран из внеэкранного буфера flushGraphics(); }
Система прорисовки игровой графики построена на использовании двойной буферизации, без .которой невозможно создать ни одной хорошей компьютерной игры. Смысл механизма двойной буферизации заключается в использовании внеэкранного буфера. Вся игровая графика рисуется во вторичном или внеэкранном буфере и только после полного цикла отрисовки, копируется непосредственно на экран с помощью метода flushGraphics (). При этом улучшается качество самой графики и, что самое главное, до тех пор, пока игровой процесс не обновится, обработка событий с клавиш телефона является недоступной.
Сама же обработка событий с клавиш упрощена с помощью метода getKeyState (). Вы просто определяете нажатую клавишу пописываете соответствующие игровые действия для нее. Изменены некоторые названия констант для клавиш телефона. Обработка событий с клавиш телефона происходит с помощью следующих констант:
Использование констант значительно упрощает работу с объектом, а с помощью метода getKeyStates () класса GameCanvas, можно определить, какая именно клавиша нажата в данный момент. Проанализируем методы класса GameCanvas:
Класс GameCanvas создает основной цикл игрового процесса в одном потоке, наблюдает за событиями, получаемыми с клавиш телефона на основе которых производит постоянное обновление экрана.
Класс Layer
Абстрактный класс Layer задает основные свойства для всех созданных уровней игры.
Класс Layer имеет два подкласса TiledLayer и Sprite. При создании любых других подклассов класса Layer необходимо реализовать метод paint () в этих классах, чтобы иметь возможность рисовать созданные уровни на экране телефона, представляемом классом Graphics. С помощью методов класса Layer можно задавать размер и позицию уровня.
Класс LayerManager
Менеджер уровней представлен классом LayerManager. Это класс осуществляет представление любого количества уровней на игровом поле. Для создания объекта нужно воспользоваться конструктором класса LayerManager.
А чтобы добавить уровни в игру необходимо использовать следующие методы:
Предположим, у вас имеется четыре уровня: фон, игрок, препятствия и артефакты. Для того чтобы связать все четыре уровня воедино, создается объект класса LayerManager и вызывается метод append (). Например:
LayerManager im = new LayerManager(); im.append(fon); im.append(igrok); im.append(prep); . im. append (artf.) ;
И все! Четыре перечисленных уровня отражается на игровом поле.
Класс Sprite
Механизм работы с объектом класса Sprite идентичен модели работы с классом TiledLayer. Но если класс TiledLayer в основном отвечает за фоновое изображение, то с помощью класса Sprite рисуются на экране основные анимированные герои, космические корабли, машины, люди, звери, артефакты и так далее. Изображение, загружаемое в игру, может быть выполнено в виде анимационной последовательности. Количество рисунков в анимационной последовательности неограниченно, а отсчет происходит от нуля. Располагаться рисунки могут как в виде столбца, так и в виде колонки, в зависимости от ваших предпочтений. Каждый рисунок анимационной последовательности называется фреймом. Фрейм может быть любого размера по ширине и высоте, но все фреймы должны быть одинаковых размеров. Размер фрейма должен быть известен, потому что он используется при создании объекта класса Sprite. Есть три конструктора класса Sprite каждый из которых можно использовать при создании объекта класса Sprite.
Для перехода по фреймам исходного изображения, а также определения столкновения между объектами используются методы класса Sprite.
Метод defineReferencePixel () изменяет опорную позицию спрайта, но для чего это нужно? Опорная позиция для спрайта задается левым верхним углом, но не всегда это удобно, поэтому опорную позицию можно перенести, в центр спрайта. Например, если спрайт сделан в виде машины, то при вращении вокруг своей оси, если опорная позиция перенесена в центр, вращение будет правдоподобным. Но если не переопределить позицию, то вращение произойдет в точке левого верхнего угла спрайта и выглядеть это будет не вполне естественно, как будто у машины пробито одно из колес. Для этого вызывается метод def ineReferencePixel () с заданными координатами и переопределяет опорную позицию, например в центр спрайта:
defineReferencePixel(frameWidth / 2, frameHeight / 2);
Метод setTransform() производит трансформацию спрайта, вращая или зеркально отображая спрайт вокруг своей оси с помощью следующих констант:
Посмотрите на рис. 8.2, где очень привлекательно показаны константы для различных состояний спрайта.
Рассмотрев классы GameCanvas, Layer, Sprite, TiledLayer и LayerManager, перейдем к практическим занятиям этой главы.
Класс TiledLayer
С помощью класса TiledLayer создается фон игровой сцены. Фоновое изображение выполняется в виде одинаковых по размеру ячеек как показано на рис. 8.1.
Рис 8.1. Ячейки фонового изображения
Количество и расположение ячеек может варьироваться как угодно, но нумерация ячеек следует от единицы, слева направо и сверху вниз. Построение сцены происходит путем загрузки исходного изображения, разбитого на ячейки и указания индекса необходимой ячейки на игровом поле. Но прежде нужно создать объект класса TiledLayer с помощью конструктора, прототип которого выглядит следующим образом:
TiledLayer(int columns, int rows, Image image, int tileWidth, int tileHeight)
Размеры одной ячейки по ширине и высоте могут быть разными, но все ячейки исходного изображения должны быть одинаковыми по размеру. В качестве примера, возьмем за основу изображение на рис. 8.1 с шестью ячейками и предположим, что размер одной ячейки по ширине равен 10 пикселям, а по высоте 15 пикселям, тогда загрузка изображения и создание объекта TiledLayer может выглядеть следующим образом:
Image im = Image.createlmage("/fon.png"); TiledLayer tl =new TiledLayer(3, 2, im, 10, 15);
Загрузив изображение и создав объект класса TiledLayer, вы можете приступить к разметке фона па игровом ноле. Допустим, каждая из перечисленных по номеру ячеек обладает следующими характеристиками:
1) камни;
2) трава;
3) вода;
4) песок;
5) воздух;
6) заграждение.
А игровое поле разбито на пятнадцать столбцов и десять строк, тогда создав массив данных, очень легко выполнить разметку всего поля, например таким образом:
int[] pole = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 5, 5, 5, 1, 1, .5, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 1, 1, 1,1, 1, 1, 4, 4, 4, 4, 6, 6, 6, 6, 6, 4, 4, 4,4,4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3/3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3,,3, 3, 3, 3, 3, }
Затем весь имеющийся массив данных считывается с помощью цикла и рисуется методом paint () на экране телефона.
Познакомимся с методами класса TiledLayer:
Обработка событий с клавиш телефона
В профиле MIDP 2.0 предусмотрена улучшенная обработка событий получаемых с клавиш телефона. Используя метод getKeyState () можно определять состояние клавиш телефона и действовать адекватным образом. 'В демонстрационном примере к этому разделу мы выведем на экран мячик, созданный при помощи класса MySprite являющимся подклассом класса Sprite. В листинге 8.2 представлен код примера, в котором на экране рисуется синий мяч, а с помощью клавиш телефона Up, Down, Left и Right этот мяч можно передвигать по экрану. Листинг 8.2 состоит из трех классов: MainGame. MyGameCanvas и MySprite, расположенных в трех разных файлах MainGame.java, MyGameCanvas.java и MySprite.java.
/** Листинг 8.2 класс MainGame */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; public class MainGame extends MIDlet implements CommandListener { // команда выхода private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // объект класса MyGameCanvas private MyGameCanvas mr; public void startApp() { // обрабатываем исключительную ситуацию try { // инициализируем объект класса MyGameCanvas mr = new MyGameCanvas(); // запускаем поток mr.start(); // добавляем команду выхода mr.addCommand(exitMidlet); mr.setCommandLis'tener (this) ; // отражаем текущий дисплей Display.getDisplay(this).setCurrent(mr); } catch (Java.io.lOException zxz) {} ; } public void pauseApp() {} public void destroyApp(boolean unconditional) { // останавливаем поток if(mr != null) mr.stopt); } public void commandAction (Command c, Displayable d;) { if (с == exitMidlet) { destroyApp(false); notifyDestroyed(); } } } /** файл MyGameCanvas.Java класс MyGameCanvas */ import java.io.*; import javax.microedition.Icdui.*; import javax.microedition. Icdui .game .*; public class MyGameCanvas extends GameCanvas implements Runnable { // создаем объект класса MySprite private MySprite bol; // создаем объект класса Lay'erManager private LayerManager lm; // логическая переменная boolean z; public MyGameCanvas() throws IOException { // обращаемся к конструктору суперкласса Canvas super(true); // загружаем изображение Image im = Image.createlmage("/bol.png"); // инициализируем объект bol bol = new MySprite (itn, 23, 23); // выбираем позицию в центре экрана bol.setPosition(getWidth()/2, getHeight()/2); // инициализируем менеджер уровней 1m = new LayerManager(); // добавляем объект bol к уровню lm.append(bol); } public void start() { z = true; // создаем и запускаем поток Thread t = new Thread(this); t.start(); } // останавливаем поток public void stop() { z = false; } public void run() { // получаем графический контекст Graphic's g = getGraphics () ; while (z) { // обрабатываем события с клавиш телефона inputKey(); // рисуем графические элементы init(g); // останавливаем цикл на 20 миллисекунд try { Thread.sleep(20); } catch (Java.lang.InterruptedException zxz) {}; } } private void inputKey() { // определяем нажатую клавишу int keyStates = getKeyStates(); // код обработки для левой нажатой клавиши -if ((keyStates & LEFT_PRESSED) != 0) bol.moveLeft(); // код обработки для правой нажатой клавиши if ((keyStates & RIGHT_PRESSED) != 0) bol.moveRight(); // код обработки для клавиши вверх if ((keyStates & UP_PRESSED) != 0) bol.moveUp(); // код обработки для клавиши вниз if ((keyStates & DOWN_PRESSED) != 0) bol.moveDown(); } private void init(Graphics g) { // белый цвет фона g.setColor(0xffffff); // перерисовываем экран g.fillRect (0 , 0, getWi.dth () , getHeight()); // рисем уровень в точке 0,0 lm.paint(g, 0, 0) ; // двойная буферезация flushGraphics(); }; } /** файл MySprite.Java класс MySprite */ import javax.microedition.Icdui.*; import javax.microedition.Icdui.game.*; public class MySprite extends Sprite { // конструктор public MySprite(Image image, int fw, int fh) { // обращаемся к конструктору суперкласса super (image, fw, fh); } // метод для клавиши Left public void moveLeft() ; { // передвигаем спрайт move(-1,0); } // метод для клавиши Right public void moveRight() { / / передвигаем спрайт move(1,0); } // метод для клавиши Up public void moveUp() { // передвигаем спрайт move(0,-1); } // метод для клавиши Down public void moveDown() { // передвигаем спрайт move(0,1); '} }
В файле MySprite.java находится класс MySprite, с которого и начнем рассмотрение листинга. Конструктор класса MySprite обращается к конструктору своего суперкласса Sprite!
super(image, fw, fh);
Этот конструктор имеет три параметра - это исходное изображение спрайта, ширина и высота фрейма. Спрайт, как вы помните, может иметь анимационную последовательность, поэтому необходимо точно знать ширину и высоту одного фрейма, при обязательном условии, что все фреймы спрайта должны быть одного размера. В этом примере мы не используем анимационной последовательности, и можно было обойтись и более простым конструктором суперкласса Sprite.
Для передвижения спрайта по экрану телефона созданы методы moveLef t (), moveRight (), moveUp () и moveDowri (), в основу которых положены вызовы метода move (). Метод move () имеет два параметра - это координаты по осям X и Y. Задавая необходимое смещение на 1, 2, 3 и более пикселей по одной из осей, вы будете производить движение объекта по экрану.
Класс MyGameCanvas работает по схеме, использованной в разделе 8.6, с той лишь разницей, что вместо фонового изображения загружается спрайт в виде мячика. В конструкторе класса MyGameCanvas происходит загрузка исходного изображения bol.png, это и есть наш мячик или спрайт. Спрайт размером 23x23 пикселя. При создании объекта bol класса MySprite
bol = new MySprite(im, 23, 23)
используется изображение bol.png, затем, в конструкторе класса MyGameCanvas происходит выбор позиции для первоначальной отрисовки спрайта на экране с помощью метода setPosition (). Мячик рисуется в центре экрана и добавляется методом append () к уровню.
В методе run () в игровом цикле происходит вызов двух методов. Метод init () производит рисование всех графических элементов с помощью менеджера уровней, а метод input Key () осуществляет обработку нажатий клавиш телефона.
private void inputKey() { int keyStates = getKeyStates(); if ((keyStates & LEFT_PRESSED) != 0) bol.moveLeft(); if ((keyStates & RIGHT_PRESSED) !=0) bol.moveRight(); if ((keyStates & UP_PRESSED) != 0) bol.moveUp(); if ((keyStates & DOWN_PRESSED) != 0) bol.moveDown (); }
В методе inputKey () происходит определение нажатой клавиши посредством метода getKeyState (). Весь остальной код в методе inputKey () использует оператор if для обработки нажатых клавши, вызывая соответствующие методы moveLeftO, moveRight (), moveUp ()или moveDown () для перемещения объекта по экрану.
В классе MainGame из файла MainGame.java создается объект класса MyGameCanvas, запускается системный поток и отражается текущий экран.
В этом примере использовался спрайт файла ресурса bol.png состоящий из одного фрейма размером 23x23 пикселя. В следующем разделе мы рассмотрим технику анимации спрайтов в играх, и будем исполВзовать спрайт, состоящий уже из нескольких фреймов.
Создание фонового изображения
С помощью класса TiledLayer можно создавать любое количество уровней, накладывая их друг на друга, а с помощью менеджера уровней, представленного классом LayerManager, отслеживать все имеющиеся уровни. В качестве примера будет создан фон на основе элементов разметки игрового поля. Фоновое изображение загружается из файла fon.png. Само изображение выполнено в виде шести ячеек размером 15x15 пикселей.
В листинге 8.1 находится код примера создающего фоновое изображение. Ознакомьтесь с листингом, а потом мы перейдем к анализу этого примера.
Рис. 8.2. Константы трансформации
/ * * Листинг 8.1 класс MainGame */ import javax.microedition.lcdui.* ; import javax.microedition.midlet.*; public class MainGame extends MIDlet implements CommandListener { //команда выхода private Command exitMidlet = new Command!"Выход", Command.EXIT, 0) ; // объект класса MyGameCanvas private MyGameCanvas mr; public void startApp.{} { // обрабатываем исключительную ситуацию try{ // инициализируем объект класса MyGameCanvas; mr = new MyGameCanvas() ; // запускаем поток mr.start(); // добавляем команду выхода mr.addCommand(exitMidlet); mr.setCommandListener(this) ; // отражаем текущий дисплей Display .getDisplay (this) . setCurrent (mr-) ; } catch (Java . io. ID-Exception zxz) {} ; } public void pauseApp() {} public void destroyApp(boolean unconditional) { // останавливаем поток if(mr != null) mr.stop'O; } public void coramandAction(Command c, Displayable d) { if (c == exitMidlet) { destroyApp(false) ; notifyDestroyed() ; } } } / * * Файл MyGameCanvas.Java класс MyGameCanvas */ import Java.io.IOException; import javax.microedition.Icdui.*; import javax.microedition Nlcdui.game.* ; public class MyGameCanvas extends GameCanvas implements Runnable- { // создаем объект класса TiledLayer private TiledLayer fonPole; // создаем объект класса LayerManager private LayerManager im; // логическая переменная для выхода из цикла boolean z; public MyGameCanvas(), throws IOException { // обращаемся к конструктору суперклассаNCanvas super(true); // инициализируем fonPole fonPole = Fon () ; // создаем менеджер уровней 1m = new LayerManager(); // добавляем объект fonPole к уровню im.append (fonPole); } public void start() { z = true; // создаем и запускаем поток Thread t = new Thread(this); t.start(); } //* метод, создающий объект класса TiledLayer и загружающий фоновое изображение */ public TiledLayer Fon()throws IOException { // загрузка изображения из файла ресурса Image im = Image.createlmage("/fon.png"); // создаем объект класса TiledLayer fonPole = new TiledLayer(/*столбцы*/10,/*строки*/10, /*изображение*/lm,/*ширина*/15,/*высота*/15); // разметка игрового поля int[] pole = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 5, 5, 5, 1, 1, 5, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 2, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3 }; // цикл, считывающий разметку поля for(int i = 0; i < pole.length; i + + ) { /* присваиваем каждому элементу игрового поля определенную ячейку изображения im*/ fonPole.setCell(i % 10, i / 10, pole[i]); } return fonPole; } public void stop(){ z = false; } public void run() { // получаем графический контекст Graphics g = getGraphics(); while (z) { // рисуем графические элементы init(g) ; // останавливаем цикл на 20 миллисекунд try { Thread.sleep(20); } catch (Java.lang.InterruptedExceptlori zx.z) {}; } } private void init(Graphics g) { // белый цвет фона для перерисовки экрана g.setColor(0xffffff); // размер перерисовки экрана g.fillRect(0, 0, getWidth(), getHeight()); // рисуем уровень с левого верхнего угла дисплея 1m.paint(g, 0, 0) ; // двойная буферизация flushGraphics(); } }
Листинг 8.1 состоит из двух классов MainCanvas и MyGameCanvas, находящихся в файлах MainCanvas.java и MyGameCanvas.java. Анализ листинга начнем с класса MyGameCanvas. В первых строках кода этого класса объявляются два объекта классов TiledLayer и LayerManager, атак же логическая переменная z.
private TiledLayer fonPole; private LayerManager lm, boolean z;
Объект fonPole класса TiledLayer будет отвечать за фоновое изображение. Объект im класса LayerManager является менеджером уровней. Логическая переменная z необходима для прерывания цикла в методе run () и для окончания системного потока, в котором происходит работа всего игрового цикла.
В конструкторе MyGameCanvas происходит инициализация объекта fonPole класса TiledLayer и объект im класса LayerManager. Инициализированный объект fonPole добавляется менеджером уровней к текущему уровню для представления на экране телефона. Обратите внимание, объект fonPole инициализируется с помощью метода Fon ().
Image im = Image.createlmage("/fon.png"); fonPole= new TiledLayer(/*столб*/10,/*строки*/10,im, /*ширина*/15,/*высота*/15);
В этих двух строках происходит загрузка исходного изображения из файла ресурса и создание объекта fonPole с помощью конструктора класса TiledLayer.
Вся разметка игрового поля выполнена в виде десяти строк и десяти столбцов. Первые два параметра конструктора класса TiledLayer как раз и отвечают за количество столбцов и строк. Третий параметр конструктора - это исходное изображение, выполненное в виде шести ячеек, каждая размером 15x15 пикселей. Два последних параметра конструктора класса TiledLayer определяют ширину и высоту ячейки. При создании объекта класса TiledLayer необходимо быть внимательным и указывать реальные размеры одной ячейки. Если размер одной ячейки будет, предположим 20x20 пикселей, а вы обозначите как 15x15 пикселей, то в итоге ячейки изображения загружены не будут.
Дальше в методе Fon () происходит разметка игрового поля выполненного в виде десяти столбцов и десяти строк.
int[] pole = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 5, 5, 5, 1, 1, 5, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 2, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, };
Все строки и столбцы состоят из элементов. Отсчет ячеек происходит от единицы и выше. Присвоение номера ячейки исходного изображения одному из элементов и организует разметку игрового поля, которое в последствии будет рисоваться на экране. Единственное О5чем нельзя забывать - это о размере дисплеев реальных телефонов. Если вы имеете десять столбцов и размер каждой ячейки 15 пикселей по ширине, то в итоге ваше игровое поле в ширину будет 10x15 = - 150 пикселей. Не каждый телефон может похвастаться таким разрешением, поэтому при создании игрового поля нужно учитывать эти нюансы. Вслед за разметкой игрового поля в методе Fon () происходит считывание всех элементов с помощью цикла for.
forfint i = 0; i < pole.length; i++) { fonPole.setCell(i % 10, i / 10, pole[i]); }
Присвоение номера ячейки определенному элементу происходит при помощи метода setCell (). В этом методе первый параметр-номер столбца, второй - номер строки и последний - номер ячейки изображения. Здесь главное не запутаться, потому что номера столбцов и строк начинаются с нуля из-за того, что это обычный массив данных, а все массивы, как вы знаете, ведут свой отсчет с нуля, тогда как ячейка исходного изображения начинается с единицы. Сразу возникает вопрос, а почему не произвести отсчет тоже с нуля, чтобы не было путаницы? Дело в том, что отсчет и производится с нуля, но число ноль - это своего рода зарезервированное значение для ячеек изображения. Нулевое значение может использоваться, но оно не. загружает ничего, поэтому отсчет ячеек ведется с единицы. С методом Fon () мы разобрались, перейдем к методу init ().
g.setColor(0xffffff); g.fillRect(0, 0, getWidth0, getHeight());
В этих строках кода происходит постоянная перерисовка фона экрана. Эти действия вы производили в главе 7, когда разбирали механизм отсечения.
С помощью метода paint () рисуется уровень. Начало точки вывода уровня задано точкой 0,0, что соответствует началу, системы координат.
И последний метод flushGraphics () осуществляет двойную буферизацию, копируя графические элементы из внеэкранного буфера на экран.
В методе run () происходит остановка игрового цикла. Перед тем как цикл создается с помощью оператора while, методом getGraphics () происходит получение графического контекста, что и является одним из достоинств механизма игрового цикла в профиле MIDP 2.0.
В файле MainGame.java создается основной класс мидлета MainGame. В методе startApp() производится создание объекта рассмотренного класса MyGameCanvas, добавляется команда выхода, запускается системный поток и отражается текущий дисплей. В методе destroyApp () происходит остановка потока методом stop () класса MyGameCanvas.
Столкновение объектов
Практически во всех играх приходится обрабатывать события связанные со столкновением двух объектов или с препятствием. В профиле MIDP 2.0 существует три отличных метода, отслеживающих факт столкновения. Все три метода определены в классе Sprite.
Используя эти методы можно обрабатывать всевозможные ситуации, связанные со столкновением. Как правило, при столкновении должны произойти какие-то события, чаще всего связанные с изменением первоначального состояния объекта. Это может быть уничтожение объекта, его перемещение, уменьшение или увеличение. В основе изменения состояния объекта положен перебор имеющихся фреймов в анимационной последовательности или перерисовка изображения на новом месте. Для этих операций в классе Sprite имеется несколько методов. С одним из методов nextFrame (), вы уже познакомились в разделе 8.8, рассмотрим оставшиеся методы.
Набора этих методов вполне достаточно для обработки различных ситуаций возникающих в игровом процессе. Однако необходимо очень тщательно разобраться в действии всех вышеперечисленных методов. Для этого был написан исходный код примера, иллюстрирующего работу методов nextFrame (), prevFrame (), setFrame () и setFrameSequence (). В этой программе на экран выводятся четыре бомбы и синий шарик, перемещая который в разные стороны можно произвести столкновение с четырьмя бомбами. Все бомбы являются объектами класса MySprite, являющимся подклассом класса Sprite. Метод, обрабатывающий столкновение мяча и бомбы, использует один из четырех методов nextFrame (), prevFrame.(), setFrame () и setFrameSequence () для каждой из бомб, что красочно иллюстрирует работу каждого метода. Исходные, изображения бомбы и мяча выполнены в виде последовательности четырех фреймов размером 23x23 пикселя. Первый фрейм мяча и бомбы является исходным изображением, а три последующих фрейма реализованы в виде взрыва. Переход по этим фреймам создает иллюзию взрыва мячика или бомбы. Но оттого, что для каждой бомбы как мы договорились, используются различные методы, то результат может оказаться неожиданным. Поэтому внимательно посмотрите на код примера в листинге 8.4 и запустите программу с помощью любого эмулятора, поддерживающего профиль MIDP 2.0. Либо откомпилируйте исходный код из листинга 8.4 и внимательно ознакомьтесь с работой этой программы. Я уверен, что вы без труда разберетесь, что именно нужно сделать для логического завершения взрывов бомб и мяча. Алгоритм действий очень прост и может быть следующим после столкновения мяча с одной из мин. Необходимо произвести взрыв, последовательно переходя по всем фреймам, после чего, например, нарисовать бомбу и мячик заново. В листинг 8.4 предложен исходный код примера.
/ * * листинг 8.4 класс MainGame */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; public class MainGame extends MIDlet implements CommandListener { // команда выхода private Command exitMidlet = new Command("Выход",Command.EXIT, 0); // объект класса MyGameCanvas private MyGameCanvas mr; public void startApp() { // обрабатываем исключительную ситуацию. try{ // инициализируем'объект класса MyGameCanvas mr = new MyGameCanvas(); // запускаем поток mr.start{}; // добавляем команду выхода mr.addCommand(exitMidlet) ; mr.setCommandListener(this); // отражаем текущий дисплей Display.getDisplay(this).setCurrent(mr) ; } catch (Java . io. lOException zxz) {} ; } public void pauseApp() {} public void destroyApp(boolean unconditional) { // останавливаем поток if(mr != null) mr.stopf); } public void commandAction(Command c, Displayable d) { if (c = = exitMidlet) { destroyApp (false); notifyDestroyed(); } } } } /** файл MyGameCanvas.Java класс MyGameCanvas */ import java.io.*; import javax.microedition.Icdui.*; import javax.microedition.Icdui.game.*; public class MyGameCanvas extends GameCanvas implements Runnable { // создаем объект класса MySprite private MySprite bol; // создаем объект класса LayerManager private LayerManager lm; // создаем бомбы private MySprite bombal, bomba2, bombaB, bomba4; // логическая переменная boolean z; public MyGameCanvas() throws lOException { // обращаемся к конструктору суперкласса Canvas super(true); // загружаем изображение мяча linage bollmage = Image.createlmage ("/bol.png») // инйциалтзируем объект bol bol = new MySprite(bollmage, 23, 23); // выбираем позицию в центре экрана bol.setPosition(getWidth() /2, getHeight. () /2) ; // загрузка изображения бомбы Image bombalmage = Image.createlmage("/bomba.png"); // инициализируем первую бомбу bombal = new MySprite(bombalmage, 23, 23); // выбираем позицию для первой бомбы bombal.setPosition(10, 10); // инициализируем вторую бомбу bomba2 = new MySprite(bombalmage, 23, 23); // выбираем позицию для второй бомбы bomba2 . setPosition( getwidth()-30, 10); // инициализируем третью-бомбу bоmbа3 = new MySprite(bombalmage, 23, 23); // выбираем позицию для третьей бомбы bоmbа3.setPosition(10, getHeight()-40); // инициализируем четвертую бомбу bomba4 = new MySprite(bombalmage, 23, 23); // выбираем позицию для четвертой бомбы bomba4.setPosition(getWidth()-30, getHeight 0-40); // инициализируем менеджер уровней lm = new LayerManager(); // добавляем мяч к уровню lm.append(bol); // добавляем бомбы к уровню lm.append(bombal); lm.append(bomba2); lm.append(ЬотЬаЗ); lm.append(bomba4); } // обрабатываем столкновение public void stolknovenie() { // столкновение с первой бомбой if (bol. collidesWith (bombal, true)) { bol.nextFrame(); bombal.nextFrame(); } // столкновение со второй бомбой if(bol.collidesWith(bomba2, true)) { bol.prevFrame(); bomba2.prevFrame(); } // столкновение с третьей бомбой if (bol .collidesWith(bоmbа3 , true)) { bol.setFrame (2) ; vbomba3.setFrame(0); } // столкновение с четвертой бомбой if(bol.collidesWith(bomba4, true)) { int[] i = {2,3}; bol.setFrame(0); bomba4 . setFrameSequence (i) ; } } public void start() { z = true; // создаем и запускаем поток Thread t = new Thread(this); t.start(); } // останавливаем поток public void stop() { z = false; } public void run() { // получаем графический контекст Graphics g = getGraphics(); while (z) { // столкновение с препятствием stolknovenie (); // обрабатываем события с клавиш телефона inputKey(); // рисуем графические элементы init(g); // останавливаем цикл на 20 миллисекунд try { Thread.sleep(20); } catch (Java.lang.InterruptedException zxz) {}; } } private void inputKey() { //-определяем нажатую клавишу int keyStates = getKeyStates(); // код обработки для левой нажатой клавиши if ((keyStates & LEFT_PRESSED) != 0) bol.moveLeft(); // код обработки для правой нажатой клавиши if ((keyStates & RIGHT_PRESSED) != 0) bol.moveRight(); // код обработки для клавиши вверх if ((keyStates & UP_PRESSED) != 0) bol.moveUp(); // код обработки для клавиши вниз if ({keyStates & DOWN_PRESSED) !=-0) bol.moveDown(); } private void init(Graphics g) { // желтый цвет фона g.setColor(0xffff00); // перерисовываем экран g.fillRect(0, 0, getWidth(), getHeight()); // рисем уровень в точке 0,0 lm.paint(g, 0, 0); // двойная буферизация flushGraphics(); } } /** файл MySprite.Java класс MySprite */import javax.microedition.Icdui.*; import javax.microedition.Icdui.game.*; public class MySprite extends Sprite // констоуктор oublic MySprite(Image image, int fw, int fh) // обращаемся к конструктору суперкласса super( image , fw, fh); }//метод для левой нажатой клавиши public void moveLeft() //передвигаем спрайт move(-1,0); //метод для правой нажатой клавиши publiс void moveRight() //передвигаем спрайт move(1,0); } // метод для клавиши вверх public void rnoveUp () // передвигаем спрайт // метод для клавиши вниз public void moveDown() //передвигаем спрайт move(0,1); } }
В листинге 8-4 содержатся три класса MainGame, MyGameCanvas и My Sprite. Основной код обработки столкновений бомб и мяна находится в классе Мус игпйСа n vas - этому классу мы и уделим особое внимание при разборе - листинга.
В конструкторе класса MyGameCanvas происходит загрузка изображения мяча из файла ресурса bol.png, инициализация объекта bol, класса MySprite и устанавливается позиция прорисовки на экране объекта bol.
ImagebolImage = Image.createlmage("/bol.png") ; bol= new KySprioe(bollmage, 23, 23); bol.setPosition(getWidth()/2 ,getHeight()/2 ) ;
Заметьте, что позиция вывода мяча на экран установлена в центре экрана, но эта позиция определена для левой верхней точки мяча, поэтому именно левый верхний угол изображения спрайта мяча будет находиться в центре экрана. Для того чтобы нарисовать сам спрайт в центре экрана, нужно переопределить опорную позицию мяча с помощью метода def ineRef erencePixel ().
Затем в конструкторе класса MyGameCanvas загружается изображение бомбы.
Image bombalmage=Image.createlmage("/bomba.png");
После этого происходит инициализация четырех объектов bombal, bomba2, bomba3 и bomba4 класса MySprite и устанавливается позиция для вывода всех четырех бомб на экран телефона.
bombal = new MySprite(bombalmage, 23, 23); bombal.setPosition(10,10); bomba2 = new MySprite(bombalmage, 23, 23); bomba2.setPosition( getwidth()-30, 10); bomba3 = new MySprite(bombalmage, 23, 23); bonba3.setPosition(10, getHeight()-40); bomba4 = new MySprite(bombalmage, 23, 23);. bomba4.setPosition(getWidth()-30, getHeight()-40);
Все четыре бомбы рисуются в разных углах экрана слева направо и сверху вниз.
Произведя загрузку необходимых изображений и инициализируя все объекты класса MySprite, можно добавить их к уровню с помощью менеджера уровней.
lm.append(bol); lm.append(bombal); lm.append(bomba2); lm.append(bomba3); lm. append (bomba4);
Наша задача в этом примере - это определение столкновения бомб и мячика, для этого создан метод stolknovenie (), где при помощи конструкции if/ else происходит обработка столкновения объектов bol и bombalbomba4. Сейчас было бы очень хорошо, если бы вы могли запустить программу из листинга 8.4 и попробовали осуществить столкновение мяча с четырьмя бомбами. Как мы договорились, при столкновении будет обсуждаться работа четырех разных методов.
В столкновении с первой бомбой, находящейся в левом верхнем углу экрана, используется метод next Frame (). Если вы переместите мячик по экрану, то при наезде на первую бомбу произойдет взрыв бомбы и мяча. То есть начнется перебор всех имеющихся фреймов обоих объектов в цикличном порядке. Как только вы уберете мячик с бомбы, взрыв обоих объектов прекратится, потому что закончится перебор фреймов изображений. А состояние бомбы и мяча будет соответствовать одному из фреймов всей анимационной последовательности, при этом возможности повлиять на остановку- перехода по фреймам в методе nextFrame () нет.
Вторая бомба, находящаяся в правом верхнем углу экрана, при обработке столкновения использует практически идентичный предыдущему Метод prevFrame (), отличающийся лишь тем, что переход по всем существующим фреймам бомбы и мяча происходит в обратном порядке. Остановить работу метода на нужном фрейме также невозможно.
Третья бомба рисуется в нижнем углу экрана и для обработки столкновения мяча с бомбой используется метод setFrame (). Этот метод производит переход по заданным фреймам всей анимационной последовательности по номеру или индексу фрейма. В этом примере используется следующий код при столкновении мяча и третьей бомбы.
bol, setFrame (2); bomba3.setFrame(0);
Когда вы передвинете мячик на третью бомбу, то увидите, что изображение мячика изменится, и будет соответствовать третьему фрейму всей анимационной последовательности мячика. Состояние бомбы останется неизменным, потому что используется индекс 0, а это первый фрейм бомбы.
Четвертая бомба при столкновении задействует метод setFrameSequenсе (), благодаря которому можно использовать фреймовые последовательности в виде массива индексов.
Используя эти методы, я думаю, вы вполне сможете создать любую цепочку событий для перемещения, столкновения и других возможных действий объекта В следующей главе будет рассматриваться мультимедийная библиотека, необходимая для создания звукового сопровождения в играх.
Интерфейс Control
Интерфейс Control - это самый главный интерфейс, с его помощью осуществляется контроль над всеми имеющимися ресурсами, также от этого интерфейса наследуются еще два интерфейса ToneControl и VolumeControl.
Интерфейс Controllable
С помощью интерфейса Controllable можно получить управление над воспроизведением, посредством использования двух методов:
Интерфейс Player
Интерфейс Player наследуется от интерфейса Controllable и необходим для реализации процесса воспроизведения звуковых данных на основе формирования проигрывателей. Проигрыватели создаются методом createPlayer () класса Manager, например:
Player player1 = Manager.createPlayer();
После создания проигрывателя можно производить воспроизведения звука, для этого необходимо воспользоваться методами интерфейса Player.
Методы интерфейса Player
Большинство методов направленно на работу со звуковыми данными, позже в разделе 9.3 мы разберем подробнее работу с методами интерфейса Player.
Интерфейс PlayerListener
Интерфейс PlayerListener позволяет осуществлять обработку событий полученных от проигрывателя. Помните в главе 5 мы разбирали работу интерфейса CommandListener? Интерфейс PlayerListener функционирует почти по такой же схеме, но ориентирован на работу с проигрывателем. В составе интерфейса PlayerListener .имеется всего один метод:
C помощью констант интерфейса Player в методе playerUpdate (), нужно задавать тип необходимых событий в параметрах eventData и event:
Интерфейс ToneControl
С помощью интерфейса ToneControl происходит настройка и построение блока тональных звуков для воспроизведения. Это достигается путем использования метода void setSequence (byte [ ] sequence), который устанавливает тональные звуки для воспроизведения и набора следующих констант:
Интерфейс VolumeControl
Интерфейс VolumeControl имеет методы, на основе которых можно реализовать управление громкостью воспроизведения:
Сейчас мы вкратце рассмотрели имеющиеся интерфейсы, классы, методы и константы двух пакетов javax.microedition.media и javax.microedition.media.control. Теперь давайте подытожим все полученную информацию и рассмотрим примеры, иллюстрирующие работу со звуком в мобильных телефонах.
Класс Manager
Класс Manager создает проигрыватель для воспроизведения звуков, а также отслеживает доступные протоколы звуковых данных, с помощью нескольких методов.
Пакет javaxmicroeditionmedia
Пакет javax.microedition.media необходим для работы со звуком и содержит четыре основных интерфейса и один класс, на базе которых и происходит воспроизведение звуков в телефоне.
Пакет javaxmicroeditionmediacontrol
Пакет javox.microedition.media.control небольшой по своему составу и производит контроль над процессами, связанными с воспроизведением и регулировкой звука. В разделе 9.4 этой главы очень подробно рассматривается схема контроля.
Воспроизведение тональных звуков
При создании звукового сопровождения к играм и приложениям в основном используются так называемые тональные звуки, генерируемые телефоном. Мобильные телефоны ограничены в системных ресурсах, поэтому воспроизведение wav, mp3 файлов не всегда возможно.
Воспроизведение тональных звуков происходит примерно тем же способом, что и воспроизведение wav-файлов, рассмотренное в предыдущем разделе. Создание тональных звуков строится на основе секвенсора, используемого музыкантами. То есть, в вашем распоряжении имеются семь нот, которые могут быть сыграны в любой тональности. Указав определенную последовательность нот в заданном массиве данных, вы сможете их впоследствии последовательно воспроизвести. В принципе, аналогичные действия можно произвести в любом телефоне, где в музыкальном редакторе вы выстраиваете некую последовательность определенных Символов, обозначающих ноты. Указав нужную последовательность нот, вы получаете готовую мелодию, созданную при помощи тональных звуков.
Перейдем к практике. Первым делом необходимо создать те самые семь нот. В классе ToneControl пакета javax.microedition.media.control.*, доступна константа С4, которая по своему звучанию соответствует ноте "До". Для того чтобы создать, например ноту Ре, можно воспользоваться следующей конструкцией кода:
byte Re = (byte)(ToneControl.C4+1);
Для создания последующей ноты Ми нужно прибавить к ноте До (то есть С4), число два и так далее. Когда закончатся все семь нот, то вы переходите к следующей октаве, что и предопределяет разные тональности звукового сопровождения. Всего можно использовать значение от 0 до 127.
Затем создается массив данных, можно назвать его секвенсором, в котором указывается последовательность нот. Синтаксис, используемый в секвенсоре, строго определен, и его необходимо правильно использовать. Например, имеется следующий массив данных, характеризующийся как секвенсор:
byte[] Nota = {...};
В этом массиве данных первой строкой кода должно идти указание версии используемого атрибута.
ToneControl.VERSION,1,
Затем задается скорость воспроизведения с помощью целочисленного значения, которое может варьироваться от 5 до 127. Например:
ToneControl.TEMPO,30,
Далее необходимо дать команду, указывающую начало блока последовательности нот для воспроизведения, например:
ToneControl.BLOCK_START, 0,
И только после этого идет последовательность нот. Между нотами ставится обязательно длина ноты обычно заданная переменной, и ее диапазон может быть от 2 до 16. Например:
byte d = 4; Re,d,Mi,d,Re,d,
Между воспроизведением нот можно использовать паузы для создания выразительной мелодии. Пауза задается с помощью константы SELENCE, например:
byte stop = ToneControl.SELENCE; byte d = 4;
Тогда последовательность нот может быть следующей:
Re,d,stop,d,Mi,d,stop,d,stop,d,Re,d,
После того как вы задали всю последовательность нот, необходимо четко указать конец блока с помощью константы BLOCK_END следующим образом:
ToneControl.BLOCK_END, 0,
На каждую константу BLOCK_START, должна присутствовать константа BLOCK_END. Иначе возникнет ошибка при компиляции.
В конце нужно воспользоваться константой PLAY_BLOCK для воспроизведения блока последовательности нот. После этого созданный секвенсор можно использовать для воспроизведения проигрывателем тональных звуков. Посмотрите на листинг 9.2, где показана демонстрационная программа, воспроизводящая все семь нот одной октавы.
/ * * листинг 9.2 класс TonMIDlet воспроизводит тональные звуки */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; import javax.microedition.media.*; import javax.microedition.media.control.*; import java.io.*; public class TonMIDlet extends MIDlet implements CommandListener // команда выхода private Command exitMidlet = new Command("Выход",Command.EXIT, 0); // команда воспроизведения private Command pi = new Command("Играть", Command.OK, 1); // объект mydisplay представляет экран телефона private Display mydisplay; public TonMIDlet() { mydisplay = Display.getDisplay(this); } public void startApp() Form Is = new Form("Тональные звуки"); // добавляем команду выхода ls.addCommand(exitMidlet); // добавляем команду воспроизведения ls.addCoiranand(pl); ls.setCommandListener(this); // отражаем текущий дисплей my.display. setCurrent (Is) ; } private void TonPlay() { // нота До byte Do = ToneControl.C4;, // нота Ре byte Re = (byte)(ToneControl.C4 + 1); // нота Ми byte Mi = (byte)(ToneControl.C4 + 2) ; // нота Фа byte Fa = (byte)(ToneControl.C4 + 3); // нота Соль byte So = (byte)(ToneControl.C4 + 4); // нота Ля byte Lj = (byte)(ToneControl.C4 + 5); // нота Си byte Si = (byte)(ToneControl.C4 + 6); // пауза byte stop = ToneControl.SILENCE; // скорость воспроизведения тональных звуков byte speed = 30; // продолжительность воспроизведения ноты byte pr = 4; // секвенсор byte[] Nota = { // атрибут, задающий номер версии ToneControl.VERSION, 1, // скорость воспроизведения ToneControl.TEMPO, speed, // начало блока ToneControl.BLOCK_START, 0, // последовательность нот для воспроизведения Do,pr,stop,pr,Re,pr,stop,pr,Mi,pr,stop,pr, Fa,pr,stop,pr,So,pr,stop,pr,Lj,pr,stop,pr,Si,pr, // конец блока ToneControl.BLOCK_END, 0, // воспроизведение блока ToneControl.PLAY_BLOCK, 0, } ; // воспроизводим тональные звуки из секвенсора try{ Player player = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR); player.realize(); ToneControl toncontrl = (ToneControl)player.getControl("ToneControl"); toncontrl.setSequence(Nota); player.start(); } catch (IOException zxz){} catch (MediaException zmz){} } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { if (c = = exitMidlet) { destroyApp(false); notifyDestroyed(); } if (c == pi) { TonPlay(); } } }
В основе программы из листинга 9.2 лежит модель, используемая в предыдущем разделе при .воспроизведении wav-файла. В классе TonMIDlet создается пустая форма классом Form и назначаются две команды: выход из программы и воспроизведение тональных звуков. При нажатии на кнопку Играть, задействуется метод TonPlay (), где создаются ноты, секвенсор, после чего происходит воспроизведение последовательности нот.
Воспроизведение wav-файлов
Воспроизведение wav-фа.йлов в телефоне задача не сложная. Wav-файл должен быть размещен в каталоге создаваемого приложения. Если вы используете J2ME Wireless Toolkit 2.1, то расположите wav-файл в папке res. Впоследствии, после компиляции и установки программы, wav-файл будет находиться в JAR- архиве, и доступен для воспроизведения.
Для того чтобы воспроизвести необходимый wav-файл создается объект класса Inputstream для связывания потока данных с ресурсом, а именно wav-файлом,например:
Inputstream input = getClassf).getResourceAsStream(«файл.wav");
Затем создается проигрыватель:
Player player = Manager.createPlayer(input,"audio/X-wav");
Проигрыватель формируется с помощью метода createPlayer() класса Manager. Количество создаваемых проигрывателей регламентируется только системными ресурсами телефона. После чего используется метод start() для воспроизведения wav-файла.
В листинге 9.1 вы найдете пример исходного кода, в котором происходит загрузка и воспроизведение wav-файла из JAR-архива. В примере используется класс Form, с помощью которого создается пустой экран, и добавляются две команды: выход из приложения и воспроизведение wav-файла. Основные действия разворачиваются в методе WavPlay (), где создается проигрыватель и воспроизводится wav-файл. Обратите также внимание на подключаемые пакеты.
/** листинг 9.1. класс WavMIDlet воспроизводит wav-файл */ import javax.microedition.Icdui.*; import javax.microedition.midlet.*; import javax.microedition.media.*; import javax.microedition.media.control.*; import java.io.*; public class WavMIDlet extends MIDlet implements CommandListener { // команда выхода private Command exitMidlet = new Command("Выход", Command.EXIT, 0); // команда воспроизведения private Command pi = new Command("Играть", Command.OK, 1); // объект mydisplay представляет экран телефона private Display mydisplay; public WavMIDlet() { mydisplay = Display.getDisplay(this); } public void startApp() { Form Is = new Form("Воспроизведение wav"); // добавляем команду выхода ls.addCommand(exitMidlet); // добавляем команду воспроизведения ls.addCommand(pl); ls.setCommandListener(this); // отражаем текущий дисплей mydisplay.setCurrent(Is); } private void WawPlay() { try { // ищем ресурс с именем melod.wav InputStream input =getClass().getResourceAsStream("melod.wav"); // создаем проигрыватель Player player = Manager.createPlayer(input, "audio/X-wav"); // воспроизводим player.start(); } catch (lOException zxz) {} catch (MediaException zmz) {} } public void pauseApp() {} public void destroyApp(boolean unconditional){} public void commandAction(Command c, Displayable d) { if (c == exitMidlet) { destroyApp(false); notifyDestroyed() ; } if (c = = pi) { WawPlay(); } } }
Архитектура телефонов
Не думаю, что стоит здесь приводить схемы печатных плат телефонов и разбирать тип установленных микросхем, все это больше подходит сериям книг "Радиолюбитель", но несколько слов об аппаратной части сказать все же необходимо.
Телефон имеет процессор, память, приемо-передатчик, систему контроллеров для дисплея, клавиатуры, аккумулятора и карту SIM (Subscriber identification module - идентификационный модуль абонента). Процессор вкупе с памятью является сердцем телефона. Он имеет более скромные характеристики, чем процессор компьютера. Приемо-передатчик служит для приема и передачи сигнала и включает в себя различные фильтры, кодеры, декодеры речи и сигналов. Система контроллеров для клавиатуры (клавиш телефона) и дисплея позволяет вводить информацию в телефон посредством клавиш и выводить ее на дисплей. Контроллер аккумулятора производит управление процессом зарядки аккумуляторных батарей телефона.
Все аппаратное обеспечение телефона (железо) безусловно, само по себе функционировать не может, и работа осуществляется на основе прошивки или операционной системы.
Устройство мобильных телефонов
Инфракрасный порт
Инфракрасный порт имеют не все телефоны. В основном это модели, относящиеся ко второй и третьей условной ценовой категории, о которых мы говорили в начале этой главы. С помощью инфракрасного порта можно произвести соединение с компьютером, другим телефоном или любым иным устройством имеющим инфракрасный порт. Принцип работы инфракрасного порта очень прост: имеются светодиод и фотодиод, соответственно для передачи и приема сигнала. Поместив два устройства на расстоянии не более полутора метров в зоне прямой видимости можно осуществить связь между этими устройствами. Что касается связи телефона с компьютером посредством инфракрасного порта, то это происходит при помощи программного обеспечения поставляемого производителями телефонов. В частности на компакт диске можно найти программы для телефонов Sony Ericsson, Nokia и Siemens, подробный анализ этих программ вы найдете в главе 3.
Карта SIM
После приобретения телефона необходимо позаботиться о покупке SIM-карты одного из операторов мобильной связи. Купив SIM-карту, вы становитесь полноценным абонентом выбранного вами оператора связи.
Сама SIM-карта выполнена в виде небольшого по размерам пластмассового прямоугольника, с контактной полосой на поверхности для стыковки с идентичным разъемом на телефоне. Каждая SIM-карта, содержит свой уникальный идентификационный номер, что в конечном итоге решает проблему одинаковых номеров. В SIM-карте также находится простейший процессор, и вы можете сохранять на SIM-карте записи, как правило, это обычная телефонная книга, примерно на 200-300 записей. Более подробно об установке SIM-карты в телефон и другой информации можно узнать из инструкции к вашему телефону.
Таким образом, устройство мобильного телефона отдаленно напоминает устройство компьютерных систем. Поэтому адаптация платформы Java 2 ME, для телефонов, произошла абсолютно безболезненно, переведя виток развития мобильной индустрии на новый, до настоящего времени не ведомый уровень. Следующая глава раскрывает теорию строения платформы Java 2 Micro Edition.
Прошивка и операционная система
Все имеющиеся мобильные телефоны можно разделить еще на два типа - это телефоны, работающие под управлением прошивки и телефоны, использующие операционную систему. Телефоны с операционной системой также носят название смартфоны. На рынке сейчас имеются две операционные системы, адаптированные под нужды телефонов, это Windows Mobile и Symbian.
Операционная система Windows Mobile, за которой стоит, как не трудно догадаться, софтверный гигант Microsoft предъявляет достаточно высокие требования к аппаратной части телефона. Соответственно, высокая цена на такие устройства никак не способствует популяризации этой операционной системы. Но стоит признать тот факт, что операционная система Windows Mobile- очень мощная и хорошо продуманная система, которая в будущем возможно сможет занять одно из ведущих мест в этом сегменте рынка.
Операционная система Symbian является открытой системой и предъявляет значительно меньше требований к аппаратному устройству телефона. В акционерное общество Symbian Ltd. (разработчик операционной системы Symbian) входят все мировые лидеры производителей телефонов. Эта операционная система на данный момент занимает доминирующее положение в мобильной промышленности.
Обе операционные системы имеют различные наборы функциональных возможностей, но работа обеих похожа на работу компьютерных систем, конечно с учетом характеристик телефона, а это процессор, память, клавиатура, дисплей и так далее. Все эти факторы значительно уменьшают функциональность телефона, но прогресс не стоит на месте: в 1999 году процессор с частотой в 200 ГГц казался вершиной компьютерной техники, а сейчас об этом смешно вспомнить.
Прошивка телефона — это программа, управляющая работой телефона, но вшитая в сам телефон. Каждый из производителей создает свои прошивки для конкретных моделей, предопределяя тем самым функциональность телефона. Операционная система разрешает осуществлять загрузку созданных программ . в телефон, а в прошивке такая возможность не предусмотрена. Точнее сказать, не была предусмотрена до появления платформы Java 2 ME. Для работы приложений написанных на Java, необходима виртуальная Java машина иди среда исполнения приложений. Виртуальная Java машина, адаптированная специально для телефонов, настолько компактна по размеру, и, что самое главное, безопасна, что практически все производители телефонов стараются создать поддержку Java программ, то есть встроить среду исполнения Java программ в телефон. Загрузка сторонних приложений дала очень мощный импульс мобильной игровой индустрии, что, как мне кажется, вывело телефон на новый более качественный уровень. Единственное что необходимо понимать в этом аспекте, это то, что среда исполнения Java-приложений в телефоне реализована таким образом, что не позволяет написать "вредные" программы портящие аппаратную часть телефона. Модель работы Java-программ реализована как бы в виде закупоренной бочки, в которой и происходит работа всех Java приложений. Из этой бочки программы выбраться не могут, а соответственно не могут и нанести ущерб телефону.
Загрузка Java программ в телефон происходит при помощи программного обеспечения и кабеля, соединяющего телефон с компьютером. Также можно загрузить в телефон программы при помощи инфракрасного порта, технологии Bluetooth, либо непосредственно из Интернета с помощью протоколов WAP и GPRS. Все программы, загружаемые в телефон, распространяются в виде двух файлов, JAD - это дескриптор приложения и JAR - архив программы. Более подробно процесс загрузки программ рассматривается в главе 3.
Протокол GPRS
Связь телефона по протоколу GPRS (General Packet Radio Service - радио сервис пакетной передачи данных) осуществляется в куда более щадящем режиме. Используя соединение WAP, вы фактически звоните по другому номеру, занимая тем самым один из многочисленных каналов связи, поэтому и оплата взимается поминутно. С использованием GPRS оплата происходит только за количество скачанных данных, измеряемое в байтах, килобайтах или мегабайтах. Например, оператор мобильной связи Би Лайн за один мегабайт изымает 6 рублей 60 копеек с вашего счета (по состоянию на 2004 год). Лучше использовать WAP соединение, то есть просматривать WAP-сайты, через протокол GPRS, значительно экономя средства. Все это происходит благодаря тому, что GPRS использует пакетную передачу данных и не задействует какой-то конкретный канал связи, он вклинивается в свободные зоны различных каналов, передавая информацию в виде небольших пакетов. Скорость связи может доходить до 115 кбит/с, но полагаю, что таких показателей никто не видел, а вот цифра в 30-40 кбит/с вполне реальна. Связь через GPRS можно использовать и на компьютере, для выхода в Интернет через мобильный телефон. Такая услуга связи носит название мобильный: Интернет.
Протокол WAP
Протокол WAP (Wireless Application Protocol) - это протокол беспроводного соединения с сетью Интернет. Имея поддержку WAP в мобильном телефоне, появляется возможность выхода в Интернет для просмотра специально адаптированных web-страниц на телефоне. Также с помощью WAP можно скачать или купить игру или приложение, написанное на языке Java. Стоимость таких программ обычно не превышает 1-2 доллара. Однако пользоваться WAP можно только в том случае, если ваш оператор сотовой связи предоставляет WAP услуги. Телефон, имеющий поддержку WAP, снабжен и WAP-браузером, что и делает возможным просмотр WAP страниц в Интернете.
Если обобщить все выше сказанное, то работу телефона с протоколом WAP, можно сравнить с обыкновенным компьютером, связывающимся с сетью Интернет. Все Интернет-страницы, используемые компьютерными системами написаны на языке HTML или XML, а страницы для WAP-соединения созданы с помощью своего языка WML (Wireless Markup Language - беспроводной язык разметки). Для того чтобы через WAP выйти в Интернет с мобильного телефона, необходимо обязательно произвести соответствующие настройки в телефоне. Сделать это можно вручную, а можно воспользоваться услугами своего оператора, предоставляющего мобильную связь. Для этого необходимо позвонить по соответствующему номеру или отправить SMS, в зависимости от оператора связи указанного в инструкции, прилагающейся к SIM-карте. Если есть желание настроить WAP самостоятельно, то можно воспользоваться значениями, приведенными в таблице 1.1.
Таблица 1.1.
| Операторы |
БиЛайн |
Мегафон |
МТС |
| URL |
"http://wap.beeline.ru" |
http://wap.megawap.ru |
http://wap.mts.ru |
| Защита связи |
отключить |
отключить |
отключить |
| Канал |
GPRS |
GPRS |
GPRS |
| Входная точка |
http://wap.beeline.ru |
http://wap.megawap.ru |
http://wap.mts.ru |
| Адрес IP |
192.168.017.001 |
010.010.001.002 |
212.44.140.13 |
| Логин |
beeline |
wap |
mts |
| Пароль |
beeline |
wap |
mts |
Если вы покупаете игру с одного из коммерческих сайтов, то отсылаете по указанному на сайте номеру SMS, в котором сообщаете код программы, указанный на сайте. После этого вам на телефон придет ссылка, по которой можно скачать купленную вами программу.
Единственная проблема WAP-сервиса - это высокая цена соединения, поскольку оплата происходит поминутно, а платите вы практически как за минуту разговора по телефону. Это получается весьма дорогое удовольствие. Отчасти эту проблему решает протокол GPRS.
Стандарт GSM
Цифровой стандарт GSM (Global System Mobile Communication - система мобильной глобальной связи), на основе которого происходит связь между телефонами, - самый распространенный стандарт во всем мире, обеспечивающий диапазон работы мобильных телефонов на частотах 900/1800/1900 МГц. Стандарт GSM обладает качественными и безопасными характеристиками связи, что и повлияло на его популярность во всем мире. В нашей стране это основной стандарт, использующийся всеми крупными операторами связи.
Технология Bluetooth
Название этой сравнительно новой технологии (Bluetooth - голубой зуб) позаимствовано из истории - так некогда звали датского короля Гарольда второго, стремящегося объединить все датские земли в одно королевство Дания.
С помощью технологии Bluetooth можно осуществлять соединение сразу с множеством устройств и организовывать небольшие локальные сети. Связь с использованием Bluetooth происходит на частоте 2,4 ГГц с расстояния порядка 10 метров и что самое главное, не требует прямого соединения, то есть устройства могут находиться вне зоны видимости друг друга. Приемопередатчик сигнала выполняется в виде микросхемы и может связать в сеть около десятка разнообразных устройств.
Сейчас технология Bluetooth очень активно используется производителями мобильных телефонов для создания беспроводных гарнитур, например наушника и микрофона.
Цикл do/while
Только что рассмотренный нами цикл while при определенных условиях может и не заработать. Например, если условие будет изначально ложно, то цикл не выполнится ни разу. Программа, дойдя до строки кода с оператором while, проверит условие и если оно будет равно false, проигнорирует весь цикл и перейдет к коду, следующему сразу за циклом while. Но иногда возникает необходимость в выполнении цикла по крайней мере один раз. Для этих целей в Java существует цикл do/while. Запись и создания цикла do/while осуществляется следующим образом:
do { // действия }while (услрвие)
Между операторами do и while существует тело цикла, которое будет выполняться до тех пор, пока постусловие, следующее за оператором whilе, не будет ложно. Тело цикла выполнится) по меньшей мере, один раз, после чего будет произведена проверка условия. Цикл do/while используется не часто, но порой оказывается незаменим.
Цикл for
Это самый распространенный цикл, используемый в программировании, основанный на управлении счетчиком. Смысл работы цикла for схож с рассмотренными выше циклами while и do/while. Посмотрите, как выглядит цикл for:
for (int i = 0; i < 10; i++) { // действие }
После ключевого слова for, следует условие выполнения цикла. Само же условие объединяет в себе три этапа по инициализации счетчика: i = 0 проверка условия i < 10 и увеличение переменной i на единицу. Когда программа доходит до цикла for, то происходит инициализация счетчика i = 0 и проверяется условие i < 10. Далее программа переходит в тело цикла. По окончанию всех действий в цикле for, происходит обращение к третьему этапу цикла: i++, увеличивая счетчик на единицу. После чего сразу же происходит переход ко второму этапу - проверке переменной i < 10 и повторный выход в тело цикла. Весь цикл продолжается до тех пор, пока условие i < 10 не станет ложным. Цикл for используется постоянно при инициализации массива данных, где без него очень сложно, а порой и не возможно обойтись.
Так же как и в цикле whilе возможно использование оператора декремента, например:
for (int i = 10; i > 0; i-) { //действие }
Используя любую выбранную конструкцию цикла, вы получаете очень мощный инструмент программирования, избавляющий вас от написания большого количества строк кода.
Циклы
Вы задумывались когда-нибудь над тем, зачем вообще существуют программы? Если упростить и обобщить ответ на этот вопрос, то выяснится, что программы необходимы для автоматизации рабочего процесса, увеличения скорости выполняемой работы, избавления человека от тысяч монотонных действий и так далее. Сейчас, мы как раз и остановимся на повторяющихся друг за другом действиях.
Цикл - это последовательное выполнение повторяющихся действий на основе заданного предусловия. Например, нужно переставить сто ящиков из одного угла в другой. Если это каким-то образом записать на языке Java (к сожалению, переставить за вас ящики Java не сможет), то получится запись в сто строк наподобие этой:
1) взять ящик №1 и поставить другой угол; 2) взять ящик №2 и поставить другой угол; 3) взять ящик №3 и поставить другой угол; ... 100) взять ящик №100 и поставить другой угол;
Сто строк кода - это уже много, но бывает и тысяча. Для этих целей, а именно - упрощения записи повторяющихся действий и служат циклы.
Существует три оператора представляющих циклы в языке Java- это while, do/white и for. Каждый из операторов необходим в своей ситуации, но все же чаще всего используется оператор for. Рассмотрим по порядку каждый из операторов.
Интерфейсы
В программировании мобильных телефонов на Java 2 ME очень часто используются интерфейсы. Интерфейс задает классу, что именно должен делать этот класс, но, не говоря каким образом должны быть реализованы Эти действия, то есть, это некая спецификация, в рамках которой происходит реализация необходимых действий. Создание интерфейса совершается при помощи ключевого слова interface, а для реализации каким-либо классом возможностей интерфейса используется ключевое слово implements. Чтобы более четко разобраться в работе с интерфейсами рассмотрим небольшой пример:
public interface Mylnterface { int Inkriment(); } class MyOne implements Mylnterface { int a; // реализация метода Inkriment() для класса MyOne public int Inkriment() { a = 9++; return a; } } class MyTwo implements Mylnterface { int a; // реализация метода Inkriment() для класса MyTwo public int Inkriment() { а = 2++; return a; } }
Созданный интерфейс Mylnterfасе имеет один пустой метод Incriment (). Тело метода отсутствует, есть только его декларация, а класс МуОnе реализует данный интерфейс для своих нужд. В свою очередь класс MyTwo тоже реализует метод Incriment () в необходимой ему форме. Интерфейс задает, что именно надо сделать, а класс, реализующий данный интерфейс, решает, как ему это сделать. Все методы, заключенные в интерфейсе, обязательно должны быть созданы в классе, реализующим этот интерфейс. Интерфейсы не являются классами, поэтому создать интерфейс при помощи ключевого слова new невозможно, но создавать переменные интерфейса можно, в случае если они сохраняются на объекты класса. Любой интерфейс может наследовать другой интерфейс при помощи ключевого слова extends. Интерфейсы очень ярко отражает полифонизм языка Java.
Классы
Стержнем всех программ Java являются классы, на которых основывается объектно-ориентированное программирование. Вы по сути уже знаете, что такое классы, но пока об этом не догадываетесь. В предыдущем разделе мы говорили об объектах, ставя в пример устройство всего компьютера. Каждый объектов, из которых собран компьютер, является представителем своего класса. Например, класс Мониторов объединяет все мониторы вне зависимости от их типов, размеров и возможностей, а один какой-то конкретный монитор, стоящий на вашем столе и есть объект класса мониторов. Такой подход позволяет очень легко моделировать всевозможные процессы в программировании, облегчая решение поставленных задач. Например, имеется четыре объекта четырех разных классов: монитор, системный блок, клавиатура и колонки. Чтобы воспроизвести звуковой файл необходимо при помощи клавиатуры дать команду системному блоку, само же действие по даче команды вы будете наблюдать визуально на мониторе и, в итоге, колонки воспроизведут звуковой файл. То есть любой объект является частью определенного класса и содержит в себе все имеющиеся у этого класса средства и возможности. Объектов одного класса может быть столько, сколько это необходимо для решения поставленной задачи.
в телах обоих методов имеется
В классе Telefon в телах обоих методов имеется запись после двух слешей: //. Такая запись обозначает комментарии, которые будут игнорироваться компилятором, но нужны для читабельности кода. Чем больше информации вы закомментируете по ходу написания программы, тем больше у вас будет шансов вспомнить через год, что вы хотели сделать.
Комментарии в Java могут быть трех видов, это: //, /*...*/ и /**...*/. Комментарии, записанные с помощь оператора // должны располагаться в одной строке:
// Одна строка !!! Ошибка! На вторую строку переносить нельзя! // Первая строка // Вторая строка // ... // Последняя строка
Комментарии, использующие оператор /*...*/ могут находится на нескольких строках. В начале вашего комментария поставьте /*, а в конце, когда закончите комментировать код, поставьте оператор * /.
Последний вид комментария /**...*/ используется при документировании кода и также может располагаться на любом количестве строк.
Конструктор суперкласса
В рассмотренном примере по созданию суперкласса и подкласса Nokia, умышленно использовался конструктор по умолчанию. Ситуация с конструкторами суперклассов требует отдельного внимания.
Когда в программе происходит вызов конструктора, то вызов осуществляется согласно всей иерархии наследования. Первым вызывается конструктор самого первого суперкласса и опускается ниже по все иерархии наследования. Но иногда необходимо обратиться к ближайшему конструктору суперкласса и тогда используется ключевое слово super. Рассмотрим небольшой пример.
// суперкласс Nokia class Nokia { // конструктор суперкласса Nokia // тело класса Nokia } // подкласс NokiaSeries60 class NokiaSeries60 extends Nokia { // конструктор подкласса NokiaSeries60 NokiaSeriesGO(int a, int b) ; // тело подкласса NokiaSeries60 } // подкласс Nokia6600 для суперкласса NokiaeSeries60 class Nokia6600 extends NokiaSeries60 { // конструктор подкласса Nokia6600 Nokia6600 (short f, short b, short c) { super (a, b) // тело конструктора } } // подкласс Nokia6100 для суперкласса NokiaeSeries60 class Nokia6100 extends NokiaeSeries60 { //конструктор подкласса Nokia6100 Nokia6100 (char a, char b) { super (a, b) // тело конструктора } // тело подкласса Nokia6100 }
Если вы желаете воспользоваться конструктором ближайшего суперкласса, в конструкторе подкласса первым должно идти ключевое слово super с параметрами для необходимого конструктора суперкласса. Ключевое слово super имеет двойную смысловую нагрузку и может использоваться не только для вызова конструктора суперкласса. Второй вариант использования ключевого слова super, заключается в доступе к невидимому члену суперкласса. Сейчас мы коснулись так называемого вопроса видимости. Вы не задумывались над тем, что будет, если методы или переменные в суперклассе и подклассе будут совпадать по именам? Дело в том, что если подкласс будет иметь одинаковые названия любых членов класса, то он будет использовать только свои члены класса. Все данные суперкласса окажутся недоступными или невидимыми в силу совпадения названий. Для этих целей может быть использовано слoво super. Посмотрите на пример иллюстрирующий способ его использования:
// суперкласс Siemens class Siemens { int a, b; } // подкласс SiemensMC62 class SiemensMC62 extends Siemens { int a, b; // конструктор подкласса SiemensMC62 SiemensMC62 (int c, int d) { super.a = с; // для а в суперклассе super.b = d; // для b в суперклассе a = с; // для а подкласса b = d; // для b подкласса } }
Использование ключевого слова super очень похоже на обращение объекта класса к методам и переменным. Когда необходимо получить доступ к членам суперкласса, имеющим одинаковые названия, воспользуйтесь ключевым словом super или поступайте проще - давайте различные имена для членов суперкласса и подкласса.
В языке Java существует еще одно ключевое слово this, выполняющее похожие действия. При помощи этого ключевого слова можно произвести вызов любого другого конструктора того же класса либо использовать для указания ссылки на параметр, отсутствующий в конструкторе класса.
Подводя итог темы наследования необходимо упомянуть о классе Object. В языке Java все классы наследуются от большого суперкласса Objec. Это происходит автоматически и беспокоится о явном наследовании при помощи ключевого слова extends не нужно.
Конструктор
Каждый класс обязан содержать конструктор. Конструктор - это тот же самый метод, но имеющий название класса, например:
class Telefon { Telefon(); // конструктор int w, h, s; // переменные void Area(); // метод }
Конструктор позволяет инициализировать создаваемые объекты данного класса с заданными значениями. Каждый класс имеет конструктор, и если вы явно не записали строку кода (как в нашем случае Telefon () , Java автоматически создаст его за вас, такой конструктор носит название конструктора по умолчанию.
Конструкторы в программировании очень полезны и ни одна профессиональная программа не обходится без конструкторов. Чтобы действительно ощутить мощь конструктора, надо создать конструктор с аргументами, благодаря которым можно инициализировать данные класса.
class Telefon { int w, h, s; Telefon (int a, int b) // конструктор { w = a; h = b; } void Area() // площадь телефона { S = W*h; } }
При создании объекта (об этом чуть позже), вы можете указать необходимые значения для параметров а и b, например: а = 70, b = 100. Эти заданные числа автоматически присвоятся переменным w и h при создании объекта класса Telefon. Тем самым произойдет инициализация объекта с необходимыми значениями.
Количество конструкторов в классе ограничивается только вашей фантазией и здравым смыслом. Например, можно создать два конструктора классу Telefon:
Telefon (int a, intb); Telefon (char a, char b);
В этом случае при создании объекта по переданным параметрам конструктору класса, компилятор выберет сам необходимый конструктор и создаст заданный объект.
Массивы
Очень часто в программировании встречается большое количество однотипных данных. Для того чтобы не объявлять, скажем, сто переменных, существуют массивы данных. Массив - это набор однотипных значений. В языке Java для создания массивов предусмотрена специальная запись:
int[]M;
С помощью такой записи создается пустая переменная, содержащая определенный массив данных. Объявление массива происходит так же как и объявление объекта класса. Необходимо воспользоваться ключевым словом new чтобы выделить память массиву и явно инициализировать его с количеством элементов. Например:
int[]M = new int[20];
В этой строке кода был создан целочисленный массив из двадцати элементов. К каждому из элементов массива можно обратиться при помощи индекса М [n], для сохранения либо изъятия значения заданного элемента.
М[0] = 3; М[1] = 5; М[2] = 20;
Индекс любого созданного массива всегда начинается с 0, об этом нужно помнить. Чтобы инициализировать массив данных, например из пятидесяти элементов, должно потребоваться пятьдесят строк кода, но в нашем распоряжении имеется цикл for, прекрасно справляющийся с этой задачей.
int[]М = new int[50]; for .(int i = 0; i<50; i++) { M[i]. = i; }
В этом примере происходит инициализация каждого элемента массива от 0 до 49, соответственно, такими же значениями. Можно инициализировать массив другим способом, без ключевого слова new.
int[]M = (0, 1, 2, 3, 4}
В этом случае каждый элемент массива инициализируется пятью числами от 0 до 4. Все вышеперечисленные примеры создавали простой одномерный массив данных, но иногда приходится представлять данные в виде парных значений. Например, координаты по X и по Y в системе координат. Для этого в Java существуют многомерные массивы данных.
int stroka = 10; int stolbec =10; int[][]M = new[stroka][stolbec];
Многомерные массивы представлены в виде таблицы. Чтобы получить доступ к заданному элементу массива, нужно указать в какой строке и в каком столбце находится элемент массива. Точно так же в высшей математике происходит работа с матрицами. Многомерный массив данных можно инициализировать с помощью фигурных скобок:
intn []M = { (5, 3, 8}, {7, 12, 16} , 49, 12, 14} }
Инициализация массива данных при помощи цикла for немного сложнее, но очень эффективная и используется постоянно. Например, у вас есть большой массив данных, который требуется обнулить. Вот как будет выглядеть запись для этого массива данных:
int[][]M = new int[100][50]; for1(int i = 0; i < 100; i++) for (int a = 0; a < 50; a++) M[i][a] =0;
Многомерные массивы позволяют хранить большое количество данных при минимуме записанного кода, сохраняя при этом его понятность и читабельность.
Метод main
Класс Telefon, который мы описывали в предыдущем разделе, имел один метод, с помощью которого вычислялась площадь дисплея. Созданная спецификация класса Telefon может быть описана как угодно. Можно добавить реагирующие на обработку событий с клавиатуры телефона и любые другие методы, которые вы сочтете нужными для описания класса Telefon. Таких, и подобных классов может быть любое количество. Каждый из классов принято хранить в своем отдельном файле с расширением *.java. Например, Telefon.java. Все методы находящиеся в классе Telefon, которые вы опишете для данного класса, обязаны производить определенные действия с объектом этого класса, иначе, зачем нужны эти методы. Реализация методов как уже говорилось, происходит непосредственно в создаваемом классе. Но возникает вопрос, где и как, происходит вызов необходимых по ситуации методов или создание объектов используемого класса. В языке Java для этих целей существует Memodmain (), который подобно строительной площадке собирает на своей платформе по частям объекты, методы, строя при этом функциональность всей программы.
public class RunTelefon { public static void main( String[] args) { // Работа программы } }
Пока не обращайте внимания на ключевые слова public и static - о них чуть позже. Создав класс RunTelefon и определив в его теле метод main () мы теперь имеем возможность пользоваться классом Telefon и его не особо богатой функциональностью. Объединив эти два класса в один файл, либо записав каждый по отдельности, вы получите работоспособную программу. Класс Telefon содержит основные данные и методы, а класс RunTelefon берет на себя роль мотора. Внутри класса RunTelefon происходит создание объектов класса, в данном случае класса Telefon и вызовы соответствующих методов этого класса. Например:
class Telefon { //переменные int w, h, s; // метод void Area() { S = w*h; } } class RunTelefon { public static void main (String args[]) { /* создание объектов и вызовы метода Area() */ } }
Поскольку вы пока не умеете создавать объекты классов и вызывать методы, тело класса RunTelefon пустое. Прежде чем идти дальше, необходимо познакомиться с ключевыми словами public, private и protected, а так же научиться создавать конструкторы классов.
Методы
Когда приводился пример воспроизведения звукового файла, то было упомянуто о даче команды или сообщения, на основе которого и выполнялись определенные действия. Задача по выполнению действий решается с помощью методов, которые имеет каждый объект. Методы — это набор команд, с помощью которых можно производить те или иные действия с объектом.
Каждый объект имеет свое назначение и призван решать определенный круг задач с помощью методов. Какой толк был бы, например, в объекте Клавиатура, если нельзя было бы нажимать на клавиши получая при этом возможность отдавать команды? Объект Клавиатура имеет некое количество клавиш, с помощью которых пользователь приобретает контроль над устройством ввода и может отдавать необходимые команды. Обработка таких команд в целом, происходит с помощью методов. Например, вы нажимаете клавишу Esc для отмены каких-либо действий и тем самым даете команду методу, закрепленному за этой клавишей который на программном уровне решает эту задачу. Сразу же возникает вопрос о количестве методов объекта Клавиатура, но здесь может быть различная реализация - как от определения методов для каждой из клавиш (что, вообще-то, неразумно), так и до создания одного метода который будет следить за общим состоянием клавиатуры. То есть, этот метод следит за тем, была ли нажата клавиша, а потом в зависимости от того какая из клавиш задействована, решает, что ему делать.
Итак, мы видим, что каждый из объектов может иметь в своем распоряжении набор методов для решения различных задач. А поскольку каждый объект является объектом определенного класса, то получается, что класс содержит набор методов, которыми и пользуются различные объекты одного класса. В языке Java все созданные вами методы должны принадлежать или являться частью какого-то конкретного класса.
Наследование
В языке Java имеется термин наследование. Это очень мощный инструмент, без которого не обходится ни одна профессионально написанная программа. Каждый из вас, читающий эти строки обязательно хочет стать профессиональным программистом, поэтому стоит подробно рассмотреть механизм наследования.
Наследование - это механизм, позволяющий наследовать от вышестоящего в иерархии класса все его возможности. Что значит класс, стоящий выше в иерархии? В языке Java существует термин суперкласс и подкласс. Например, имеется некий класс Siemens:
class Siemens {Int w, h; int Area() { return w*h; } }
Чтобы создать подкласс класса Siemens, необходимо воспользоваться ключевым словом extends:
class SiemensMSS extends Siemens { // члены класса }
Класс SiemensMSS является подклассом класса Siemens, в свою очередь класс Siemens является суперклассом для класса SiemensMSS. Класс SiemensMSS наследует все члены своего суперкласса Siemens и имеет возможность доступа к ним при одном условии: все члены суперкласса Siemens, к которым вы впоследствии захотите получить доступ, должны быть объявлены со спецификатором public. Поскольку мы не определяли вообще никакого спецификатора, а это по умолчанию равно ключевому слову public, то подкласс SiemensMSS, будет иметь доступ ко всем членам своего суперкласса Siemens. Вы можете воспользоваться методом Area () и переменными w и h. Вам не нужно переопределять переменные и метод суперкласса Siemens, но вы можете добавлять дополнительные переменные и методы для подкласса SiemensMS 5, реализующие свои специфические действия для этого подкласса.
Давайте рассмотрим небольшой пример по созданию суперкласса и подкласса. Как вы уже, наверное, догадались, я воспользовался маркой телефона Siemens М55 для названия подкласса. Чтобы не обижать других производителей телефонов, рассмотрим пример для Nokia.
// суперкласс Nokia class Nokia { // высота, ширина и площадь дисплея int dh, dw, ds; // метод, вычисляющий площадь дисплея int Area() { return dw * dh; } } // подкласс Nokia5100 class Nokia310 extends Nokia { // высота, ширина и площадь всего телефона int th,dw, ds; // метод, вычисляюшщий площадь телефона int tArea() { return tw * th; } { //входная точка приложения class RunNokia ; { public static void main (String args[]) { // при создании объекта используется конструктор по умолчанию Nokia3100 nokia3100 = new Nokia3100(); // задаем значения для переменных noki.a3100.dh = 128; nokia3100.dw = 128; nokia3100.th = 102; nokia3100.tw = 43; // вычисляем площадь дисплея ds = nokia.dArea(); } // вычисляем полощадь телефона dt = nokia.tArea(); } { }
Создав подкласс Nokia3100, вы получите доступ ко всем членам суперкласса Nokia, определенные как public. Используя оператор "." (точка), вы открываете доступ к переменным и методам суперкласса. При создании объекта суперкласса, например Nokia nokiasuper = new Nokia (), объект созданного класса может пользоваться своими членами класса, но уже члены подкласса ему не доступны.
Иначе говоря, подкласс расширяет свой суперкласс, добавляя новые члены в подкласс, тем самым, подстраивая под себя новые, необходимые только подклассу, члены класса, оставляя за собой возможность использования членов суперкласса.
Суперкласс вправе иметь сколько угодно подклассов, например, в рассмотренном примере можно создать еще десяток-другой подклассов: Nokia5100, Nokia6600, Nokia2100 и так далее. Но каждый из подклассов может иметь только один суперкласс. Множественные наследования в языке Java не предусмотрены. Но каждый из подклассов может иметь свой подкласс, и такая цепочка наследования может длиться до разумной бесконечности.
Объектно-ориентированное программирование
Java типиризированный, и по своей природе объектно-ориентированный язык программирования. Эти термины при детальном рассмотрении очень просты в понимании. Основных типов данных мы коснемся, когда будем обсуждать семантику языка, а сейчас сосредоточимся на объектно-ориентированной парадигме современного программирования.
Объектно-ориентированное программирование построено на объектах по аналогии с нашим миром. Если оглянуться вокруг себя, то обязательно можно найти что-то, что поможет более ярко разобраться в модели такого программирования. Например, я сейчас сижу за столом и печатаю эту главу на компьютере, который состоит из монитора, системного блока, клавиатуры, мыши и так далее. Все эти части являются объектами, из которых состоит компьютер. Зная это, очень легко сформулировать какую-то обобщенную модель работы всего компьютера. Если не разбираться в тонкостях программных и аппаратных свойств компьютера, то можно сказать, что объект Системный блок производит определенные действия, которые показывает объект Монитор. Объект Клавиатура в свою очередь может корректировать или вообще задавать действия для объекта Системный блок, а тот влияет на объект Монитор. Объект Колонки предназначен для воспроизведения звуковых данных с различных источников. Построенный процесс очень хорошо характеризует всю систему объектно-ориентированного программирования. Представьте себе некий мощный программный продукт, содержащий сотни тысяч строк кода. Если не использовать объектно-ориентированное программирование, то вся программа должна выполняться построчно, строка за строкой и в принципе каждая из последующих строк кода обязательно будет связана с предыдущей. Когда потребуется изменить этот программный код, скажем при необходимости улучшения каких-то элементов, то придется произвести большое количество работы с кодом. В объектно-ориентированном программировании все куда проще. Допустим, вас уже не устраивает пятнадцати дюймовый монитор. Вы можете спокойно его обменять, например на семнадцати или девятнадцати дюймовый монитор, конечно же, при наличии определенных материальных средств. Сам же процесс обмена не повлечет за собой огромных проблем. Ну, разве что драйвер придется сменить, да вытереть пыль из-под старого монитора. Объектно-ориентированное программирование очень легко и ясно отражает суть решаемой проблемы и что самое главное, дает возможность веь ущерба для всей программы убирать старые и ненужные объекты заменяя их на новые, точней говоря, модернизировать без лишних затрат. Также общая читабельность всей программы становится намного проще. Существенно и то, что один и тот же код можно использовать в абсолютно разных программах.
Объекты классов
Объекты представляют класс, наследуя от своего класса все возможности. Объявить объект очень просто, необходимо вначале указать класс, а потом объект этого класса. Например:
Telefon object;
Точно так же как создается переменная int а, создается и объект класса. Такая запись создаст пустой объект класса, инициализирующийся значением null. Конечно, это еще не полноценный объект, а всего лишь ссылка на данный класс. Чтобы создать полноценный класс, нужно воспользоваться ключевым словом new, с помощью которого происходит выделение области памяти для содержания создаваемого объекта.
Telefon object; object = new Telefon);
или
Telefon object = new Telefonf);
Обе записи создания объекта класса Telefon одинаковы. Чаще всего используется вторая запись, но это можно оставить на усмотрение программиста. Сначала создается пустая ссылка object, а потом с помощью ключевого слова new выделяется память для объекта и он инициализируется конструктором класса Telefon (). Именно тут и необходим хорошо продуманный конструктор с параметрами, инициализирующий объект с заданными значениями.
Теперь давайте рассмотрим пример посложнее. Создадим класс с конструктором для инициализации высоты и ширины дисплея и в методе main () создадим объект класса Telefon, вычислив при этом площадь экрана абстрактного телефона.
class Telefon { int w, h, s; // конструктор класса Telefon Telefon (int a, int b) { w = a; h = b; } // метод, вычисляющий площадь экрана void Area() { S = w*h; } } // class RunTelefon может находится в файле RunTelefon.Java class RunTelefon { public static void main (String args[]) { // создаем объект класса Telefon Telefon object = new Telefon (70, 90); // вычисляем площадь дисплея object.Area(); } }
Разберем весь пример более подробно. Итак, мы создаем класс Telefon с тремя переменными: w, h и s, в которых впоследствии будут храниться, соответственно, ширина, высота и площадь дисплея телефона. Далее создаем конструктор класса Telefon для инициализации высоты и ширины дисплея. Метод Area () класса Telefon вычисляет площадь экрана, сохраняя полученный результат в переменной s. После этого идет класс RunTelefon с методом main (), являющийся входной точкой для всей программы. Как только написанное приложение начнет работать, программа найдет метод main () и начнет выполнять содержимое программы.
В первой строке кода метода main () происходит создание объекта класса Telefon со значениями ширины - 70 и высоты - 90 для экрана телефона. Вторая строка кода вызывает метод Area (), вычисляющий площадь дисплея. Метод Area () нельзя просто так вызвать в программе, он должен ссылаться на объект класса Telefon. Запись object.Area () как раз и указывает на то, что объект класса Telefon вызывает метод Area (). Если имеется несколько объектов класса Telefon, то есть несколько различных телефонов, тогда вызов метода Area () должен происходить для каждого из объектов класса Telefon, например:
object1.Area(); object2.Area(); objects.Area();
Для каждого из объектов класса Telefon будет вычисляться только своя площадь экрана. Давайте рассмотрим еще более сложную программу, создав несколько объектов класса Telefon, а заодно используем другую схему работы метода Area (), воспользовавшись ключевым словом return.
class Telefon { int w, h, s, n; // конструктор Telefon (int a, int b) { w = a; h = b; } // вычисляет площадь дисплея int Area() { return w*h; } } // class RunTelefon может находится в.файле RunTelefon.java class RunTelefon { public static void main (String[] args) { // создадим объект Siemens Telefon Siemens = new Telefon (101, 8.0); // создадим объект nokia Telefon nokia = new Telefon (128, 128); // сохраним полученную площадь в s s = Siemens.Area(); // сохраним полученную площадь в n n = nokia.Area(); } }
В реализации класса Telefon изменился только метод Area (), использовалось ключевое слово return. С его помощью результат умножения высоты на ширину, то есть результат работы всего метода возвращается для дальнейшего использования в коде программы. А в рабочем цикле программы в методе main (), этот результат сохраняется в двух переменных s и N для каждого из объектов класса Telefon. В данном случае площадь экрана для объекта Siemens равна 101x80=8080, а для объекта nokia 128x128=16384 и оба результата хранятся в различных переменных.
У вас наверно сразу возникает вопрос, а как увидеть получившийся результат? Действительно, просчитать значение не составляет труда, но хотелось бы увидеть полученный результат на дисплее. Для этого в Java существует встроенный метод print In(). Чтобы увидеть на экране результат работы метода Area (), нужно добавить вызов метода print In ().
s = Siemens.Area(); System.out.println("Площадь экрана Siemens" + s) ; n = nokia.Area() System.out.println("Площадь экрана nokia" + n) ;
Метод print (), как уже говорилось, встроенный и принадлежит классу System, поэтому такая запись, out — это поток ввода, связывающий программу с консолью. Реально в программировании телефонов метод printIn () используется, как правило, в диагностических целях, но как логическое завершение примера подойдет. С помощью кавычек ограничивается количество выводимого на экран текста, это необходимое условие. Запись + s, применяет операцию конкатенации на основе оператора +, с помощью которого на экран выводится значение переменной s, то есть целочисленное значение равное площади экрана.
Резюмируя объектно-ориентированное программирование, можно с уверенностью заявить - это не сложно, не страшно, достаточно понятно и, что самое главное, просто в использовании. Создав необходимый класс, объявив объект и воспользовавшись методами созданного класса, вы получаете неограниченные возможности в программировании приложений. Но главное - большое количество необходимых классов и методов уже созданы за вас и собраны в специальные библиотеки, о которых мы поговорим в конце этой главы. Вам же остается только воспользоваться этими готовыми классами, создавая свои объекты этих классов.
Оператор while
Синтаксическая запись оператора while выглядит следующим образом:
while (условие) { // действия }
Также имеет место выполнение определенного предусловия, но в отличие от оператора if/else, данная конструкция построена на циклах проверки условия. Когда программа доходит до оператора while, если предложенное условие истинно, происходит выполнение всех действий в блоке из фигурных скобок {...}. После выполнения этих действий, снова происходит очередная проверка условий после оператора whilе и если условие опять истинно, происходит повторное выполнение действий в блоке. Действия в блоке выполняются до тех пор, пока условие не станет ложным, тогда происходит выход из цикла while. В основном все циклы управляются при помощи так называемых счетчиков. Рассмотрим не большой пример:
int i = 0; while (i < 10) { // действия i + +; }
Сначала переменной i присваивается значение 0, далее происходит проверка условия i<10, если переменная i меньше цифры 10, выполняются все действия в блоке цикла. В конце блока переменная i увеличивается на 1и вновь проверяется условие в цикле. И так ровно десять, раз для нашего примера. Переменная i служит счетчиком для цикла while. Отсутствие операции по увеличению переменной i на единицу приведет к бесконечному циклу, поскольку 0 всегда будет меньше десяти. В циклах так же можно использовать оператор декремента, например:
int. i = 10; while (i>0) { // действия i --; }
Те же действия, но уже в обратную сторону. Но все-таки чаще всего используется оператор декремента.
В цикле while имеется возможность использования булевых переменных, содержащих значения false или true. После оператора while происходит проверка предусловия, то можно воспользоваться булевой переменной, например:
boolean i = true, while (i) { // действия }
Переменная i истинна, ей присвоено значение true, поэтому происходит выполнение цикла whilе. Единственное о чем необходимо позаботиться - это о выходе из такого цикла, поскольку переменная i истинна, то цикл while будет выполняться бесконечно и такие циклы носят названия бесконечных циклов.
Напоследок хочу еще обратить ваше внимание на оператор равно ==. Если записать цикл таким образом:
int i = 0 while (i = = 5) { // действия i + +; }
То получится вполне работоспособный цикл, а вот если вы ошибетесь или по привычке воспользуетесь классическим вариантом оператора равно =, использующимся в математике, то у вас будет проблема в виде бесконечного цикла.
int i =0 while (i = 5) { // действия i++; }
В предусловии происходит присвоение переменной i значения 5, а оттого, что это действие не запрещено, то произойдет выполнение блока цикла. В конце которого значение i увеличится на один, но в предусловии после оператора while, переменной i новь будет присвоено значение пять - это пример простого бесконечного цикла и как следствие, классическая ошибка, случающаяся с начинающими программистами.
Операторы
Операторы языка Java имеют различные назначения. Существуют арифметические операторы, операторы инкремента и декремента, логические операторы и операторы отношения.
Арифметические операторы очень просты и аналогичны операторам умножения "*", деления "/", сложения "+" и вычитания "-" используемые в математике. Существует оператор деления по модулю "%" и слегка запутанная на первый взгляд ситуация с оператором равно "=". Оператор равно в языках программирования называется оператором присваивания:
int х = 3
Здесь вы переменной х присваиваете значение 3. А оператор "равно" в языках программирования соответствует записи двух подряд операторов "равно": <= = >. Рассмотрим на примере, что могут делать различные арифметические операторы.
int х, у, z; ; х = 5; У = 3 ; Z = 0; z = х + у;
В данном случае z будет иметь значение уже суммы х и у, то есть 8.
x = z*x;
Переменная х имела значение 5, но после такой записи предыдущее значение теряется и записывается произведение z *х (8*5), что равно 40. Теперь, если мы продолжим дальше наш код, то переменные будут иметь такой вид:
// х = 40; // У = 3 ; // z = 8;
Это обязательно необходимо иметь в виду.
Что касается оператора деления, то поскольку Java 2 ME не поддерживает дробных чисел, то результат такого деления:
x = z/y;
что равносильно записи:
х = 8/3;
будет равен 2. Дробная часть просто отбрасывается, то же самое происходит при использовании оператор деления по модулю "%".
Операторы сложения и вычитания имеют те же назначения что и в математике. Отрицательные числа так же родственны.
Операторы декремента "—" и инкремента "++" весьма специфичны, но очень просты. В программировании часто встречаются моменты, когда требуется увеличить или уменьшить значение на единицу. Часто это встречается в циклах. Операция инкремента увеличивает переменную на единицу.
int x = 5; х++; // Здесь х уже равен 6
Операция декремента уменьшает переменную на единицу.
int х = 5; х -- ; //х равен 4
Операции инкремента и декремента могут быть пост и префиксными:
int х = 5; int у = 0; y = х++;
8 последней строке кода сначала значение х присваивается у, это значение 5, и только потом переменная х увеличивается на еденицу. Получается что:
х = 6, у = 5
Префиксный инкремент имеет вид:
int х = 3; int у = 0; у = ++х;
И в этом случае, сначала переменная х увеличивается на один, а потом присваивает уже увеличенное значение у.
у = 4, х = 4
Операторы отношения позволяют проверить равенство обеих частей выражения. Имеется оператор равенства "= =", операторы меньше "<" и больше ">", меньше или равно "<=" и больше или равно ">=", а так же оператор отрицания "!=".
9 = = 10;
Это выражение не верно, девять не равно десяти, поэтому его значение этого выражения равно false.
9 != 10;
Здесь же, наоборот, оператор отрицания указывает на неравенство выражения, и значение будет равно true.
Операторы больше, меньше, больше или равно и меньше или равно аналогичны соответствующим операторам из математики.
Существует два логических оператора. Оператор "И", обозначающийся значками "&&" и оператор "ИЛИ", обозначенный в виде двух прямых слешей "||". Например, имеется выражение:
А*В && В*С;
В том случае, если только обе части выражения истинны, значение выражения считается истинным. Если одна из частей неверна, то значение всего выраже- , ния будет ложным.
В противовес оператору "&&" имеется оператор "I I ", не напрасно имеющий название "ИЛИ".
А*В|| В*С;
Если любая из частей выражения истинна, то и все выражение считается истинным. Оба оператора можно комбинировать в одном выражении, например:
А*В || B*C && C*D ||В*А;
С помощью этого выражения я вас ввел, как мне кажется, в затруднение, неправда ли? Дело в том, что в Java, как и в математике существует приоритет или так называемая иерархия операторов, с помощью которой определяется какой из операторов главнее, а, следовательно, и проверяется первым. Рассмотрим с помощью списка приоритет всех операторов языка Java:
[] , . , () , ! , ~, ++, - -, +(унарный), -(унарный), new, *, /, % , +, -, << , >>, >>>, <, <=, >, >=, = = , !=, &, ^, | , &&, || , ?:, = , +=, -=, *=, /=, %=, |=, ^=, <<=, >>=, >>>=.
Не со всеми операторами вы еще знакомы, поэтому пугаться не стоит. Ассоциативность операторов в списке следует слева на право и сверху вниз. То есть все, что находится левее и выше - старше по званию и главнее.
Пакеты
При наличии большого количества своих классов, можно создавать пакеты, для этих классов, коллекционируя их. С помощью ключевого слова package можно создать пакет для класса. Для этого в самом начале файла, где вы пишете исходный код для класса, сделайте запись, например следующую, для созданного ранее в разделе 1.10.1 класса Nokia:
package Nokia;
В последствии вы сможете получить доступ к пакету с этим классом с помощью спецификатора import в начале файла, где вам необходим класс Nokia.
import Nokia.*
Оператор звездочка в конце импорта класса Nokia обозначает доступ ко всем классам этого пакета. Но возможно обращение и к отдельному классу всего пакета, например:
import Nokia..NokiaeSeries60 .Nokia6600;
При условии, конечно, что все эти классы существуют в пакете Nokia. Если вы собираетесь использовать много классов из пакета, то лучше воспользоваться оператором звездочка, чем перечислять каждый класс в отдельной строке кода.
Кроме этого пакеты имеют еще одну ценную возможность - при создании своих классов существует вероятность того, что какой-нибудь программист, собирающий яблоки в Новой Зеландии возьмет и назовет свой созданный класс точно таким же именем. В этом случае возникает конфликт имен вызывающий исключительную ситуацию. Но если пользоваться возможностью создания пакетов, такая вероятность повторения снижается. Даже если названия созданных классов будут одинаковыми, содержаться они будут в разных пакетах. Конфликта не возникнет. Слышу провокационный вопрос: а если названия пакетов совпадут? Да вы правы, есть же сказка про Буратино от двух разных авторов... В таком случае можно воспользоваться рекомендуемой компанией Sun Microsystems, создавшей язык Java, схемой записи по зарезервированному домену в Интернете, например':
package ru.dmk;
Или как в случае упомянутой сказки о деревянном человечке:
package Buratino; package Pinocchio;
И избежать тем самым конфликта имен. Такой способ записи по домену действительно работает и на этой схеме построены все пакеты в Java.
Язык Java имеет огромное количество предопределенных классов, существующих в виде библиотек. Все библиотеки разбиты на пакеты по своему назначению. Платформа Java 2 ME состоит из одиннадцати пакетов:
Каждый из пакетов содержит множество классов с различной областью применения. Имеются математические классы, классы, отвечающие за работу с сетью, классы ввода-вывода, классы утилит и так далее. Более подробно каждый из пакетов будет рассмотрен в главе 2. Для того чтобы воспользоваться имеющимися классами и методами, необходимо в начале исходного кода импортировать нужный для работы пакет:
import java.lang.*
Затем можно воспользоваться, к примеру методом abs (int а) .класса Math, возвращающим целочисленное значение переменой.
int а = 9; int x = Math.abs(a);
Импортируя пакеты в программу, вы упрощаете разработку приложения, поскольку имеется огромное количество готовых классов и достаточно просто создать объект импортированного класса и пользоваться всеми его методами и возможностями.
В этом приложении мы рассмотрели язык программирования Java вкратце, но изученного материала будет достаточно для прочтения этой книги и освоения азов программирования мобильных телефонов на Java 2 Micro Edition.
Основы языка Java
Синтаксис и семантика языка Java ME
Для того чтобы говорить и читать на любом иностранном языке, необходимо изучить алфавит и грамматику этого языка. Подобное условие наблюдается и при научении языков программирования, с той лишь разницей, как мне кажется, что этот процесс несколько легче.
Таким образом, как вы знаете из раздела посвященного основам программирования, прежде чем начинать писать исходный код программы, необходимо сначала решить поставленную перед вами задачу в любом удобном для себя виде.
Давайте создадим некий класс отвечающий, например, за телефон, который будет иметь всего два метода: включающий и выключающий этот самый телефон. Поскольку мы сейчас не знаем синтаксис языка Java, то, напишем класс Телефон на абстрактном языке.
Класс Телефон { Метод Включить() { // операции по включению телефона } Метод Выключить() { // операции по выключению телефона } }
Таким вот образом может выглядеть класс Телефон. Заметьте, что фигурные скобки обозначают соответственно начало и конец тела класса, метода, либо всякой последовательности данных. То есть скобки указывают на принадлежность к методу или классу. На каждую открывающую скобку обязательно должна быть закрывающая скобка. Чтобы не запутаться их обычно ставят на одном уровне в коде. А теперь давайте запишем тот же самый класс только уже на языке Java.
class Telefon { void on() { // тело метода оn() } void off() { // тело метода off () } }
Ключевое слово class в языке Java объявляет класс, далее идет название самого класса. В нашем случае это Telefon. Сразу пару слов касательно регистра записи. Почти во всех языках программирования важно сохранять запись названий в том регистре, в котором она была сделана. Если вы написали Telefon, то уже такое написание как telefon или TELefoN выдаст ошибку при компиляции. Как написали первоначально, так и надо писать дальше.
Зарезервированные или ключевые слова записываются в своем определенном регистре, и вы не можете их использовать, давая их названия методам, классам, объектам и так далее.
Пробелы между словами не имеют значения, поскольку компилятор их просто игнорирует, но для читабельности кода они важны.
В теле класса Telefon имеются два метода: on () - включающий телефон и метод off () - выключающий телефон. Оба метода имеют свои тела и в них по идее должен быть какой-то программный код, описывающий необходимые действия обоих методов. Для нас сейчас не важно как происходит реализация этих методов, первостепенное - это синтаксис языка Java.
Оба метода имеют круглые скобки on (), внутри которых могут быть записаны параметры, например on (int time) или on (int time, int time1). С помощью параметров происходит своего рода связь методов с внешним миром. Говорят, что метод on (int time) принимает параметр time. Для чего это нужно? Например, вы хотите, чтобы телефон включился в определенное время. Тогда целочисленное значение в параметре time будет передано в тело метода и на основе полученных данных произойдет включение телефона. Если скобки пусты, то метод не принимает никаких параметров.
Типы данных Java
Чтобы задать произвольное значение, в Java существуют типы данных. Как уже говорилось, Java - язык типиризированный, поэтому каждое значение имеет свой тип. В классе Telefon мы создали два метода. Оба метода не имели параметров, но когда приводился пример метода on (int time) с параметром time, говорилось о передаче значения в метод. Данное значение указывало на время, с помощью которого якобы должен включиться телефон. Спецификатор int как раз и определяет тип значения time. В Java 2 ME шесть типов данных. Посмотрите на табл. 1.1.
Таблица 1.1.
| Тип |
Назначение |
Размер в байтах |
| byte |
маленькое целое |
1 |
| short |
короткое целое |
2 |
| int |
целое |
4 |
| long |
длинное целое |
8 |
| char |
символ |
2 |
| boolean |
логический тип |
  |
Java 2 ME в отличие от Java 2 SE не поддерживает числа с дробной частью в связи с тем, что мобильные устройства имеют небольшие по объему ресурсы.
Чтобы объявить какое-то необходимое значение используется запись:
int time; long BigTime; char word;
Оператор точка с запятой необходим после таких записей в конце строки. Можно совместить несколько одинаковых по типу объявлений через запятую:
mt time, timel, time2;
Теперь давайте, усовершенствуем наш класс Telefon, добавив в него несколько значений. Методы on () и off () нам больше не нужны, добавим методы поинтересней.
class Telefon { //s- площадь дисплея //w - высота дисплея //h - ширина дисплея int w, h, s; //метод вычисляющий площадь дисплея vord Area.() { S = w*h; } }
Итак, мы имеем три переменные S, w и h, отвечающие, соответственно, за площадь, высоту и ширину дисплея в пикселях. Метод Area () вычисляет площадь экрана телефона в пикселях. Операция бесполезная, но очень показательная и простая в понимании. Тело метода Area () обрело себя и имеет вид S = w*h. Мы просто перемножаем высоту на ширину и присваиваем или как еще говорят, сохраняем результат в переменной S. Сейчас мы подошли вплотную к операторам языка Java, с помощью которых можно совершать всевозможные операции.
Управляющий оператор
В языке Java существует управляющий оператор switch, который можно в принципе отнести к условным операторам. Он тоже основан на неких условиях, но предоставляет многовариантное ветвление для выбора пути заданных действий. Посмотрите на синтаксический шаблон этого оператора:
switch (условие) { case 1 // действие 1 break; case 2: // действие 2 break; case 20: // действие 20 break; default: //-действие по умолчанию break; }
Вся конструкция оператора switch основана на метках case, имеющих целочисленные значения. Когда условие, проверяющееся оператором switch совпадает с одним из значений метки case, то последующие за меткой действия будут выполнены. Если ни одно из условий не совпало с меткой case, то будут выполнены действия, следующие за меткой default. Оператор break, использующийся в конце всех действий для каждой метки очень важен. Когда условие совпадет с одной из меток и начнется выполнение указанных действий для этой метки, то выходной точкой служит оператор break. Если вы случайно забудете поставить оператор break, то ваша программа начнет выполнять следующую метку, сведя тем самым ваши усилия по выбору заданных действий на ноль. Никогда не забывайте ставить оператор break для каждой из меток!
Условные операторы
Когда мы создавали и использовали класс RunTelefon, с методом main (), я говорил, что программа выполняет прописанный код строка за строкой и это действительно так. В небольших программах, таких, как мы создали, этого вполне достаточно, но в действительно огромных программах такой подход не логичен. Нельзя "прыгать" по программе, надо идти от строки к строке. Но если все же требуется перейти в программе к какому-то методу или месту программы, что тогда? Для этого в языке Java существуют условные операторы.
Рассмотрим ситуацию, которая более наглядно объяснит смысл операторов. Допустим, вы дома, у вас нет хлеба и надо сбегать в булочную за углом. Прежде чем идти в булочную вы обязательно проверите, есть ли у вас деньги на покупку хлеба и только потом отправитесь в магазин за хлебом. Здесь имеет место предусловие наличия денег, выполнение которого приводит вас либо к походу за хлебом, либо к соседу за деньгами. В том случае, если не рассматривать это предусловие, то вы бы вышли и пошли в магазин, а уже придя, стали бы искать по карманам. Вот для этого и существуют условные операторы. В языке Java имеется несколько условных операторов. Первый из них: if /else - представляющий собой такую сдвоенную конструкцию. Синтаксический шаблон условного оператора if /else выглядит следующим образом:
if (условие) { // действие №1 } else { // действие №2 }
Переводя эту конструкцию на русский язык, можно сказать: если (if) некое условие верно, то перейти к действию №1, а иначе (else) выполнить действие №2. Такая сдвоенная конструкция if /else может быть не обязательна, иногда достаточно лишь записи оператора if. Можно использовать вложенные операторы if /else, например:
if (условие 1) { if (условие 2) { } }
Здесь проверяется первое условие и если оно верное, то происходит переход к следующему оператору if, если и это условие верное, то выполняются действия и во втором и в первом условном операторе. Если же условие во втором операторе if не верно, то выполняются действия только первого оператора if. Условные операторы в программировании на Java используются постоянно и важно понимать их общий принцип работы.
В приложении
Это приложение не претендует на роль полного руководства по языку Java (Ява), но данного материала будет достаточно для дальнейшего изучения книги. Предлагаемая к рассмотрению в этом разделе информация содержит основы языка Java и ориентирована на неподготовленного читателя. Также нужно иметь в виду, что обучение языку Java будет происходить в соответствии с контекстом книги, а именно, всей той части языка Java, необходимой для программирования мобильных устройств. То есть такие "продвинутые" темы как аплеты, библиотеки AWT и Swing в этом приложении не рассматриваются, поскольку не применяются в Java 2 Micro Edition.
Введение в программирование
Программирование - это написание исходного кода программы на одном из языков программирования. Существует множество различных языков программирования, благодаря которым создаются всевозможные программы, решающие определенный круг задач. Язык программирования - это набор зарезервированных слов, с помощью которых пишется исходный код программы. Компьютерные системы еще не в силах понимать человеческий язык и логику, поэтому все программы пишутся на языках программирования, которые впоследствии переводятся на язык компьютера, то есть в машинный код. Системы, переводящие исходный код программы в машинный код, очень сложные и их, как правило, создают не один десяток месяцев и не один десяток программистов. Такие системы называются интегрированными средами программирования приложений.
Система программирования представляет собой огромную продуманную визуальную среду, где можно писать исходный код программы, переводить его в машинный код, тестировать, отлаживать и многое другое. Также существуют программы, которые позволяют производить вышеперечисленные действия при помощи командной строки. Язык Java предоставляет такую возможность, но в книге данная проблематика не освещается.
Вы, наверное, не раз слышали термин "программа написана под Windows или под Linux, Unix". Дело в том, что среды программирования при переводе языка программирования в машинный код могут быть двух видов — это компиляторы и интерпретаторы. Говоря про общий вид: компиляция или интерпретация программы задает способ дальнейшего выполнения программы. Программы написанные на языке Java всегда работают на основе интерпретации, тогда как программы написанные на C/C++ - компиляции. В чем разница этих двух способов? Компилятор после написания исходного кода в момент компиляции читает сразу весь исходный код программы и переводит в машинный код. После чего программа существует как одно целое и может выполняться только в той операционной системе, в которой она была написана. Поэтому программы, написанные под Windows, не могут функционировать в среде Linux и наоборот. Интерпретатор осуществляет пошаговое или построчное выполнение программы каждый раз, когда она выполняется. Во время интерпретации создается не выполняемый код, а виртуальный, который впоследствии выполняется виртуальной Java машиной. Поэтому на любой платформе — Windows или Linux, Java-программы могут одинаково выполняться при наличии в системе виртуальной Java машины, которая еще носит название Системы времени выполнения.
Все что сейчас от вас требуется - это изучение синтаксиса языка Java, для того чтобы писать и понимать исходные коды программ, написанные на этом языке. А так же освоить работу с одной из сред программирования, подробное описание которых вы найдете в главе 3. Это приложение содержит теоретический материал, раскрывающий особенности программирования на языке Java.
Закрытые и открытые члены классов
Ключевое слово public, объявленное перед методом main (), показывает на то, что метод main () считается открытым или в любом классе метод main () виден, и к нему можно обратиться. Ключевое слово public может назначаться не только методам, но и объектам класса, переменным, любым членам созданного класса. Все объявленные члены класса с ключевым словом public, будут доступны всем другим существующим в программе классам, поэтому стоит призадуматься, а хорошо ли это? Например, у вас есть какие-то данные, которые не должны быть доступны другим классам, что тогда? Для этого в языке Java существует еще пара ключевых слов: private и protected, благодаря которым вы защищаете свои члены классов от общего доступа.
По умолчанию, если вы не используете ключевые слова, Java назначает всем членам класса спецификатор public. Метод main () всегда должен вызываться с ключевым словом public, чтобы для всех классов программы метод main () был доступен. Как только программа начнет работать, первым делом она ищет метод main () и постепенно, шаг за шагом, а точнее, строка за строкой, выполняет все предписанные действия в методе main ().
Интерфейс Certificate
Общий сертификат связи.
Методы
Интерфейс Choice
Содержит набор методов создающих возможность выбора заданных элементов
Методы
Константы
Интерфейс CommandListener
Реализует возможность обработчика событий.
Метод
Интерфейс CommConnection
Находит последовательный порт.
Методы
Интерфейс Connection
Общий тип всей связи с сетью.
Метод
Интерфейс ContentConnection
Определяет связь с потоком.
Методы
Интерфейс Controllable
Осуществляет контроль над объектами.
Методы
Интерфейс Datagram
Общий интерфейс дейтограммы.
Методы
Интерфейс DatagramConnection
Определяет возможность связи дейтограммы.
Методы
Интерфейс Datalnput
Декларирует Методы для чтения простых типов во входном потоке данных.
Методы
Интерфейс DataOutput
Декларирует Методы для записи простых типов в выходной поток данных.
Методы
Интерфейс Enumeration
Декларирует возможность доступа к элементам.
Методы
Интерфейс HttpConnection
Декларирует Методы и Константы для протокола соединения HTTP.
Методы
Константы
Интерфейс HttpsConnection
Декларирует Методы и Константы для безопасного сетевого соединения.
Методы
Интерфейс InputConnection
Интерфейс для создания входной связи с сетью.
Методы
Интерфейс ItemCommandListener
Реализует возможность получения событий от объектов класса Item.
Метод
Интерфейс ItemStateListener
Используется при получении событий о состоянии объектов класса Item устроенных в Form.
Метод
Интерфейс OutputConnection
Интерфейс для создания выходной связи с сетью.
Методы
Интерфейс Player
Реализует контроль над воспроизведением.
Методы
Константы
Интерфейс PlayerListener
Получает асинхронные события проигрывателя.
Методы
Константы
Интерфейс Record Filter
Определяет совпадения записей.
Метод
Интерфейс RecordComparator
Осуществляет сортировку записей.
Метод
Константы
Интерфейс RecordEnumeration
Реализует двунаправленный список записи.
Методы
Интерфейс RecordListener
Производит обработку событий связанных с изменением, добавлением и удалением записей.
Методы
Интерфейс Runnable
Метод
Интерфейс SecureConnection
Определяет безопасную связь с сетью.
Метод
Интерфейс Securitylnfo
Имеет в своем составе методы для получения информации сетевой связи.
Методы
Интерфейс ServerSocketConnection
Реализует связь с сервером.
Методы
Интерфейс SocketConnection
Находит разъем (socket) для потока связи.
Методы
Константы
Интерфейс StreamConnection
Этот интерфейс определяет связь с потоком и не имеет методов и констант.
Интерфейс StreamConnectionNotifier
Определяет возможность всей связи.
Метод
Интерфейс ToneControl
Производит воспроизведение тональных звуков на устройстве.
Метод
Константы
Интерфейс UDPDatagramConnecJion
Реализует связь с дейтограммой.
Методы
Интерфейс VolumeControl
Регулирует громкость воспроизведения.
Методы
Исключение
Исключение
Исключение
Исключения
Исключения
Исключения
Исключения
Класс Alert
Создает различные информационные сообщения.
Конструкторы
Методы
Константы
Класс AlertType
Отображает тип уведомления.
Конструктор
Метод
Класс Boolean
Объектно-ориентированный класс-оболочка или как еще говорят "обвертка" для типа Boolean. Конструктор
Методы
Класс Byte
Объектно-ориентированный класс оболочка, для простого типа Byte. Конструктор
Методы
Константы
Класс ByteArraylnputStream
Совершает чтение входного потока байт из массива данных для дальнейшего размещения их в памяти.
Конструкторы
Методы
Константы
Класс ByteArrayOutputStream
Производит запись потока байт из памяти в массив выходных данных.
Конструкторы
Методы
Константы
Класс Calendar
Необходим для работы с датой и временем, выполняет функции обыкновенного календаря.
Конструктор
Методы
Константы
Класс Canvas
Абстрактный класс, обеспечивающий графическую прорисовку различных элементов на экране телефона.
Конструктор
Методы
и реализует стрельбу из оружия;
КонстантыКласс Character
Объектно-ориентированный класс-оболочка для простого типа Char. Конструктор
Методы
Константы
Класс ChoiceGroup
Встраиваемая группа выбираемых, элементов. Интегрируется в класс Form, наследуется от класса Item и реализует интерфейс Choice.
Конструктор
Методы
Класс Class
Виртуальная Java машина создает объекты этого класса, которые представляют интерфейсы и классы языка Java. Методы
Класс Command
Инкапсулирует командные действия, при этом не определят фактические действия на команды, а лишь содержит информацию.
Конструкторы
Методы
Константы .
Класс Connector
Класс для создания объектов связи.
Методы
Константы
Класс Custom Item
Создает возможность в отображении новых графических элементов встроенных в класс Form.
Конструктор
Методы
Константы
Класс DatalnputStream
Этот класс наследуется от интерфейса Datalnput, реализуя при этом все его Методы.
Конструктор
Методы
Константа
Класс DataOutputStream
Этот класс наследуется от интерфейса DataOutput, реализуя при этом все его Методы.
Конструктор
Методы
Константа
Класс Date
Реализует возможность работы с датой.
Конструкторы
Методы
Класс DateField
Класс, представляющий работу с датой и временем. Интегрируется в класс Form, наследуется от класса Item.
Конструкторы
Методы
Константы
Класс Display
Менеджер дисплея определяющий, какой из объектов будет представлен на дисплее.
Методы
Константы
Класс Displayable
Абстрактный класс, содержит иерархию классов пользовательского интерфейса.
Методы
Класс Font
Класс шрифтов.
Методы
Константы
Класс Form
Этот класс создает пустую форму, в которую интегрируются классы пользовательского интерфейса. Конструкторы
Методы
Класс GameCanvas
Абстрактный класс, содержащий основные элементы игрового интерфейса.
Конструктор
Методы
Константы
Класс Gauge
Представляет графическое течение процесса, своего рода датчик или счетчик.
Конструктор
Методы
Константы
Класс Graphics
Предоставляет возможность рисования графических элементов на экране мобильного устройства.
Методы
Константы
Класс Hashtable
Предоставляет возможность хранения объектов с доступом к ним по определенно заданному ключу.
Конструкторы
Методы
Класс Image
Отвечает за загрузку и отображение любых видов графических изображений формата PNG.
Методы
Класс Imageltem
Контейнер для загружаемых в приложение сложных графических изображений
Конструкторы
Методы
Класс InputStreamReader
Наследуется от класса Reader, реализуя Методы для чтения символьных данных входного потока с перекодировкой.
Конструкторы
Методы
Класс Integer
Объектно-ориентированный класс для простого типа int.
Конструктор
Методы
Константы
Класс Item
Суперкласс, содержащий ряд классов для их дальнейшей интеграции в класс Form.
Методы
Константы
Класс Layer
Абстрактный класс, отвечающий за уровни представляемые в игре
Методы
Класс LayerManager
Менеджер имеющихся в игре уровней.
Конструктор
Методы
Класс List
Создает список группы элементов.
Конструкторы
Методы
Константа
Класс Long
Объектно-ориентированный класс-оболочка для простого типа long. Конструктор
Методы
Константы
Класс Manager
Менеджер системных ресурсов.
Методы
Константа
Класс Math
Математический класс, содержащий несколько методов для различных математических операций. Очень сильно урезан в отличие от класса Math из Java 2 SE.
Методы
Класс MIDIet
Основной класс мйдлета должен наследовать класс MIDlet для управления работой приложения.
Конструктор
Методы
Класс Object
Суперкласс для всех классов Java. Все классы наследуются от класса Object и являются его подклассами
Методы
Класс OutputStream
Абстрактный класс, предназначенный для работы с выходным потоком байт.
Конструктор
Методы
Класс OutputStreamWriter
Наследуется от класса Writer, реализуя Методы для записи символьных данных в выходной поток с перекодировкой. Конструкторы
Методы
Класс PrintStream
Расширяет выходной поток способностью печати данных.
Конструктор
Методы
Класс PushRegistry
Класс для поддержания списков связей.
Методы
Класс Random
Генератор случайных чисел.
Конструкторы
Методы
Класс Reader
Абстрактный класс, предназначенный для чтения символьных потоков данных.
Конструкторы
Методы
Константа
Класс RecordStore
Производит запись данных.
Методы
Константы
Класс Runtime
Класс времени исполнения приложения.
Методы
Класс Screen
Суперкласс для всех высокоуровневых классов определяющих пользовательский интерфейс приложения.
Класс Short
Объектно-ориентированный класс-оболочка для простого типа Short. Конструктор
Методы
Константы
Класс Spacer
Создает заданное пространство на экране.
Конструктор
Методы
Класс Sprite
Создает спрайт, представляющий изображение или анимационные фреймы.
Конструкторы
Методы
Константы
Класс Stack
Реализует функциональность стека.
Конструктор
Методы
boolean ignoreCase, int toffset, String
regionMatches ( boolean ignoreCase, int toffset, String other, int oof f set, int len) - проверяет заданную область текста на совпадение;Класс String Item
Формирует текстовые строки.
Конструкторы
Методы
Класс String
Создает символьные строки текста. Конструкторы
Методы
Класс StringBuffer
Класс StringBuffer может содержать строки символов любого размера.
Конструкторы
Методы
Класс System
Содержит ряд системных методов.
Методы
Константы
Класс TextBox
Организовывает редактируемый текстовый контейнер.
Конструктор
Методы
Класс TextField
Создает редактируемый текстовый контейнер, который встраивается в класс Form.
Конструктор
Методы
Константы
Класс Thread
Создает поток в работе приложения для виртуальной Java машины, мобильных телефонов. Доступна многопоточность.
Конструкторы
Методы
Константы
Класс Throwable
Суперкласс для всех классов, предназначенных для работы с ошибками и исключениями в языке программирования Java.
Конструкторы
Методы
Класс Ticker
Создает на экране бегущую строку текста.
Конструктор
Методы
Класс Tiled Layer
Осуществляет создание фоновых изображений.
Конструктор
Методы
Класс Timer
Реализует возможность работы со временем по принципу таймера.
Конструктор
Методы
Класс TimerTask
Планировщик задач.
Конструктор
Методы
Класс TimeZone
Устанавливает и определяет часовой пояс.
Конструктор
Методы
Класс Vector
Создает массивы любого размера. Имеет возможность изменять размер заданного массива.
Конструкторы
Методы
Константы
Класс Writer
Абстрактный класс, предназначенный для записи символьных данных в выходной поток.
Конструкторы
Методы
Константа
КлассInputStream
Абстрактный класс, предназначенный для работы с входным потоком байт.
Конструктор
Методы
Ошибки
Пакет Javaio
Классы этого пакета отвечают за работу с входными и выходными потоками данных.
Пакет javautil
В этом пакете содержатся классы стандартных утилит для создания Java 2 ME приложений. Пакет сильно урезан по сравнению со стандартным пакетом Java 2 SE.
Пакет javaxmicroeditionio
Этот пакет обеспечивает мобильное устройство связью с сетью.
Пакет javaxmicroeditionlcdui
Пакет классов пользовательского интерфейса (UI) для создания полей, форм, уведомлений, текста и так далее.
Пакет javaxmicroeditionlcduigame
Игровой пакет, благодаря которому можно достаточно легко создавать игры для мобильных устройств.
Пакет javaxmicroeditionmedia
Пакет добавлен в профиль МШР 2.0 и дает возможность в создании звукового сопровождения в приложении.
Пакет javaxmicroeditionmidlet
С помощью этого пакета происходит связь между приложением и мобильным информационным профилем устройства (MIDP).
Пакет javaxmicroeditionrms
Осуществляет хранение, удаление, добавление записей в системную память устройства.
Справочник по Java Micro Edition
В этом приложении
В этом приложении содержится исчерпывающий справочный материал по всем пакетам, интерфейсам, классам, конструкторам классов и константам платформы Java 2 Micro Edition. Справочник выполнен на основе имеющейся документации к платформе Java 2 ME, находящейся на сайте компании Sun Microsystems, по адресу в Интернет: http://java.sun.com. Аналогичная документация также поставляется с платформой Java 2 ME, которую вы найдете на компакт-диске, приложенном к книге, в составе среды программирования SUN ONE Studio.4 Mobile Edition и J2ME Wireless Toolkit 2.1. Справочник рассматривает все пакеты, имеющиеся в составе платформы Java 2 ME. Каждый пакет содержит множество интерфейсов, классов, конструкторов и констант. Для всех имеющихся компонентов каждого пакета дается краткая характеристика, на основании которой вам будет очень легко сориентироваться в создании приложений для платформы Java 2 Micro Edition.
Бизнес: Предпринимательство - Малый бизнес - Управление
- Бизнес
- Разновидности бизнеса
- Планирование бизнеса
- Управление бизнесом
- Предпринимательство
- Русское предпринимательство
- Управление и предпринимательство
- Малый бизнес
- Виды малого бизнеса
- Русский малый бизнес
- Управление малым бизнесом
- Posix для малого бизнеса
- Телефония как малый бизнес
- Телефония на Java для малого бизнеса