close

Вход

Забыли?

вход по аккаунту

?

markovskij1

код для вставкиСкачать
Министерство образования и науки Российской Федерации
Государственное образовательное учреждение
высшего профессионального образования
Санкт-Петербургский государственный университет
аэрокосмического приборостроения
С. Г. Марковский, Н. В. Марковская
ПРОГРАММИРОВАНИЕ ПРИЛОЖЕНИЙ
ДЛЯ МОБИЛЬНЫХ УСТРОЙСТВ
Лабораторный практикум
Санкт-Петербург
2011
УДК 621.395.7
ББК 32.882
М27
Рецензенты:
кафедра безопасности информационных систем ГУАП;
доцент кафедры вычислительных систем и сетей ГУАП В. П. Попо
Утверждено
редакционно-издательским советом университета
в качестве лабораторного практикума
Марковский, С. Г.
М27 Программирование приложений для мобильных устройств: лабораторный практикум / С. Г. Марковский, Н. В. Марковская. – СПб.:
ГУАП, 2011. – 112 с.: ил.
Приведены теоретические и методические указания к выполнению лабораторных работ по дисциплине «Программирование приложений для мобильных устройств». Лабораторный практикум
предназначен для магистров, обучающихся по магистерской образовательной программе 230211 «Мультимедиатехнологии».
УДК 621.395.7
ББК 32.882
© Санкт-Петербургский государственный
университет аэрокосмического
приборостроения (ГУАП), 2011
© С. Г. Марковский,
Н. В. Марковская, 2011
ПРЕДИСЛОВИЕ
Лабораторный практикум по дисциплине «Программирование
приложений для мобильных устройств» включает в себя методические указания к четырем лабораторным работам, посвященным разработке мобильных приложений на платформе Java Micro
Edition (Java ME), изучению классов пользовательского интерфейса и работе с изображениями. Целью лабораторного практикума
является обучение магистров процессу создания мобильных приложений (мидлетов) на платформе Java ME и закрепление навыков
программирования на языке высокого уровня Java, приобретенных
при изучении других дисциплин.
Практикум содержит большое число примеров мидлетов для
мобильных устройств. Предполагается, что, разработанные магистрами мидлеты должны работать не только на программных эмуляторах, но и на реальных мобильных телефонах, большинство из
которых имеют виртуальную машину Java и поддержку платформы Java ME. Магистры знакомятся и осваивают методы интерфейсов и классов, содержащихся в пакетах javax.microedition.midlet
и javax.microedition.lcdui профиля MIDP 2.0 платформы Java ME
[1].
Выполнение лабораторных работ, а также приведенные примеры программ рассчитаны на использование среды программирования Java ME SDK 3.0. Можно также использовать среду программирования NetBeans 6.9.1 [2].
По лабораторным работам № 1, 3 и 4 имеются дополнительные
задания, помеченные в тексте лабораторного практикума символом
«*». Выполнение этих заданий позволяет получить максимальный
рейтинг за лабораторную работу при использовании модульнорейтинговой системы оценки знаний студентов.
3
Лабораторная работа № 1
Разработка мобильного приложения
на платформе Java ME
Цель работы: знакомство с платформой Java ME, средой разработки NetBeans, инструментарием Java ME SDK 3.0, изучение
структуры и жизненного цикла мидлета, написание простейшего
мидлета с использованием текстового контейнера TextBox.
1.1. Методические указания
Платформа Java ME
На сегодняшний день американская компания Sun Microsystems,
входящая в состав компании Oracle Corporation, имеет три платформы, предназначенные для разработки разнообразных программных продуктов:
• Java Enterprise Edition для создания серверных приложений;
• Java Standard Edition для написания простых компьютерных
приложений;
• Java Micro Edition для работы с портативными устройствами.
Так как ресурсы портативных устройств сильно ограничены,
то в связи с этим Java ME предъявляет определенные требования
к виртуальной Java-машине, свойствам языка Java и библиотекам
Java API. Для мобильных устройств, таких как мобильные телефоны, платформа Java ME задает конфигурацию CLDC (Connected
Limited Device Configuration – конфигурация для подключенных
ограниченных устройств) и профиль MIDP (Mobile Information
Device Profile – информационный профиль мобильных устройств).
Конфигурация CLDC содержит ряд классов, интерфейсов и методов платформы Java SE, но в урезанном виде. Виртуальная машина, используемая в конфигурации CLDC, находится в мобильном телефоне и носит название KVM (Kilobyte Virtual Machine), что
подчеркивает ее компактность. В настоящее время используются
две версии конфигурации CLDC – 1.0 и 1.1. Версия 1.1 построена на
базе версии 1.0 и имеет больше возможностей.
Профиль MIDP предъявляет требования к аппаратной части мобильного устройства и имеет в своем составе определенный набор
API. На сегодняшний день используется профиль MIDP 2.0.
4
Библиотека, доступная для профиля MIDP 2.0 и конфигурации
CLDC 1.1, состоит из 11 пакетов. При этом пакеты java.lang, java.
util и java.io взяты из Java SE в урезанном виде и определены в
конфигурации CLDC 1.1. Пакеты javax.microedition.midlet, javax.
microedition.io, javax.microedition.rms, javax.microedition.midlet.
lcdui, javax.microedition.midlet.lcdui.game, javax.microedition.pki,
javax.microedition.media и javax.microedition.media.control написаны специально для профиля MIDP 2.0 [1].
Программные продукты
для разработки Java-приложений
Для создания приложений на языке Java необходимо, прежде
всего, установить на компьютер JDK (Java Development Kit). Последние версии JDK можно найти на сайте фирмы Sun Microsystems
разработчика языка Java. Например, jdk-6u23-windows-i586-p.
exe. Этот комплект содержит виртуальную Java-машину, компилятор и другие полезные для работы с Java-компонентами утилиты.
После установки JDK необходимо установить инструментарии
для работы с платформой Java ME. До недавнего времени использовался инструментарий Java ME Wireless Toolkit версии 2.5.2. Существенным недостатком данного инструментария можно назвать
отсутствие текстового редактора. Поэтому исходные коды программ приходилось создавать при помощи других текстовых редакторов. Тем не менее для начального программирования на платформе Java ME этот инструментарий вполне можно использовать.
Его дистрибутив можно найти на сайте www.java.sun.com. Последняя разработка фирмы Sun Microsystems Micro Edition SDK 3.0 –
дальнейшее развитие Java ME Wireless Toolkit 2.5.2. Этот инструментарий представляет собой интегрированную среду разработки,
включает текстовый редактор и имеет возможность выполнения
мобильных приложений в режиме отладчика. Для установки данного продукта необходимо загрузить файл sun_java_me_sdk-3_0win.exe с сайта www.java.sun.com. Иногда может потребоваться не
только создание мобильных приложений на платформе Java ME,
но и разработка Java-приложений на платформах Java SE и Java
EE, аплетов, сервлетов, приложений с использованием других языков программирования. Для этого фирмой Sun Microsystems была
разработана интегрированная среда разработки NetBeans. На сайте
фирмы можно найти бесплатную версию этого продукта, например
5
загрузить файл netbeans-6.9.1-ml-windows.exe, соответствующий
последней версии NetBeans версии 6.9.1 [2].
Разработка мидлета в среде Java ME SDK 3.0
После запуска Java ME SDK 3.0 на экране монитора откроется
рабочее окно, изображенное на рис. 1.1. Чтобы создать новый проект, выберите в меню команду File => New Project. Откроется диалоговое окно New Project (рис. 1.2).
В этом окне в списке Projects появятся все возможные шаблоны проектов. При выборе конкретного шаблона проекта в поле
Description будет находиться его описание. Интерес представляют
два шаблона. При выборе MIDP Application будет создано простое
мобильное приложение с одним основным классом мидлета. Выбор
Import Wireless Toolkit Project импортирует любой проект, ранее
созданный при помощи инструментария Wireless Toolkit 2.5.2.
Нажимаем кнопку Next. Далее в новом окне Name and Location
(рис. 1.3) необходимо определить имя нового проекта и место его
хранения. Назовем новый проект FirstApp и разместим его на диске H в папке JavaMESDKProjects. По умолчанию проект будет расположен в папке C:\Documents and Settings\User\My Documents\
JavaMESDKProjects.
Рис. 1.1. Рабочее окно Java ME SDK 3.0
6
Рис. 1.2. Создание нового проекта
Рис. 1.3. Выбор места хранения проекта
7
Рис. 1.4. Выбор конфигурации и профиля проекта
Дополнительно можно указать Set As Main Project (установить
проект как главный). Тогда при наличии нескольких проектов команды построения и выполнения будут применены непосредственно к этому проекту. Сделать выбор проекта в качестве главного
можно и после его создания. Выбор Create Hello MIDlet создает
Hello MIDlet, файл HelloMIDlet.java. При выполнении этого мидлета на экране мобильного устройства появится сообщение «Hello,
world!» Нажимаем кнопку Next.
Последнее диалоговое окно Default Platform Selection (рис. 1.4)
позволяет выбрать конфигурацию и профиль создаваемого проекта.
Платформа CLDC уже выбрана. Выбор устройства связан с выбором
профиля. Следует отметить, что профиль MIDP 2.1 реализован не
во всех современных мобильных телефонах. Для примера выберем
профиль MIDP 2.0.
Нажатие клавиши Finish завершает процесс создания проекта.
В правой части рабочего окна SDK 3.0 (рис. 1.5) Project появляется название проекта FirstApp. Щелкнув правой кнопкой мыши
на имени проекта и выполнив New->MIDlet…, открываем окно
Name&Location (рис. 1.6). В этом окне вводим имя мидлета, например, назовем мидлет FirstMIDlet и нажимаем Finish. В папке
JavaMESDKProjects:\FirstApp\src\ пояляется файл FirstMIDlet.
java. На рис. 1.7 в рабочем окне SDK 3.0 можно отобразить содержимое файла FirstMIDlet.java.
8
Рис. 1.5. Рабочее окно SDK 3.0
Рис. 1.6. Выбор имени мидлета
Мидлет – это программа, написанная для мобильного телефона с использованием платформы Java ME. Для создания мидлета используется основной класс мидлета, в нашем примере
9
Рис. 1.7. Окно FirstMIDlet.java
FirstMIDlet, который наследуется от абстрактного класса javax.
microedition.midlet.MIDlet и реализует методы startApp(), pauseApp()
и DestroyApp(boolean).
Класс FirstMIDlet является основным классом приложения. По
этой причине он должен быть объявлен открытым (public). Этот
класс может иметь также открытый конструктор без аргументов,
который в тексте нашего мидлета отсутствует. Тогда при построении компилятор сам добавит этот конструктор.
Мидлеты запускаются под контролем виртуальной машины
Java. Управление мобильными приложениями контролируется программами управления приложениями AMS (Application
Management Software), которые находятся на мобильном устройстве. При загрузке приложения в телефон выполняется следующая
последовательность действий [3]:
1. AMS запускает приложение, создает экземпляр класса
FirstMIDlet, используя конструктор без аргументов, определенный
в базовом классе.
2. Приложение переходит в состояние paused (рис. 1.8). AMS
вызывает метод startApp, который является точкой входа в программу.
10
new()
startApp()
Paused
pauseApp()
destroyApp()
Active
destroyApp()
Destroyed
Рис. 1.8. «Жизненный цикл» мидлета
В языке Java все приложения имели метод main(). Такой метод
существует. Это часть реализации MIDP, а не приложения. Его вызывает программное обеспечение AMS, но мы это не видим.
3. После вызова startApp() мидлет переходит в состояние active.
Приложение захватывает все необходимые ресурсы.
4. Приложение выполняется, пока система не перейдет или в
состояние Paused, или в состояние Destroyed. Paused – состояние,
в котором выполнение мидлета приостанавливается. Выполнение
приложения может быть возобновлено AMS при помощи метода
startApp() или полностью завершено методом destroyApp(boolean).
Destroyed – прерванное состояние. Приложение остановлено и уже
не может перейти в другие состояния. Все используемые ресурсы
освобождаются.
Состояния Active, Paused и Destroyed образуют «жизненный
цикл» мидлета (см. рис. 1.8).
Отметим, что FirstMIDlet является очень простым и его выполнение не отображает никакой информации на экране мобильного
телефона. Немного усложним мидлет, добавив операторы и выделив его жирным начертанием:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
* @author Stanislav
*/
public class FirstMIDlet extends MIDlet {
private Form f;
private DateField df;
private Display d;
11
}
public void startApp() {
f = new Form(«First MIDlet»);
df = new DateField(«Time», DateField.TIME);
f.append(df);
d = Display.getDisplay(this);
d.setCurrent(f);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
Для получения доступа к экрану необходимо импортировать пакет javax.microedition.lcdui, который содержит классы для реализации интерфейса пользователя, в том числе класс Display и класс
Form. Объект класса Display создается автоматически реализацией
MIDP при запуске мидлета. Пользователь не может сам создать такой объект, но может получить ссылку на него с помощью метода
getDisplay(MIDlet). В качестве аргумента используется ссылка на
текущий мидлет. Ссылка на текущий объект в языке Java обозначается ключевым словом this.
Для вывода объекта на экран используется метод
setCurrent(Displayable). Класс Displayable – абстрактный класс, который содержит иерархию классов пользовательского интерфейса,
отображаемых на экране. Изучению классов пользовательского
интерфейса посвящены лабораторные работы № 2 и 3 настоящего
практикума. Одним из таких классов является класс Form. Это некоторый контейнер, который может содержать различные визуальные элементы. В данном примере в форму помещается объект
класса DateField. Класс DateField можно использовать для установки необходимой даты и времени. В мидлете FirstApp он используется для установки времени.
Компиляция и запуск проекта
Для компиляции и компоновки проекта необходимо в рабочем
окне SDK 3.0 выполнить Run->Build или нажать горячую клавишу F11. После успешного построения в окне вывода должно
появиться сообщение: «BUILD SUCCESSFUL». При этом в папке JavaMESDKProjects:\FirstApp\build\compiled появится файл
FirstMIDlet.class, а в папке JavaMESDKProjects:\FirstApp\dist
файлы FirstApp.jad и FirstApp.jar. После построения можно запу12
Рис. 1.9. Результат выполнения мидлета FirstApp
стить проект из меню Run->Run или нажать горячую клавишу F6.
При этом на экране мобильного телефона отобразится строка текущего времени (рис. 1.9). Используя клавишу «Enter», можно перейти в режим установки времени и выставить правильное время.
Разработка мидлета в среде NetBeans 6.9.1
После запуска NetBeans 6.9.1 на экране монитора откроется рабочее окно. Чтобы создать новый проект, выберите в меню команду File => New Project. Откроется диалоговое окно New Project
(рис. 1.10). Чтобы создать новый проект мобильного приложения
необходимо в списке Categories выбрать категорию Java ME, а в
списке Projects выбрать или шаблон Mobile Application, или шаблон Import Wireless Toolkit Project. Дальнейший процесс по созданию проекта в среде NetBeans 6.9.1 полностью повторяет ранее
описанный процесс для среды Java ME SDK 3.0.
1.2. Задание к лабораторной работе
1. Разработать Java-приложение, реализующее механизм наследования согласно рис. 1.11. Класс A – суперкласс. Класс B является
13
Рис. 1.10. Создание нового проекта в среде NetBeans
подклассом класса A, в свою очередь класс C является подклассом
класса B. Все члены класса A должны быть открытыми. Подклассы
B и C должны содержать собственные закрытые переменные – члены класса, для доступа к которым из других классов программы
классы B и C должны иметь соответствующие методы. Для демонстрации работы приложения необходимо разработать специальный
класс Demo, содержащий метод main. Метод main должен создавать
Class A
Class B
Class C
Рис. 1.11. Диаграмма взаимодействия классов
14
объекты классов, вызывать методы классов и выводить всю информацию на экран монитора.
2. Разработать простейший мидлет, выводящий некоторое сообщение на экран мобильного телефона, с использованием текстового
контейнера TextBox.
3. Добавить в мидлет команду завершения «Exit», ннтерфейс
CommandListener и метод CommandAction.
4. Реализовать Java-приложение в виде мидлета, сохранив
структуру взаимодействия и содержимое классов A, B и C. Заменить содержимое класса Demo на класс DemoMIDlet для отображения всей информации на экране мобильного телефона.
5*. Используя возможности класса TextBox добавить возможности ввода произвольных значений переменных класса B с клавиатуры мобильного телефона в класс DemoMIDlet. Класс C исключить
из рассмотрения.
Каждый класс необходимо хранить в отдельном файле с расширением .java.
1.3. Пример выполнения задания
В качестве примера создадим Java-приложение Memory для
работы полупроводниковыми запоминающими устройствами
(рис. 1.12). Штрих-пунктирной линией отмечено возможное наследование классов, не реализованное в рассматриваемом приложении.
Суперкласс Memory – это класс полупроводниковых запоминающих устройств (листинг 1.1).
Class Memory
Class ROM
Class RAM
Class PROM
Class DDRRAM
Рис. 1.12. Диаграмма взаимодействия классов Java-приложения Memory
15
Листинг 1.1. Класс Memory.
public class Memory {
byte []M;
void ClearMemory(int size)
{
int i;
for( i = 0; i < size; i++ )
M[i] = 0;
}
Memory(int size)
{
M = new byte [size];
ClearMemory(size);
}
}
Единственная переменная член суперкласса – байтовый массив
M (накопитель) размера size. Предполагается, что массив имеет
байтовую организацию. Переменная M объявлена с ключевым словом public и, следовательно, является открытым членом класса
и доступна всем другим классам программы. Конструктор класса
инициализирует накопитель и обнуляет его ячейки, используя метод суперкласса ClearMemory().
Подклассом класса Memory является класс RAM (листинг 1.2) –
класс оперативных запоминающих устройств. Класс RAM наследует все свойства суперкласса и имеет собственные переменные:
rw_mode – режим работы (чтение или запись) и ram_data (двунаправленная шина данных) и методы WriteIntoMemory (записать данные
в память по адресу) и ReadFromMemory (прочитать данные из памяти
по адресу). Так как переменные rw_mode и ram_data – закрытые члены класса, то класс имеет дополнительные методы для доступа к
этим переменным из других классов приложения. Методы чтения
и записи при успешном завершении возвращают 0. Если возникает
ошибка (задан неверный режим работы), то данные функции возвращают значение –1. Отметим, что конструктор класса RAM вызывает конструктор суперкласса Memory.
Листинг 1.2. Класс RAM.
public class RAM extends Memory {
private boolean rw_mode; // 0 – read, 1 – write
private byte ram_data;
RAM(int size)
{
16
}
super(size);
rw_mode = false;
ram_data = 0;
int WriteIntoMemory(int addr)
{
int Err;
if( rw_mode )
{
M[addr] = ram_data; Err = 0;
}
else Err = -1;
return Err;
}
int ReadFromMemory(int addr)
{
int Err;
if( rw_mode == false )
{
ram_data = M[addr]; Err = 0;
}
else Err = -1;
return Err;
}
void SetMode( boolean mode ) { rw_mode = mode; }
boolean GetMode() { return rw_mode; }
}
void SetData( byte data ) { ram_data = data; }
byte GetData() { return ram_data; }
Класс DDRAM (листинг 1.3) – подкласс класса RAM. Это класс оперативных запоминающих устройств с возможностью обращения к
двум ячейкам памяти за один такт. Закрытые переменные – члены класса data1 и data2. Класс имеет соответствующие методы
WriteInto2Memory и ReadFrom2Memory, в которых работа происходит с
двумя ячейками памяти одновременно. Они используют соответствующие методы записи и чтения класса RAM.
Дополнительный метод GetData позволяет обратиться к переменным data1 и data2 из других классов программы.
Листинг 1.3. Класс DDRAM.
public class DDRRAM extends RAM {
private int data1, data2;
DDRRAM(int size)
{
17
super(size);
}
int WriteInto2Memory(int addr1, int addr2, byte val1, byte val2)
{
int Err, Err1, Err2;
SetData(val1);
Err1 = WriteIntoMemory( addr1 );
SetData(val2);
Err2 = WriteIntoMemory( addr2 );
if(( Err1 == 0 ) && (Err2 == 0 ) ) Err = 0;
else Err = -1;
return Err;
}
int ReadFrom2Memory(int addr1, int addr2)
{
int Err;
Err = ReadFromMemory(addr1);
if(Err == 0)
data1 = GetData();
else return -1;
Err = ReadFromMemory(addr2);
if(Err == 0)
data2 = GetData();
else return -1;
return 0;
}
}
int GetData( boolean b )
{
if( b ) return data1;
else return data2;
}
Для работы приложения необходимо создать специальный класс
RunMemory, который будет выполнять роль класса Demo и содержать
метод main, в котором будет происходить создание объектов рассмотренных выше классов и вызов необходимых методов этих классов.
Класс RunMemory представлен в листинге 1.4.
Листинг 1.4. Класс RunMemory.
public class RunMemory{
public static void main(String[] args) {
int i;
int size = 10;
int Err;
RAM m1 = new RAM(size);
DDRRAM m2 = new DDRRAM(size);
18
m1.SetMode(true);
m1.SetData((byte)0xFD);
Err = m1.WriteIntoMemory(3);
if( Err == -1 ) System.out.println(«Error»);
m1.SetData((byte)0x03);
Err = m1.WriteIntoMemory(4);
if( Err == -1 ) System.out.println(«Error»);
m2.SetMode(true);
Err = m2.WriteInto2Memory(3, 4, (byte)0xFF, (byte)0x1);
if( Err == -1 ) System.out.println(«Error»);
m1.SetMode(false);
System.out.println(«********* RAM *********»);
for( i = 0; i < size; i++ )
{
Err = m1.ReadFromMemory(i);
if( Err == -1 )
{
System.out.println(«Error»); break;
}
System.out.print( «[«+i+»] = « + m1.GetData() + « « );}
System.out.println( « « );
m2.SetMode(false);
System.out.println(«******** DDRRAM ********»);
for( i = 0; i < size; i++ )
{
Err = m2.ReadFromMemory(i);
if( Err == -1 )
{
System.out.println(«Error»); break;
}
System.out.print( «[«+i+»] = « + m2.GetData() + « « );}
System.out.println( « « );
}
}
m2.ReadFrom2Memory(3, 4);
if( Err == -1 )
System.out.println(«Error»);
else
System.out.println( « m2[3]= « + m2.GetData(false) +
« m2[4]= « + m2.GetData(true));
Рассмотрим подробно работу этого класса. Сначала создаются
объекты: m1 класса RAM и m2 класса DDRAM. Емкость обоих запоминающих устройств – 10 байт. Далее, для памяти RAM устанавливается режим «запись», на шину данных выставляется значение (–3) и
производится запись этого значения в память по адресу 3. Аналогично по адресу 4 в память заносится значение 3. Если при записи
19
возникает ошибка, то выводится соответствующее сообщение. Для
памяти DDRAM устанавливается режим «запись» и производится
запись в ячейки памяти DDRAM с адресами 3 и 4 значений 1 и (–1)
соответственно.
Далее, выставляется режим «чтение» и в цикле читается содержимое памяти RAM и отображается на экране. Аналогично,
на экране отображается содержимое памяти DDRAM. При этом
объект m2 использует метод ReadFromMemory, наследованный от класса RAM. В конце листинга объект m2 использует собственный метод
ReadFromMemory и выводит на экран содержимое ячеек памяти с адресами 3 и 4.
Ниже приведены результаты работы Java-приложения.
********* RAM *********
[0] = 0 [1] = 0 [2] = 0 [3] = –3 [4] = 3 [5] = 0 [6] = 0 [7] = 0 [8] = 0 [9] = 0
******** DDRRAM ********
[0] = 0 [1] = 0 [2] = 0 [3] = –1 [4] = 1 [5] = 0 [6] = 0 [7] = 0 [8] = 0 [9] = 0
m2[3] = 1 m2[4] = –1
Теперь рассмотрим реализацию Java-приложения в виде мидлета. При этом содержимое классов Memory, RAM и DDRAM не изменяется.
Единственное, что надо сделать, это написать класс мидлета, который мы назовем MemoryMIDlet (листинг 1.5). Этот класс будет выполнять роль класса DemoMIDlet.
Листинг 1.5. Класс MemoryMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MemoryMIDlet extends MIDlet
{
private TextBox t;
private Display d;
public MemoryMIDlet()
{
super();
}
public void startApp()
{
int i;
int size = 10;
int Err;
RAM m1 = new RAM(size);
DDRRAM m2 = new DDRRAM(size);
20
Byte ii;
t = new TextBox( «memory», null, 256, 0 );
d = Display.getDisplay( this );
m1.SetMode(true);
m1.SetData((byte)0xFD);
Err = m1.WriteIntoMemory(3);
if( Err == -1 ) t.insert( «Error!!!», 10 );
m1.SetData((byte)0x03);
Err = m1.WriteIntoMemory(4);
if( Err == -1 ) t.insert( «Error!!!», 10 );
m2.SetMode(true);
Err = m2.WriteInto2Memory(3, 4, (byte)0xFF, (byte)0x1);
if( Err == -1 ) t.insert( «Error!!!», 10 );
m1.SetMode(false);
t.setString( «*********
RAM
*********\n» );
for( i = 0; i < size; i++ )
{
Err = m1.ReadFromMemory(i);
if( Err == -1 )
{
t.insert( «Error!!!», 10 ); break;
}
ii = new Byte(m1.GetData());
t.insert( ii.toString() + «\n», t.getCaretPosition() );
}
m2.SetMode(false);
t.insert( «********* DDRRAM
********\n «,
t.getCaretPosition() );
for( i = 0; i < size; i++ )
{
Err = m2.ReadFromMemory(i);
if( Err == -1 )
{
t.insert( «Error!!!», 10 ); break;
}
ii = new Byte(m2.GetData());
t.insert( ii.toString() + « «, t.getCaretPosition() );
}
m2.ReadFrom2Memory(3, 4);
if( Err == -1 )
t.insert( «Error!!!», 10 );
else
{
t.insert( «\n m2[3] = « +
String.valueOf(m2.GetData(false)), t.getCaretPosition() );
21
t.insert( «\n m2[4] = « +
String.valueOf(m2.GetData(true)), t.getCaretPosition() );
}
}
}
d.setCurrent( t );
public void pauseApp() { }
public void destroyApp(boolean destroy)
{
notifyDestroyed();
}
Результаты выполнения мидлета отображаются на экране мобильного телефона (рис. 1.13).
Преобразуем мидлет для реализации пункта 5 задания. Изменения затронут класс MemoryMIDlet. Раньше мы задавали конкретные
значения в программе, которые при выполнении программы на мобильном телефоне изменять не могли. Например, в ячейку памяти
RAM с адресом 3 мы записывали число (–3), а в ячейку с адресом 4 –
число 3. Чтобы записать другие значения, необходимо: исправить
текст программы, перестроить программу и запустить ее на телефоне. Теперь мы должны изменить мидлет так, чтобы в процессе выполнения программы иметь возможность с клавиатуры мобильного
устройства вводить адрес ячейки и число, которое мы хотим в нее записать. Согласно заданию класс DDRRAM исключим из рассмотрения.
Чтобы выполнить это задание, надо иметь три объекта TextBox.
Первый, как и ранее для отображения информации, второй – для
ввода адреса ячейки с клавиатуры, третий – для ввода числа, запи-
Рис. 1.13. Результаты работы мидлета MemoryMIDlet
22
ЭКРАН A
Add
ЭКРАН B
Next
ЭКРАН C
Next
Рис. 1.14. Схема переключения между экранами
сываемого в ячейку. Каждый объект TextBox должен отображаться
на отдельном экране, поэтому необходимо предусмотреть схему переключения между экранами, или, по-другому, навигацию между
экранами. Схема подобного переключения показана на рис. 1.14.
Кроме того, необходимо предусмотреть команды, реализующие
переходы между экранами. При запуске мидлета отображается
экран A, отображающий содержимое TextBox вывода памяти RAM.
Все ячейки памяти RAM в данный момент обнулены. К объекту
TextBox экрана A добавляются две команды «Exit» – выход из приложения и «Add» – переход к экрану B (объекту TextBox для ввода
адреса). К объекту TextBox для ввода адреса добавляются команды
«Back» – вернуться к экрану A и «Next» – перейти к экрану C (объекту TextBox для ввода данных). Объект TextBox для ввода данных,
в свою очередь, имеет команды «Back» для возврата к экрану B и
«Next» – для перехода к экрану A и отображения новой информации. Листинг модернизированного класса MemoryMIDlet приведен в
листинге 1.6.
Листинг 1.6. Класс MemoryMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MemoryMIDlet extends MIDlet implements CommandListener
{
private TextBox t, tbAddr, tbValue;
23
private
private
private
private
Display d;
Command exitMIDlet, add, next, back;
RAM m1;
int iAddr, iValue, size;
public MemoryMIDlet() { super(); }
public void startApp()
{
exitMIDlet
add
back
next
= new Command( «Exit», Command.EXIT, 0 );
= new Command( «Add»,
Command.OK, 1 );
= new Command( «Back», Command.BACK, 1 );
= new Command( «Next», Command.OK, 1 );
t = new TextBox( «memory», null, 256, 0 );
t.addCommand( exitMIDlet );
t.addCommand( add );
t.setCommandListener( this );
tbAddr = new TextBox( «Address», ««, 2, TextField.NUMERIC );
tbAddr.addCommand( next );
tbAddr.addCommand( back );
tbAddr.setCommandListener( this );
tbValue = new TextBox( «Value», ««, 4, TextField.NUMERIC );
tbValue.addCommand( next );
tbValue.addCommand( back );
tbValue.setCommandListener( this );
size = 10;
m1 = new RAM(size);
ReadMemory( 0, 0 );
}
d = Display.getDisplay( this );
d.setCurrent( t );
private void ReadMemory( int addr, int value )
{
int i, Err;
Byte ii;
m1.SetMode(true);
m1.SetData((byte)value);
Err = m1.WriteIntoMemory(addr);
if( Err == -1 ) t.insert( «Error!!!», 10 );
m1.SetMode(false);
t.setString( «***********
RAM
***********\n» );
for( i = 0; i < size; i++ )
{
Err = m1.ReadFromMemory(i);
24
}
}
if( Err == -1 )
{
t.insert( «Error!!!», 10 ); break;
}
ii = new Byte(m1.GetData());
t.insert( ii.toString() + «\n», t.getCaretPosition() );
public void pauseApp() { }
public void destroyApp(boolean destroy)
{ }
public void commandAction( Command c, Displayable s )
{
if( c == exitMIDlet )
{
destroyApp( false );
notifyDestroyed();
}
if( c == add ) d.setCurrent( tbAddr );
if( c == back )
{
if( s == tbAddr ) d.setCurrent( t );
if( s == tbValue ) d.setCurrent( tbAddr );
}
if( c == next )
{
if( s == tbAddr )
{
iAddr = Integer.parseInt( tbAddr.getString() );
if( ( iAddr > ( size – 1 ) ) || ( iAddr < 0 ) )
{
Alert al = new Alert( «Error», «Illegal address», null,
AlertType.ERROR );
al.setTimeout( 2000 );
d.setCurrent( al );
}
else d.setCurrent( tbValue );
}
if( s == tbValue )
{
iValue = Integer.parseInt( tbValue.getString() );
if( ( iValue > 127 ) || ( iValue < -128 ) )
{
Alert al = new Alert( «Error», «Illegal value», null,
AlertType.ERROR );
al.setTimeout( 2000 );
d.setCurrent( al );
}
25
else
{
}
}
}
}
}
ReadMemory( iAddr, iValue );
d.setCurrent( t );
Дадим некоторые комментарии к вышеприведенной программе.
Подробно этот материал будет рассмотрен в методических указаниях к лабораторной работе № 2. Строка объявления класса мидлета
теперь выглядит следующим образом:
public class MemoryMIDlet extends MIDlet implements CommandListener.
Это означает, чтобы объекты программы могли реагировать на события, задаваемые командами, в программе должен быть реализован интерфейс CommandListener. Он имеет единственный метод
CommandAction(Command, Displayable), который реализует обработку
команд пользователя. При обсуждении навигации между экранами в программе мы рассмотрели команды, которые необходимо
добавить в программу. Команды создаются в методе startApp() при
помощи конструктора: Command(String label, int CommandType, int
priority), где:
• label – название команды для ее отображения на экране;
• commandType – тип команды;
• priority – приоритет команды.
Далее в методе startApp() создаются три объекта TextBox.
К каждому объекту TextBox добавляют команды, используя
метод addCommand(Command) класса Displayable. Вызов метода
setCommandListener(this) позволяет связать объект TextBox с блоком
прослушивания команд, который реализован в основном классе
мидлета. Метод ReadMemory( int addr, int value ) записывает новое
значение value по адресу, после чего отображает все содержимое
памяти RAM.
Метод соmmandAction – блок прослушивания команд, который
реализует действия в зависимости от поданной пользователем команды и объекта, отображаемого на экране. Следует отметить, что
адрес может изменяться в данной задаче от 0 до 9, а данные в формате байта от –128 до 127. При вводе выполняется проверка на корректность введенных значений. В случае ошибки сообщение выводится на экран мобильного телефона с использованием объекта
класса Alert и пользователю предлагается повторить ввод.
26
И последнее, строка iAddr = Integer.parseInt( tbAddr.getString()).
Метод getString() преобразует содержимое TextBox в строку, а метод
parseInt(String) преобразует строку к типу int.
1.4. Содержание отчета
1. Титульный лист.
2. Цель работы.
3. Задание к лабораторной работе.
4. Диаграмма взаимодействия классов Java-приложения, описание членов переменных и методов для каждого класса.
5. Листинги классов Java-приложения.
6. Результаты работы Java-приложения на экране монитора.
7. Листинг простого мидлета, выводящего сообщение на экран
мобильного телефона.
8. Листинг мидлета, реализующего Java-приложение на платформе Java ME.
9. Результаты работы мидлета на экране мобильного телефона.
10*. Схема переключения между экранами для мидлета, реализующего пятый пункт задания.
11*. Листинг мидлета, реализующего пятый пункт задания.
12. Выводы по лабораторной работе.
27
Лабораторная работа № 2
Высокоуровневый программный интерфейс в Java ME
Цель работы: изучение классов высокоуровневого пользовательского интерфейса UI (user interface) пакета javax.microedition.
lcdui платформы Java ME, обработка событий, разработка мидлета, использующего элементы высокоуровневого пользовательского
интерфейса.
2.1. Методические указания
В программах Java ME схема поэкранного отображения информации, исключающая одновременное наличие нескольких окон на
дисплее, является основной. Это связано с ограничением мобильных телефонов в системных ресурсах. Поэтому задачей пользователя является разработка интуитивно понятной структуры приложения, использующей простую экранную навигацию.
Каждый мобильный телефон имеет свой дисплей, но функция
у всех одна – отображение информации. Для работы с дисплеем в
платформе Java ME предусмотрены два класса.
Первый из них – класс Display. Объект этого класса соответствует дисплею телефона. Каждый мидлет может иметь только один
объект класса Display, так как у телефона только один дисплей.
Второй класс – Displayable. Этот класс отвечает за содержимое
дисплея. Объекты класса Displayable – это объекты, с помощью которых программа взаимодействует с пользователем. Объект класса
Displayable можно представить в виде чистого листа, на который
можно нанести, что угодно. Программа может содержать любое количество объектов класса Displayable, но отображаться на экране в
любой момент времени может только один.
Структура пользовательского интерфейса пакета javax.
microedition.lcdui приведена на рис. 2.1.
Классы пользовательского интерфейса разделяются на высокоуровневый класс, назначенный классу Screen и всей его дальнейшей
иерархии наследования, и низкоуровневый класс Canvas. Оба класса создают структуру интерфейсов, разделенную на высокоуровневый и низкоуровневый пользовательский интерфейсы.
Высокоуровневый интерфейс содержит классы, которые позволяют организовать жестко заданную модель отображения пользо28
Displayable
Screen
Alert
List
Canvas
Form
TextBox
GameCanvas
Рис. 2.1. Структура пользовательского интерфейса
вательского интерфейса на экране телефона, с помощью которых
программист организует меню, текстовые контейнеры, навигацию
и т. д.
Низкоуровневый интерфейс предоставляет графические средства для рисования на экране различных графических элементов
и обработку команд, посылаемых непосредственно с клавиш телефона.
Такое разделение классов существует в сугубо теоретическом
виде, и ничто не мешает комбинировать элементы обоих интерфейсов в одной программе. В данной лабораторной работе изучаются
только элементы высокоуровневого интерфейса. Классы низкоуровневого интерфейса будут рассмотрены в лабораторной работе
№ 3.
Высокоуровневый интерфейс включает в себя 4 класса:
• List – класс для работы со списками;
• Alert – класс для создания уведомлений пользователей о внезапно возникших ошибках или исключениях или небольших информативных сообщений;
• TextBox – массив данных, содержащий текстовую информацию,
с возможностью ее редакции;
• Form – экранный контейнер, в котором можно разместить различные элементы интерфейса с помощью дополнительных подклассов класса Item.
Все объекты иерархии класса Screen обладают необязательным
заголовком и бегущей строкой. При создании объекта высокоуровневого API можно указать его заголовок, а можно оставить заголовок пустым, указав в качестве параметра null. В процессе работы с
объектом можно получить его заголовок с помощью метода String
getTitle() и установить новый заголовок, используя метод void
setTitle(String s).
29
Бегущая строка перемещается справа налево с одинаковой скоростью. При достижении конца текста бегущая строка высвечивается снова, обеспечивая тем самым цикличность перемещения текста.
Бегущая строка представляется объектом класса Ticker. Класс
имеет единственный конструктор public Ticker(String str), где
str – бегущая строка. Для размещения бегущей строки на экране
используется метод void setTicker(Ticker ticker) класса Displayable.
Получить ссылку на объект класса Ticker позволяет метод Ticker
getTicker(). Методы класса Ticker для редактирования бегущей
строки:
• void setString(String str) – устанавливает текст бегущей строки;
• String getString() – получает текст бегущей строки.
Класс List
Класс List предназначен для организации меню (списка) с возможностью перемещения по пунктам меню и выбора одного из пунктов. Класс List имеет два конструктора:
• List(String title, int listType);
• List(String title, int listType,
• String[] stringElements, Image[] imageElements).
Первый конструктор создает пустой список, в который можно в дальнейшем добавить необходимые элементы, второй получает элементы списка из массива stringElements. Длина массива stringElements определяет количество элементов в списке.
С каждым элементом списка можно связать изображение из массива imageElements. Число элементов в массивах imageElements и
stringElements должно быть одинаково. Если пользователь не хочет
использовать изображения для элементов массива, то в качестве
параметра imageElements следует указать значение null.
Параметр title задает заголовок списка, а listType задает один
из трех возможных типов списка, определяемых константами
класса List (табл. 2.1).
Если список имеет тип IMPLICIT, то перемещение по пунктам
меню вызывает немедленное оповещение через блок прослушивания команд. При выборе элемента списка формируется команда
SELECT_COMMAND класса List, которая передается в метод commandAction
(Command,Displayable) обработчика команд. Другие типы списков не
генерируют оповещений.
30
Таблица 2.1
Типы списков
Константа
Описание
EXCLUSIVE G Позволяет выбирать только один из элементов списка
MULTIPLE Позволяет выбирать любое количество элементов в списке
IMPLICIT ПП Позволяет выбирать только один из элементов списка,
на котором сфокусировал свое внимание пользователь
Перечислим основные методы класса List:
• int append(String stringPart, Image imagePart) – добавляет новый элемент, представленный строкой stringPart и изображением
imagePart в конец списка и возвращает присвоенный элементу индекс;
• void insert(int elementNum, String stringPart, Image imagePart) –
вставляет новый элемент в позиции списка, заданную индексом
elementNum;
• void set(int elementNum, String stringPart, Image imagePart) –
изменяет элемент списка с индексом elementNum в соответствии с параметрами stringPart и imagePart;
• void delete(int elementNum) – удаление элемента списка с индексом elementNum;
• void deleteAll() – удаление всех элементов;
• int size() – возвращает количество элементов в списке;
• void setTitle(String s) – добавляет название в список элементов;
• String getString(int elementNum) – получает строку текста для
выбранного элемента из списка;
• boolean isSelected(int elementNum) – возвращает значение true,
если элемент списка elementNum является выделенным;
• int getSelectedIndex() – получает индекс выбранного элемента
списка (если тип списка MULTIPLE, то возвращается значение –1);
• void setSelectedIndex(int elementNum, boolean selected) – для
типа списка MULTIPLE устанавливает элемент списка с индексом
elementNum в состояние, соответствующее параметру selected. Для
остальных типов списков параметр selected должен иметь значение
true, при этом соответствующий пункт меню переходит в выделенное состояние. Элемент, бывший до этого в выделенном состоянии,
переходит в невыделенное состояние;
31
• int getSelectedFlags(boolean[] selectedArray_return) – в параметр selectedArray_return возвращается массив флагов, соответствующих элементам списка. Элемент массива содержит значение true,
если соответствующий элемент списка является выделенным. Для
списка типа MULTIPLE значение true может содержать произвольное
число элементов массива, для других типов списка – только один
элемент. Метод возвращает количество выделенных элементов;
• void setSelectedFlags(boolean[] selectedArray) – устанавливает
элементы списка в выделенное состояние в соответствии с массивом
флагов selectedArray. Для списков типа EXCLUSIVE и IMPLICIT только
один элемент массива selectedArray должен иметь значение true.
Полный список методов можно посмотреть в [1].
В листинге 2.1 представлен код мидлета, создающего список
классов высокоуровневого пользовательского интерфейса. В программе используется первый тип конструктора. Элементы добавляются в список при помощи методов append() и insert(). Для
формирования заголовка используется метод setTitle(). Результат
работы программы приведен на рис. 2.2. Для перемещения по элементам списка используются клавиши указатели. Выбор элемента
списка производится нажатием клавиши Select.
Листинг 2.1. Класс ListExclusiveMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ListExclusiveMIDlet extends MIDlet {
private List l;
private Display d;
public ListExclusiveMIDlet()
{
l = new List( null, List.EXCLUSIVE);
l.append( «List», null );
l.append( «Alert», null );
l.append( «Textbox», null );
l.insert( 2, «Form», null );
l.setTitle( «High API classes» );
d = Display.getDisplay(this);
d.setCurrent( l );
}
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean b) {}
}
Модернизируем программу, используя конструктор класса List
c заранее определенным списком элементов и типом списка MULTIPLE.
32
Рис. 2.2. Список типа
EXCLUSIVE
Рис. 2.3. Список типа
MULTIPLE
Используя метод setSelectedFlags(), переведем в выделенное состояние элементы списка «Alert» и «Form», а при помощи метода
setSelectedIndex() выделим элемент «List». Код мидлета приведен
в листинге 2.2. Результат работы мидлета ListMultipleMIDlet приведен на рис. 2.3.
Листинг 2.2. Класс ListMultipleMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ListMultipleMIDlet extends MIDlet {
private String[] str = {«List», «Alert», «Textbox», «Form»};
private boolean[] flags= {false, true, false, true};
private List l;
private Display d;
public ListMultipleMIDlet()
{
l = new List( «High API classes», List.MULTIPLE, str, null);
l.setSelectedFlags(flags);
l.setSelectedIndex(0, true);
d = Display.getDisplay(this);
d.setCurrent( l );
}
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean b) {}
}
В листинге 2.3 представлен пример мидлета, демонстрирующего
использование списка типа IMPLICIT и бегущей строки. При выборе
определенного элемента списка (метод getSelectedIndex()) обработчику команд посылается команда List.SELECT_COMMAND и содержимое строки текста, соответствующее выбранному элементу (метод
getString()), отображается в бегущей строке (метод setString класса
33
Рис. 2.4. Список типа EXCLUSIVE
Ticker) и строке заголовка экрана (метод setTitle класса List). Обработчик команд и обработка событий для высокоуровневого API
будут подробно рассмотрены позднее. Положение бегущей строки
зависит от конкретного эмулятора. Для SDK 3.0 бегущая строка
размещается внизу экрана. Результат работы мидлета приведен на
рис. 2.4.
Листинг 2.3. Класс ListImplicitMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ListImplicitMIDlet extends
CommandListener
{
private List l;
private Ticker t;
private Display d;
public ListImplicitMIDlet()
{
t = new Ticker(««);
l = new List(null, List.IMPLICIT);
l.append(«List», null);
l.append(«Alert», null);
l.append(«Textbox», null);
l.insert(2, «Form», null);
l.setCommandListener(this);
34
MIDlet
implements
}
l.setTicker(t);
d = Display.getDisplay(this);
d.setCurrent(l);
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean b) {}
public void commandAction(Command c, Displayable d)
{
int index;
if(c == List.SELECT_COMMAND)
{
index = l.getSelectedIndex();
l.setTitle(l.getString(index));
t.setString(«Ticker:»+l.getString(index));
}
}
}
Класс Alert
Класс Alert представляет собой сообщение, состоящее из изображения и текста, которое отображается на экране в течение заданного количества времени, после чего автоматически происходит смена экрана. Время демонстрации сообщения может быть бесконечно
большим. Такая ситуация возникает, если сообщение имеет большой размер и для его просмотра пользователю требуется прокрутка
экрана. В этом случае пользователь сам закрывает сообщение.
Класс имеет два конструктора:
• Alert(String title) – создает пустое сообщение с заголовком
title;
• Alert(String title, String alertText, Image alertImage, AlertType
alertType) – создает сообщение с заголовком title, текстом alertText,
изображением alertImage и типом сообщения alertType. Параметр,
задающий тип сообщения, определяется одной из констант класса
alertType (табл. 2.2). Для создания обычного сообщения в качестве
параметра необходимо указать значение null.
Перечислим основные методы класса Alert:
• int getDefaultTimeout() – возвращает время демонстрации сообщения в миллисекундах, устанавливаемое по умолчанию при
создании объекта класса Alert, или константу FOREVER класса Alert,
если сообщение демонстрируется неограниченное количество времени;
35
• int getTimeout() – возвращает время демонстрации данного сообщения в миллисекундах или константу FOREVER;
• int setTimeout(int time) – устанавливает новое время демонстрации сообщения. Время задается аргументом time в миллисекундах или константой FOREVER;
• AlertType getType() – возвращает тип данного сообщения в виде
объекта класса AlertType;
• void setType(AlertType type) – задает новый тип сообщения в
виде объекта класса AlertType;
• void setString(String str) – устанавливает текст str данному
сообщению;
• String getString() – возвращает текст данного сообщения.
Таблица 2.2
Константы класса AlertType
Параметр
ALARM
Описание
Вывод сообщения, привязанного к определенному моменту, например «Тренировка начнется через 10 минут»
CONFIRMATION Подтверждение удачных результатов действий пользователя, например «Сообщение отправлено»
ERROR
Сообщение об ошибке в результате действий пользователя, например «Отсутствует файл»
INFO
Отображение информационного сообщения
WARNING
Предупреждение об опасных действиях пользователя,
например «Контакт будет уничтожен»
Модернизируем код программы листинга 2.1, реализовав метод
startApp(), который выполняется при переходе программы в активное состояние. Для начала объявим объект al класса Alert там же,
где был объявлен объект l класса List: private Alert al.
Листинг 2.4. Метод startApp.
public void startApp()
{
al = new Alert(null,»Loading High Level API classes List...»,
null, AlertType.INFO);
al.setTimeout(4000);
d.setCurrent(al);
}
36
Рис. 2.5. Вывод информационного сообщения
Для создания объекта al используем конструктор с четырьмя
параметрами. Мы не будем использовать заголовок для окна сообщения и собственное изображение для окна сообщения. Поэтому в качестве первого и третьего параметров передаем null. В окно
сообщения будет выводиться текст, говорящий о загрузке списка
классов высокоуровневого API. Тип сообщения определим как
INFO. В программе зададим новое время демонстрации сообщения,
равное 4 секундам. Отобразим сообщение на дисплее, используя
метод setCurrent() (рис. 2.5).
Появление сообщения сопровождается звуковым сигналом.
Каждому типу сообщения соответствует свой звуковой сигнал. Если
в листинге 2.4 заменить al.setTimeout(4000) на al.setTimeout(Alert.
FOREVER), то сообщение будет демонстрироваться неограниченное
время. Пользователь может закрыть экран, воспользовавшись клавишей done.
Класс AlertType
Класс AlertType определяет тип сообщения и имеет два метода: конструктор, не имеющий аргументов и метод воспроизведения звукового сигнала, связанного с типом сообщения: boolean
playSound(Display display) – воспроизводит звук, соответствующий
заданному типу сообщения. В определенных устройствах некоторые звуки могут отсутствовать. Возвращает значение true, если
37
звук был воспроизведен, и false – в противоположном случае.
Внешний вид и звуковой сигнал сообщения каждого типа зависят
от конкретной модели телефона.
Класс TextBox
Класс TextBox представляет экран, позволяющий вводить и редактировать текст с клавиатуры телефона. Он имеет единственный
конструктор:
• public TextBox(String title, String text, int maxSize, int
constraints), где
• title – заголовок поля ввода;
• text – начальное содержимое поля;
• maxSize – максимально допустимое количество вводимых символов;
• constraints – ограничения на вводимую информацию.
Параметр constraints задается константами класса TextField.
Возможные значения ограничений на вводимую информацию приведены в табл. 2.3.
Таблица 2.3
Константы класса TextField
Название
ANY
Описание
Допускается ввод любых символов без ограничений
EMAILADDR
Используется для ввода адреса электронной почты
NUMERIC
Применяется для ввода положительных и отрицательных
целых чисел
PHONENUMBER
Ввод телефонного номера
URL
Ввод сетевого адреса интернет-страницы в формате URL
DECIMAL
Применяется для ввода положительных и отрицательных
целых или дробных чисел
PASSWORD
Скрывает вводимые символы. Используется при запросе
пароля и другой секретной информации
Для работы с объектом класса TextBox можно использовать следующие методы:
• void delete(int offset, int length) – удаляет из поля ввода
length символов, начиная с позиции offset;
• int getCaretPosition() – возвращает текущее положение позиции ввода;
38
• int getMaxSize() – возвращает максимально допустимое количество вводимых символов;
• String getString() – возвращает содержимое поля ввода в виде
строки;
• void insert(String src, int position) – вставляет строку src в
поле ввода, начиная с позиции position;
• void setMaxSize(int maxSize) – устанавливает максимально допустимое количество вводимых символов;
• void setString(String text) – заменяет текущее содержимое
поля ввода на строку, указанную параметром text;
• int size() – возвращает количество символов, содержащееся в
поле ввода.
Составим приложение работы с классом TextBox. Конструктор
создает пустое поле ввода с заголовком «High Level API classes» с
максимально возможным количеством вводимых символов 256
без ограничений на вводимую информацию. Далее в поле ввода последовательно заносим строки с названиями классов высокоуровневого интерфейса. Отображаем объект поля ввода на экране. Код
мидлета приведен в листинге 2.5, содержимое экрана после выполнения программы показано на рис. 2.6, а). Если в коде приложения
убрать комментарий в строке t.delete(10,8), то из поля ввода будет
удален текст «Textbox» и экран телефона примет вид, показанный
на рис. 2.6, б). Отметим, что пользователь может сам редактировать
поле ввода, добавляя новые символы или удаляя существующие.
Листинг 2.5. Класс TextBoxMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class TextBoxMIDlet extends MIDlet
а)
б)
Рис. 2.6. Результат работы приложения TextBoxMIDlet
39
{
private Display d;
private TextBox t;
public TextBoxMIDlet()
{
t = new TextBox(«High Level API classes», ««, 256,
TextField.ANY );
t.setString( «List» + «\n» );
t.insert( «Alert» + «\n», t.getCaretPosition() );
t.insert( «Textbox» + «\n», t.getCaretPosition() );
t.insert( «Form» + «\n», t.getCaretPosition() );
//
t.delete( 10, 8 );
d = Display.getDisplay(this);
d.setCurrent( t );
}
public void startApp() { }
public void pauseApp() { }
public void destroyApp(boolean unconditional) { }
}
Класс Form
Объект класса Form является контейнером, который может содержать различные визуальные элементы, порожденные одним из
следующих классов: String, Image или Item. Элемент класса String
представляет собой статическую строку, а элемент класса Image –
изображение. Оба этих элемента дублируются объектами классов,
порожденных от класса Item.
Класс Item
Абстрактный класс Item является суперклассом для целой группы элементов, которые могут быть добавлены в форму (рис. 2.7):
• ChoiceGroup – это группа связанных элементов для дальнейшего выбора предполагаемых действий;
Item
ChoiceGroup
StringItem
Gauge
TextField
ImageItem
DateField
Рис. 2.7. Иерархия суперкласса Item
40
Spacer
• StringItem – класс для отображения произвольной текстовой
информации без возможности ее редактирования;
• ImageItem – осуществляет демонстрацию изображения на экране телефона;
• Gauge – допускает графическое отображение диаграмм, процессов загрузки;
• TextField – предоставляет текстовые поля для редакции;
• DateField – класс для редактирования времени и даты;
• Spacer – задает определенное по размеру пространство.
Каждый элемент класса Item может иметь свою метку. Для получения содержимого метки используется метод Sring getLabel().
Установить новое содержимое метки можно при помощи метода
void setLabel(String label).
Класс Item имеет множество методов для управления размещением элементов в форме. Перечислим основные методы:
• void addCommand(Command cmd) – добавляет команду к элементу;
• void removeCommand(Command cmd) – удаляет команду из элемента;
• void setDefaultCommand(Command cmd) – устанавливает встроенную команду по умолчанию для данного элемента;
• void setLayout(int layout) – устанавливает директивы для размещения элемента в форме:
LAYOUT_LEFT – выравнивание элемента по левой стороне;
  LAYOUT_RIGHT – выравнивание элемента по правой стороне;
 LAYOUT_CENTER – выравнивание элемента по центру;
 LAYOUT_TOP – выравнивание в верхней области формы;
LAYOUT_BOTTOM – выравнивание элемента по нижней стороне
 экрана;
 LAYOUT_VCENTER – вертикальное выравнивание по центру. Директивы горизонтального и вертикального выравниваний могут
комбинироваться при помощи оператора «|». Например, LAYOUT_
LEFT | LAYOUT_TOP. Следует отметить, что не все директивы применимы для размещения различных элементов в форме. Например, для
размещения текстовых строк нельзя применять директивы вертикального выравнивания;
• int getLayout(int layout) – возвращает директивы, используемые для размещения элементов в форме;
• int getMinimumHeight() – получает минимальную высоту для
элемента;
• int getMinimumWidth() – получает минимальную ширину для
элемента;
41
• int getPreferredHeight() – получает предпочтительную высоту
элемента;
• int getPreferredWidth() – получает предпочтительную ширину
элемента;
• void setItemCommandListener(ItemCommandListener i) – устанавливает обработчик событий для элемента.
Полный список методов класса Item можно посмотреть в [1].
Класс Form имеет два конструктора:
• Form(String title) – создает пустую форму с заголовком title;
• Form(String title, Item[] items) – создает пустую форму с заголовком title, содержащую элементы массива items.
Работа с формой осуществляется при помощи следующих методов:
• int append(String str) – добавляет статическую строку str
в форму;
• int append(Image img) – добавляет объект изображения img
в форму;
• int append(Item item) – добавляет элемент изображения item
в форму (один экземпляр элемента может быть добавлен лишь один
раз и только в одну форму). Методы append возвращают индекс, присвоенный формой элементу;
• void delete(int itemNum) – удаляет из формы элемент с индексом itemNum (нумерация элементов начинается с нуля);
• void deleteAll() – удаляет все элементы из формы;
• void insert(int itemNum, Item item) – вставляет в форму элемент
item в позицию, заданную переменной itemNum;
• void set(int itemNum, Item item) – заменяет в форме элемент с
индексом itemNum на элемент item;
• Item get(int itemNum) – возвращает элемент формы с индексом
itemNum;
• int size() – возвращает число элементов в форме;
• void setItemStateListener(ItemStateListener iListener) – задает
блок прослушивания элемента iListener.
Форма имеет свой внутренний список элементов. Добавление
элементов в конец списка осуществляется при помощи методов
append. Для добавления элемента в указанную позицию в списке
применяется метод insert. Замена элемента в списке выполняется
использованием метода set.
Перечислим основные правила размещения элементов в форме:
• элементы, которые разрешают пользовательский ввод
(TextField, DateField, Gauge, ChoiceGroup) размещаются вертикально,
42
причем первый элемент внутреннего списка формы располагается
вверху экрана, второй – непосредственно под ним и т. д.;
• элементы ImageItem и StringItem, которые не имеют метки или
имеют пустую метку, размещаются горизонтально. Если не хватает места, чтобы разместить StringItem по ширине экрана, то оставшийся текст переносится на следующую строку. Если недостаточно
места, чтобы разместить ImageItem по ширине экрана, то изображение просто обрезается;
• элементы ImageItem и StringItem, которые имеют непустую метку, обязательно выводятся со следующей строки;
• символ новой строки в StringItem приводит к переносу текста
на следующую строку;
• если ширина формы совпадает с шириной экрана, то высота
формы может превышать высоту экрана. Тогда устройство обеспечивает вертикальную прокрутку. Горизонтальный скроллинг не
выполняется.
Пример размещения элементов в форме демонстрирует мидлет, приведенный в листинге 2.6. Результат работы мидлета приведен на рис. 2.8. На форму последовательно добавляются строки
«TextField» и «ChoiceGroup». Они размещаются в верхней строке
экрана. Следующая строка «This is a very long string. It doesn’t
fit on one line.» превышает ширину экрана. Оставшаяся часть
строки переносится на следующую строку. Строка «StringItem\
б)
а)
Рис. 2.8. Отображение формы на экране
43
nImageItem\n» содержит символы переноса на следующую строку.
Поэтому строки «ImageItem» и далее «DateField» выводятся с новой строки. Элемент TextField c меткой «Item» выводится со следующей строки. Так как элемент StringItem s1 не имеет метки, то
он отображается в той же строке, что и строка текста «Gauge». Элемент StringItem s2 имеет метку «label». Поэтому он отображается со
следующей строки. Так как элемент s2 не помещается в одной строке экрана, то он переносится на следующую строку. На рис. 2.8, а
показан случай, когда высота формы превышает высоту экрана и
на экране появляется полоса прокрутки. Если форма помещается
на экране (рис. 2.8, б), то скроллинг не нужен.
Листинг 2.6. Класс ItemLayoutMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ItemLayoutMIDlet extends MIDlet
{
private Form f;
private Display d;
private TextField tf;
private StringItem s1,s2;
public ItemLayoutMIDlet()
{
f = new Form(«Items Layout»);
f.append(«TextField»);
f.append(«ChoiceGroup»);
f.append(
«This is a very long string. It doesn’t fit on one line.»);
f.append(«StringItem\nImageItem\n»);
f.append(«DateField»);
tf = new TextField(«Item»,null,16,TextField.ANY);
f.append(tf);
f.append(«Gauge»);
s1 = new StringItem(null,»This is a short string 1»);
s2 = new StringItem(«label»,
«This is a very long string 2. It doesn’t fit on one line.»);
f.append(s1);
f.append(s2);
d = Display.getDisplay(this);
d.setCurrent( f );
}
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean b) {}
}
44
Элементы класса Item
Класс ChoiceGroup
Позволяет встраивать в форму группу элементов, создавая меню.
Класс имеет два конструктора:
• public ChoiceGroup(String label, int choiceType), где
label – название создаваемой группы элементов,
choiceType – тип создаваемой группы элементов (EXCLUSIVE,
MULTIPLE или POPUP) и
• public ChoiceGroup(String label, int choiceType, String[]
stringElements, Image[] imageElements), где
• title – название создаваемого списка элементов,
• choiceType – тип создаваемой группы элементов,
• stringElements – массив строк для каждого элемента группы,
• imageElements – массив изображений для каждого элемента
группы.
Класс имеет примерно тот же набор методов, что и класс List.
Основные отличия класса ChoiceGroup от класса List:
• объект класса List может быть непосредственно отображен на
дисплее, а объект класса ChoiceGroup должен быть встроен в форму;
• оба класса позволяют создавать списки типов EXCLUSIVE и
MULTIPLE, но список типа IMPLICIT может быть создан только классом
List, а список типа POPUP – только классом ChoiceGroup.
Список всплывающего типа POPUP показан на экране в виде выпадающего меню. Модернизируем код мидлета из листинга 2.1 для
создания списка типа POPUP. Вместо объекта класса List создаем
объект cg класса ChoiceGroup. Добавляем элементы меню в группу
выбора и включаем объект cg в форму. Код мидлета приведен в листинге 2.7. Результат работы мобильного приложения приведен на
рис. 2.9.
Рис. 2.9. Список типа POPUP
45
Листинг 2.7. Класс ChoiceGroupMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ChoiceGroupMIDlet extends MIDlet {
private Form f;
private ChoiceGroup cg;
private Display d;
public ChoiceGroupMIDlet()
{
f = new Form(«High level API»);
cg = new ChoiceGroup (null, Choice.POPUP);
cg.append(«List», null);
cg.append(«Alert», null);
cg.insert(2, «Form», null);
cg.append(«TextBox», null);
f.append(cg);
d = Display.getDisplay(this);
d.setCurrent(f);
}
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean b) {}
}
Класс DateField
С помощью класса DateField можно произвести установку даты и
времени. Класс имеет два конструктора:
• public DateField(String label, int mode), где label – строка
текста, mode – режим отображения: DATE – вывод даты, TIME – вывод
времени, DATE_TIME – вывод даты и времени;
• public DateField(String label, int mode, TimeZone timeZone), где
label – строка текста, mode – режим отображения, timeZone – объект
класса TimeZone для установки часового пояса.
Класс DateField содержит всего четыре метода:
• Date getDate() – возвращает текущую дату;
• void setDate(Date date) – устанавливает новую дату;
• int getInputMode() – возвращает режим вывода;
• void setInputMode(int mode) – устанавливает режим вывода.
Описание классов Date и TimeZone приведено в [1, 4]. Пример работы с классом DateField представлен в листинге лабораторной работы № 1.
46
Класс TextField
С помощью класса TextField можно создать редактируемую
строку, отображаемую на экране телефона. Пользователь имеет
возможность для ввода и редактирования символов с клавиатуры
устройства.
Объект класса TextField реализует тот же набор методов, что и
объект класса TextBox, но если TextBox – самостоятельный отображаемый объект класса Displayable, то TextField для отображения на
экране должен быть обязательно включен в форму использованием
соответствующих методов класса Form. Вид и размещение полей ввода на экране зависит от конкретной модели устройства. Код мидлета, иллюстрирующий создание объектов класса TextField, приведен
в листинге 2.8. Программа отображает на экране форму для заполнения данных о кафедре университета: поля для ввода пароля, номера кафедры, адреса сайта и телефона. Содержимое дисплея телефона после выполнения программы показано на рис. 2.10.
Листинг 2.8. Класс TextFieldMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class TextFieldMIDlet extends MIDlet
{
private Display d;
private Form
f;
private TextField tpa, ta, tu, tph;
}
public TextFieldMIDlet()
{
f = new Form(«Department»);
tpa = new TextField(«Login», ««, 8, TextField.PASSWORD);
ta = new TextField(«Number», ««, 3, TextField.NUMERIC );
tu = new TextField(«URL», ««, 25, TextField.URL);
tph = new TextField(«Phone Number», ««, 20,
TextField.PHONENUMBER);
f.append(tpa);
f.append(ta);
f.append(tu);
f.append(tph);
d = Display.getDisplay(this);
d.setCurrent( f );
}
public void startApp() { }
public void pauseApp() { }
public void destroyApp(boolean unconditional) { }
47
Рис. 2.10. Создание объектов класса TextField
Класс StringItem
Класс StringItem позволяет интегрировать в форму статическую
строку текста, не допускающую возможности дальнейшего редактирования. Класс имеет два конструктора:
• public StringItem(String label, String text), где label – метка
для строки текста, text – строка текста;
• public StringItem(String label, String text, int appearanceMode),
где appearanceMode – режим отображения текстовой информации. Возможные значения параметра appearanceMode приведены в
табл. 2.4.
Таблица 2.4
Значения параметра appearanceMode
Параметр
Описание
0
Обычная строка текста
Item.BUTTON
Строка в виде кнопки
Item.HYPERLINK Строка в виде гиперссылки
Отметим, что последние два режима задаются константами
класса Item и могут быть связаны с командами, реагирующими на
нажатие кнопки или гиперссылки.
Перечислим основные методы класса StringItem:
• int getAppearanceMode() – возвращает режим отображения текста на экране;
• String getText() – получает содержимое текстовой строки;
• void setText(String text) – устанавливает содержимое текстовой строки;
• Font getFont() – получает шрифт текста;
• void setFont(Font font) – устанавливает шрифт текста.
48
Для примера создадим приложение StringItemMIDlet (листинг
2.9), выводящее на экран три строки (обычную строку, в виде кнопки и в виде гиперссылки) с разными размерами шрифта.
Определим порядок действий в конструкторе мидлета:
– создается форма f;
– создаются три статические строки с разными режимами и различным расположением на экране – si1, si2, si3;
– к элементам si2 и si3 добавляется командa cmd;
– к форме добавляется элементы si1, si2, si3;
– форма отображается на дисплее.
Для размещения строк на экране используется метод setLayout
класса Item. Строка si2 выравнивается по центру экрана, а строка
si3 – по правому краю экрана. Команда cmd имеет тип Command.ITEM.
Она добавляется к элементам si2 и si3, чтобы они приняли на экране вид кнопки и гиперссылки, соответственно. Обработка этой команды будет рассмотрена позднее при описании обработки событий
от элементов интерфейса, поэтому в данном мидлете не реализована. Результат работы мидлета приведен на рис. 2.11.
Листинг 2.9. Класс StringItemMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class StringItemMIDlet extends MIDlet
{
private Display d;
private Form f;
private StringItem si1, si2, si3;
private Command cmd;
public StringItemMIDlet()
{
f = new Form( «StringItem» );
Рис. 2.11. Отображение элементов StringItem на экране
49
}
}
si1 = new StringItem( «1», «String»);
si1.setFont( Font.getFont( 0, 0, Font.SIZE_SMALL ) );
si2 = new StringItem( «2», «BUTTON», Item.BUTTON );
si2.setLayout(Item.LAYOUT_CENTER );
si2.setFont( Font.getFont( 0, 0, Font.SIZE_LARGE ));
si3 = new StringItem( «3», «HYPERLINK», Item.HYPERLINK );
si3.setLayout(Item.LAYOUT_RIGHT );
cmd
= new Command( ««, Command.ITEM, 1 );
si2.addCommand( cmd );
si3.addCommand( cmd );
f.append(si1);
f.append(si2);
f.append(si3);
d = Display.getDisplay(this);
d.setCurrent(f);
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
Класс Spacer
Клаcc Spacer создает на экране свободное пространство определенного размера. Конструктор класса Spacer выглядит следующим
образом:
• public Spacer(int minWidth, int minHeight), где minWidth и
minHeight – ширина и высота в пикселях соответственно. Добавим
в листинг 2.8 следующие строки:
• private Spacer sp;
• sp = new Spacer(30,30);
Рис. 2.12. Использование объекта класса Spacer
50
• f.append(sp). Объект sp создает пустую область размером 30×30
пикселей. Поэтому объект tpa (текстовое поле для ввода пароля)
и все остальные объекты отображаются на экране ниже, чем на
рис. 2.10. Результат работы мидлета TextFieldMIDlet при добавлении объекта класса Spacer приведен на рис. 2.12. Описание методов
класса Spacer дана в [1].
Класс ImageItem
С помощью класса ImageItem возможна загрузка изображения в
форму. Работа с классом ImageItem подробно рассмотрена в лабораторной работе № 4.
Класс Gauge
При помощи класса Gauge создается шкала, отображающая
графическое течение некоторого процесса, например процесса загрузки приложения, поиска информации и т. п. Шкала имеет индикатор, который перемещается от одного конца шкалы к другому пропорционально завершению процесса. Внешний вид шкалы
зависит от конкретной модели телефона и не может быть изменен
пользователем.
Создать объект класса Gauge можно при помощи конструктора
public Gauge(String label, Boolean interactive, int maxValue, int
initialValue), который создает шкалу с заголовком label и возможным диапазоном значений от 0 до maxValue. Начальное значение
устанавливается равным initialValue. Параметр interactive имеет
два значения: true для интерактивного режима, когда значение
шкалы можно изменять, и false – для неинтерактивного режима,
когда шкалу можно только наблюдать, но изменять нельзя.
Класс Gauge имеет методы для управления шкалой и перемещением индикатора шкалы.
Изменить положение индикатора шкалы можно при помощи
метода int setValue(int value), где value – новое текущее значение
шкалы. Чтобы вычислить новое значение value необходимо:
• определить текущее значение шкалы, используя метод int
getValue();
• увеличить или уменьшить значение шкалы на некоторую величину;
• проверить, чтобы новое значение шкалы не превышало максимально возможное значение шкалы. Получить максимально возможное значение шкалы можно вызовом метода int getMaxValue().
51
Если необходимо расширить шкалу и увеличить это значение, необходимо использовать метод int setMaxValue(int maxValue).
Метод void setLabel(String label) устанавливает новый заголовок шкалы.
Пример создания шкалы, демонстрирующей процесс загрузки
некоторого приложения, представлен в листинге 2.10. Объект g
класса Gauge создается в неинтерактивном режиме. Для автоматического управления течением процесса загрузки в мидлете создается поток t. Метод run() выполнения потока представлен в классе
GaugeModification. Подробно работа с потоками будет рассмотрена в
лабораторной работе № 3.
Шкала имеет десять позиций. Каждую секунду индикатор шкалы перемещается на одну позицию вправо. Процесс загрузки в процентах отображается в поле метки элемента (рис. 2.13, а). По окончании загрузки, когда индикатор достигает максимального значения, выводится текст «Loading Completed» (рис. 2.13, б).
Листинг 2.10. Класс GaugeMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class GaugeMIDlet extends MIDlet
{
private Display d;
private Form f;
private Gauge g;
private Thread t;
public GaugeMIDlet()
{
f = new Form(««);
g = new Gauge(««, false, 10, 0);
f.append(g);
d = Display.getDisplay(this);
d.setCurrent(f);
t = new Thread(new GaugeModification());
t.start();
}
а)
б)
Рис. 2.13. Отображение шкалы загрузки некоторого приложения
52
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
}
class GaugeModification implements Runnable
{
GaugeModification()
{
g.setLabel(«Loading...»);
}
public void run()
{
try
{
while(g.getValue() < g.getMaxValue())
{
int ratio = ((g.getValue()+1) * 100)/g.getMaxValue();
g.setValue(g.getValue() + 1);
g.setLabel(«Loading « +
( new Integer( ratio ) ).toString() + «%»);
Thread.sleep(1000);
}
g.setLabel(«Loading Completed»);
}
catch(InterruptedException err)
{
}
}
}
Обработка событий в высокоуровневом API
При использовании высокоуровневого API приложение не имеет возможности получить информацию о том, какая клавиша была
нажата на клавиатуре мобильного устройства. Тем не менее высокоуровневый интерфейс поддерживает обработку событий при
помощи команд, описываемых классом Command из пакета javax.
microedition.lcdui. Объектам класса Command соответствуют экранные (функциональные) клавиши на дисплее устройства. Команда
представляет собой действие пользователя, которое выражается в
нажатии на функциональную клавишу. Событие – вызов команды
реализацией MIDP в ответ на действие пользователя.
Для создания команды используется конструктор: Command(String
label, int commandType, int priority), где label – строка, содержащая информацию о назначении команды, отображаемая на экране
в качестве названия команды; commandType – тип команды для опре53
деления ее назначения и местоположения (табл. 2.5); priority –
используется приложением для определения наиболее важных
команд. Если команд больше, чем функциональных клавиш, то
команды реализуются в виде меню таким образом, чтобы пользователь мог получить доступ к наиболее важным командам, как можно быстрее. Приоритет задается целым числом. Наименьшее число
означает наивысший приоритет.
Константы класса Command в табл. 2.5 задают лишь тип команды
и определяют ее местоположение на экране конкретного телефона.
Они не предписывают никаких действий, т. е. обработка команд не
будет происходить автоматически. Возврат к предыдущему экрану, выход из приложения и другие действия должны быть реализованы в соответствующем месте приложения.
Команды могут быть связаны с любыми отображаемыми объектами класса Displayable.
Таблица 2.5
Описание типов команд
Константа
BACK
CANCEL
EXIT
HELP
ITEM
OK
SCREEN
STOP
Описание
Возврат к предыдущему экрану. Применяется в приложениях, имеющих несколько экранов, для навигации между ними
Выбор отрицательного ответа в диалоге, реализуемом текущим экраном
Выход из приложения. Используется для завершения работы
приложения и выхода из него
Используется для вызова справочной информации
Имеет отношение к элементу экрана, обычно имеющему фокус
ввода: полю ввода, шкале и др.
Выбор положительного ответа в диалоге, реализуемом текущим экраном
Относится к отображаемому в настоящее время экрану
Остановка выполнения операции, например процесса сохранения данных
Для использования команды в приложении необходимо:
1. Создать объект команды, используя конструктор класса
Command.
2. Добавить команду к объекту класса Displayable. Для этого используется метод void addCommand(Command cmd) класса Displayable.
Удалить команду из отображаемого объекта можно при помощи
метода void removeCommand(Command cmd).
54
3. Связать приемник команд (блок прослушивания команд) с
отображаемым объектом класса Displayable при помощи метода
void setCommandListener(CommandListener cl). Этот процесс называется регистрацией блока прослушивания. Только один блок прослушивания может быть разрешен на один Displayable. Реализация
MIDP поставляет команды только в текущий объект Displayable.
Многие отображаемые объекты могут регистрировать тот же самый
блок прослушивания команд.
4. Написать метод обработчика команд void commandAction(Command
c, Displayable d) и реализовать там связанные с командами действия. Так как может быть больше одной команды на экран, то поэтому блок прослушивания команд должен идентифицировать источник команды и выбрать команду среди всех команд, связанных
с экраном в настоящее время.
Приемником и исполнителем команд может являться любой объект, реализующий интерфейс CommandListener. В общем случае блок
прослушивания может содержаться в любом объекте, в том числе
и в основном классе мидлета. Для этого необходимо в объявлении
основного класса мидлета написать: public class CommandMIDlet
extends MIDlet implements CommandListener (листинг 2.11). Слова
«implements CommandListener» означают, что приложение будет реализовывать интерфейс CommandListener и обрабатывать команды,
поступающие от пользователя.
В мидлете CommandMIDlet создается объект класса Form и три команды cmd1, cmd2, cmdExit. Команда завершения приложения cmdExit
имеет наивысший приоритет. Команды cmd1 и cmd2 относятся ко
всему экрану. Команды cmd1 и cmdExit добавляются к форме. Вызов
метода f.setCommandListener(this) означает, что к форме добавляется блок прослушивания команд. Ключевое слово this говорит о
том, что блок прослушивания будет реализован в основном классе мидлета. Взаимодействие классов в приложении представлено на рис. 2.14. Форма отображается на экране. Экранная форма
при запуске приложения представлена на рис. 2.15, а). Обработка
f(Form)
cmd1(Command)
cmdExit(Command)
Основной класс мидлета
(приемник команды)
commandAction()
Блок прослушивания команд
Рис. 2.14. Организация взаимодействия классов в приложении
55
а)
б)
Рис. 2.15. Экранные формы работы приложения
команд реализована в методе public void commandAction(Command c,
Displayable s). Когда пользователь нажимает экранную клавишу
«Command1», команда cmd2 добавляется к форме, а команда cmd1
удаляется из формы рис. 2.15, б). Аналогично вызов команды cmd2
(при нажатии клавиши «Command2») приводит к добавлению к
форме команды cmd1 и удалению из формы команды cmd2. По команде cmdExit происходит завершение работы приложения.
Листинг 2.11. Класс CommandMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public
class
CommandMIDlet
extends
MIDlet
CommandListener
{
private Form f;
private Display d;
private Command cmd1, cmd2, cmdExit;
public CommandMIDlet()
{
f = new Form(«Commands»);
cmdExit = new Command( «Exit», Command.EXIT, 0 );
cmd1 = new Command(«Command1», Command.SCREEN, 1);
cmd2 = new Command(«Command2», Command.SCREEN, 1);
f.addCommand(cmd1);
f.addCommand(cmdExit);
f.setCommandListener(this);
d = Display.getDisplay(this);
56
implements
d.setCurrent(f);
}
public void startApp() {};
public void pauseApp() {};
public void destroyApp(boolean unconditional) {};
}
public void commandAction( Command c, Displayable s )
{
if( c == cmd1 )
{
f.removeCommand(cmd1);
f.addCommand(cmd2);
}
if( c == cmd2 )
{
f.removeCommand(cmd2);
f.addCommand(cmd1);
}
if( c == cmdExit )
{
destroyApp( false );
notifyDestroyed();
}
}
Приложение в листинге 2.12 реализует те же действия, что и
приложение в листинге 2.11, но блок прослушивания команд содержится в классе MyForm – потомке класса Form, который реализует
интерфейс CommandListener.
Листинг 2.12. Класс CommandMIDlet (блок прослушивания в классе MyForm).
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class CommandMIDlet extends MIDlet
{
private MyForm mf;
private Display d;
private Command cmd1, cmd2, cmdExit;
public CommandMIDlet()
{
mf = new MyForm(«Commands»);
cmdExit = new Command( «Exit», Command.EXIT, 0 );
cmd1 = new Command(«Command1», Command.SCREEN, 1);
cmd2 = new Command(«Command2», Command.SCREEN, 1);
mf.addCommand(cmd2);
mf.addCommand(cmdExit);
mf.setCommandListener(mf);
d = Display.getDisplay(this);
d.setCurrent(mf);
57
}
public void startApp() {};
public void pauseApp() {};
public void destroyApp(boolean unconditional) {};
private class MyForm extends Form implements CommandListener
{
public MyForm(String str)
{
super(str);
}
public void commandAction( Command c, Displayable s )
{
if( c == cmd1 )
{
mf.removeCommand(cmd2);
mf.addCommand(cmd1);
}
if( c == cmd2 )
{
mf.removeCommand(cmd1);
mf.addCommand(cmd2);
}
if( c == cmdExit )
{
destroyApp( false );
notifyDestroyed();
}
}
}
}
Код, приведенный в листинге 2.13, поясняет ранее рассмотренный материал. Взаимосвязь классов приложения показана на
рис. 2.16. В приложении создаются два объекта класса Form f1 и f2,
для которых регистрируется общий блок прослушивания команд.
f1(Form)
f2Form
cmdExit(Command)
Внутренний класс
мидлета
MyCommandListener
commandAction()
Блок прослушивания команд
cmdInfo(Command)
cmd2(Command)
cmd1(Command)
Рис. 2.16. Взаимосвязь классов приложения
58
Приложение определяет внутренний класс MyCommandListener, который реализует интерфейс CommandListener. Команды cmdInfo и cmdExit
относятся как к объекту f1, так и к объекту f2. Команда cmdInfo
выводит на экран сообщение об объекте, используя объект класса
Alert. Команда cmd1 добавляется к объекту f2 и реализует переход
к экрану формы f1, а команда cmd2 относится к объекту f1 и выполняет переход на форму f2. В методе commandAction при обработке команды cmdInfo анализируется не только поступившая команда, но и
объект класса Displayable, к которому эта команда относится.
Листинг 2.13. Класс CommandMIDlet (блок прослушивания в классе MyCommandListener).
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class CommandMIDlet extends MIDlet
{
private Form f1, f2;
private Display d;
private MyCommandListener cl;
private Command cmd1, cmd2, cmdExit, cmdInfo;
public CommandMIDlet()
{
f1 = new Form(«Form1»);
f2 = new Form(«Form2»);
cmdExit = new Command( «Exit», Command.EXIT, 0 );
cmd1 = new Command(«Goto Form1», Command.SCREEN, 1);
cmd2 = new Command(«Goto Form2», Command.SCREEN, 1);
cmdInfo = new Command(«Info», Command.SCREEN, 2);
f1.addCommand(cmd2);
f1.addCommand(cmdInfo);
f1.addCommand(cmdExit);
f2.addCommand(cmd1);
f2.addCommand(cmdInfo);
f2.addCommand(cmdExit);
cl = new MyCommandListener();
f1.setCommandListener(cl);
f2.setCommandListener(cl);
d = Display.getDisplay(this);
d.setCurrent(f1);
}
public void startApp() {};
public void pauseApp() {};
public void destroyApp(boolean unconditional) {};
private class MyCommandListener implements CommandListener
{
59
private Alert al;
public void commandAction( Command c, Displayable s )
{
if(c == cmd2)
d.setCurrent(f2);
if(c == cmd1)
d.setCurrent(f1);
if((c == cmdInfo)&&(s == f1))
{
al = new Alert( null, «It is form1», null, AlertType.INFO);
d.setCurrent(al);
}
if((c == cmdInfo)&&(s == f2))
{
al = new Alert( null, «It is form2», null, AlertType.INFO);
d.setCurrent(al);
}
if( c == cmdExit )
{
}
}
}
destroyApp( false );
notifyDestroyed();
}
Экранные формы, приведенные на рис. 2.17 и 2.18, демонстрируют работу приложения. Видно, что команды, кроме команды
cmdExit, объединяются в меню в соответствии с приоритетами.
Рис. 2.17. Форма 1 и информационное сообщение по команде cmdInfo
60
Рис. 2.18. Форма 2 и информационное сообщение по команде cmdInfo
Команды для элементов интерфейса
Ранее рассмотренные команды относились к элементам класса
Displayable, например, ко всей форме. Но очень часто необходимо создать команду для того или иного элемента интерфейса, например – команду для изменения указателя шкалы. Если шкала только одна, то проблем не возникает. Если же, допустим, на
устройстве есть несколько различных регуляторов для управления
громкостью и другими параметрами, то лучше всего использовать
команды типа Item, предназначенные для отдельных элементов интерфейса.
Интерфейс ItemCommandListener реализует возможность получения событий от объектов класса Item. В интерфейсе определен метод void commandAction(Command c, Item item) для обработки команд,
поступающих от элементов интерфейса. Блок обработки команд
для элементов интерфейса устанавливается при помощи метода
setItemCommandListener класса Item.
Следующий мидлет (листинг 2.14) демонстрирует обработку событий, приходящих как от объектов класса Displayable, так и от объектов класса Item. В результате в программе определены два метода
CommandAction. В объявлении главного класса приложения указывается соответственно implements CommandListener, ItemCommandListener.
Главное окно приложения – объект класса Form. На форму добавляются два объекта cg1 и cg2 класса ChoiceGroup типа MULTIPLE:
61
список напитков (чай, кофе, какао) и список пирожных (эклер, бисквит, шоколадное пирожное с орехами). К объектам cg1 и cg2 добавляется команда «Order» – сделать заказ и блок прослушивания
ItemCommandListener. К форме добавляются команды «Exit» (завершение работы приложения) и «Clear» (очистка содержимого заказа) и блок прослушивания CommandListener.
Окно заказа – объект t класса TextBox. К объекту t добавляется
команда «Back» (возврат к главному окну приложения) и блок прослушивания CommandListener. Схема взаимодействия окон приложения приведена на рис. 2.19.
Работа с каждым списком выполняется отдельно. Чтобы добавить напиток в заказ, например кофе, необходимо выделить этот
элемент списка и применить команду «Order». Также в списке пирожных можно выбрать эклер и вызвать команду «Order». Содержимое главного окна приложения представлено на рис. 2.20, а), а
содержимое окна заказа – на рис. 2.20, б). Так как списки имеют
тип MULTIPLE, то пользователь может одновременно заказать несколько напитков и несколько пирожных.
Блок прослушивания ItemCommandListener
Главное окно
приложения
Окно заказа
Form
TextBox
Список напитков
Команда “Order”
Список пирожных
Команда “Order”
Команда “Exit”
Команда “Clear”
Команда “Back”
Блок прослушивания CommandListener
Рис. 2.19. Схема взаимодействия окон приложения
62
б)
а)
Рис. 2.20. Экранные формы приложения ItemCommandMIDlet
Массив get_flags используется для получения информации о выделенных элементах списка при выполнении команды «Order», а
массив clear_flags снимает выделение со всех элементов списка по
команде «Clear».
Листинг 2.14. Класс ItemCommandMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public
class
ItemCommandMIDlet
extends
MIDlet
implements
CommandListener, ItemCommandListener
{
private Form f;
private TextBox t;
private ChoiceGroup cg1, cg2;
private Display d;
private boolean[] clear_flags = { false, false, false };
private boolean[] get_flags = { false, false, false };
private String[] cakes = {«Eclair», «Sponge cake», «Brownie»};
private String[] drinks = {«Tea», «Coffee», «Cocoa»};
private
private
private
private
Command
Command
Command
Command
exit;
order;
clear;
back;
public ItemCommandMIDlet()
{
f = new Form(«Menu»);
63
t = new TextBox(«Order»,»«, 256,TextField.ANY);
exit
order
clear
back
cg1 =
cg2 =
= new Command(«Exit», Command.EXIT, 0);
= new Command(«order», Command.ITEM, 1);
= new Command(«clear», Command.ITEM, 1);
= new Command( «Back», Command.BACK, 1 );
new ChoiceGroup(«Drinks», Choice.MULTIPLE, drinks, null);
new ChoiceGroup(«Cakes», Choice.MULTIPLE, cakes, null);
f.append(cg1);
f.append(cg2);
cg1.addCommand(order);
cg2.addCommand(order);
cg1.setItemCommandListener(this);
cg2.setItemCommandListener(this);
f.addCommand(clear);
f.addCommand(exit);
f.setCommandListener(this);
}
d = Display.getDisplay(this);
d.setCurrent( f );
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean b) {}
public void commandAction(Command c, Displayable s)
{
if( c == exit )
{
destroyApp(false);
notifyDestroyed();
} else
if( c == back )
{
d.setCurrent(f);
t.removeCommand(back);
}
else if( c == clear )
{
cg1.setSelectedFlags(clear_flags);
cg2.setSelectedFlags(clear_flags);
t.delete(0,t.size());
}
}
public void commandAction(Command c, Item i)
{
if( c == order )
{
64
}
}
int pos = t.getCaretPosition();
if( i == cg1 )
{
cg1.getSelectedFlags(get_flags);
if( get_flags[0] == true ) t.insert(«Tea» + «\n»,pos);
if( get_flags[1] == true ) t.insert(«Coffee» + «\n»,pos);
if( get_flags[2] == true ) t.insert(«Cocoa» + «\n»,pos);
}
if( i == cg2 )
{
cg2.getSelectedFlags(get_flags);
if( get_flags[0] == true ) t.insert(«Eclair» + «\n»,pos);
if( get_flags[1] == true ) t.insert(«Sponge cake» + «\n»,pos);
if( get_flags[2] == true ) t.insert(«Brownie» + «\n»,pos);
}
t.addCommand( back );
t.setCommandListener( this );
d.setCurrent(t);
}
Изменение состояния элементов интерфейса
Блоки прослушивания CommandListener и ItemCommandListener не
позволяют отслеживать изменение состояния элементов класса
Item, допускающих пользовательский ввод (ChoiceGroup, DateField,
TextField, Gauge). Контролировать процесс ввода информации позволяет интерфейс ItemStateListener [4, 5]. Для регистрации блока прослушивания используется метод setItemStateListener класса
Form. Как только данные элемента изменяются пользователем, который выбирает новый пункт меню, изменяет положение индикатора
шкалы или вводит символ в поле ввода, автоматически вызывается
функция блока прослушивания void itemStateChanged(Item item).
Следует отметить, что функция вызывается только при изменении
элемента пользователем. Если изменение происходит программно,
то вызова не произойдет.
Для примера создадим приложение TranslateMIDlet (листинг
2.15), в котором выполняется перевод числа, заданного в формате
байта из двоичной системы счисления в десятичную. В объявлении
главного класса мидлета указывается implements CommandListener,
ItemStateListener.
Как только пользователь вводит очередной символ, то вызывается метод itemStateChanged. Введенные пользователем символы
помещаются в массив data. При этом если символ не соответствует
65
Рис. 2.21. Экранные формы мидлета TranslateMIDlet
двоичной системе счисления, то происходит очистка содержимого
поля ввода. В противном случае, если число введенных символов
достигло 8, выполняется перевод, и число в десятичной системе
отображается на экране в виде информационного сообщения с использованием объекта класса Alert. Экранные формы работы мидлета показаны на рис. 2.21.
Листинг 2.15. Класс TranslateMIDlet.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class TranslateMIDlet extends MIDlet implements CommandListener,
ItemStateListener
{
private Command exit;
private Form f;
private TextField tf;
private Alert al;
private Display d;
private char[] data = {‘0’,’0’,’0’,’0’,’0’,’0’,’0’,’0’};
private int num = 0;
public TranslateMIDlet()
{
exit = new Command( «Exit», Command.EXIT, 0 );
f = new Form(«(2)->(10)»);
tf = new TextField(«Number(2)»,»«,16,0);
f.append(tf);
f.addCommand(exit);
66
}
f.setItemStateListener(this);
f.setCommandListener(this);
d = Display.getDisplay(this);
d.setCurrent(f);
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void itemStateChanged(Item item)
{
int i, index;
if( item == tf )
{
tf.getChars(data);
index = tf.size() – 1;
if( !((data[index] == ‘0’) || (data[index] == ‘1’)))
tf.setString(««);
else
if(tf.size() == 8)
{
for( i = 0; i < 8; i++ )
if( data[i] == ‘1’ ) num = num + (1<<(7-i));
al = new Alert(null, String.valueOf(num),null,
AlertType.INFO);
tf.setString(««);
num = 0;
d.setCurrent(al);
tf.setString(««);
}
}
}
}
public void commandAction(Command c, Displayable s)
{
if( c == exit )
{
destroyApp(false);
notifyDestroyed();
}
}
2.2. Варианты заданий
Составить две программы, демонстрирующие использование элементов высокоуровневого пользовательского интерфейса. В табл. 2.6 приведены обязательные отображаемые объекты
67
мидлетов. В дополнение к ним в программах можно использовать
любое число отображаемых объектов разных классов. Оба мидлета должны содержать, по крайней мере, один объект класса
Alert. Мидлет 1 должен реализовать интерфейсы CommandListener
и ItemCommandListener, а мидлет 2 – интерфейсы CommandListener и
ItemStateListener.
2.3. Содержание отчета
1. Титульный лист.
2. Цель работы.
3. Задание к лабораторной работе.
4. Листинги с кодами мидлетов 1 и 2.
5. Экранные формы с результатами работы мидлетов 1 и 2.
6. Выводы по лабораторной работе.
Таблица 2.6
Объекты мидлетов, обязательные для отображения
Номер
варианта
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
68
Отображаемые объекты
1
List.IMPLICIT
List.EXCLUSIVE
List.MULTIPLE
ChoiceGroup.EXCLUSIVE
ChoiceGroup.MULTIPLE
ChoiceGroup.POPUP
ChoiceGroup.EXCLUSIVE
ChoiceGroup.MULTIPLE
ChoiceGroup.POPUP
List.IMPLICIT
List.EXCLUSIVE
List.MULTIPLE
List.IMPLICIT
List.EXCLUSIVE
List.MULTIPLE
ChoiceGroup.EXCLUSIVE
ChoiceGroup.MULTIPLE
ChoiceGroup.POPUP
2
DateField
Gauge
TextField.PASSWORD
TextBox
TextField.ANY
TextField.EMAILADDR
StringItem.HYPERLINK
Gauge
StringItem.BUTTON
TextField.URL
TextField.ANY
TextField.NUMERIC
TextField.NUMERIC
StringItem.HYPERLINK
TextField.DECIMAL
StringItem.BUTTON
TextField.PHONENUMBER
TextBox
Лабораторная работа № 3
Низкоуровневый программный интерфейс
в Java ME
Цель работы: изучение классов низкоуровневого пользовательского интерфейса, работа с графикой, обработка нажатий с клавиш
телефона, организация многопоточных приложений, разработка
мидлетов на основе низкоуровневого API.
3.1. Методические указания
Класс Canvas
Низкоуровневый интерфейс решает проблему непосредственного доступа к экрану. Для этого используется абстрактный класс
Canvas. Пользователь не может создать объект класса Canvas, но
может создать новый класс, производный от класса Canvas и переопределить в нем метод void paint(Graphics g), отвечающий за перерисовку экрана и получающий в качестве аргумента объект класса
Graphics. Класс Graphics содержит методы для рисования линий,
прямоугольников и дуг, заливки фигур, задания цвета для рисования и отображения текстовых символов. Кроме того, класс Canvas
предоставляет возможность в обработке событий, полученных с клавиш телефона.
Класс Graphics
Класс Graphics предоставляет возможность низкоуровневого
графического рисования на экране телефона. Если увеличить дисплей в несколько раз, то он будет напоминать сетку, состоящую из
большого числа ячеек. Каждая ячейка может принимать один из
возможных цветов, поддерживаемых дисплеем. Такая ячейка называется точкой, или пикселем. Разрешение экрана – это количество пикселей по вертикали и горизонтали.
Пользователь может получить доступ к любой точке экрана, указав ее координаты в системе координат, приведенной на рис. 3.1.
Начало системы координат, точка (0,0), находится в левой верхней
точке экрана телефона. Координаты оси X увеличиваются слева направо, а оси Y – сверху вниз. Закрашенный пиксел на рис. 3.1 имеет координаты – (2,1).
69
0
1
2
3
1
X
пиксел
2
3
Y
Рис. 3.1. Система координат в Java ME
Рассмотрим основные методы класса Graphics.
Методы класса Graphics
для рисования геометрических фигур:
• void drawLine(int x1, int y1, int x2, int y2) – рисует линию из точки с координатами (x1,y1) в точку с координатами (x2,y2)
(рис. 3.2);
• void drawRect(int x, int y, int width, int height) – рисует
прямоугольник с левым верхним углом в точке (x,y) шириной width
и высотой height пикселей (рис. 3.3);
(x1,y1)
(x2,y2)
Рис. 3.2. Линия
(x,y)
height
width
Рис. 3.3. Прямоугольник
70
• void drawRoundRect(int x, int y, int width, int height, int
arcWidth, int arcHeight) – рисует прямоугольник с закругленными
углами (рис. 3.4). Первые четыре аргумента совпадают с аргументами предыдущего метода, arcWidth задает ширину закругления, а
arcHeight – высоту закругления;
• void drawArc(int x, int y, int width, int height, int startAngle,
int arcAngle) – рисует дугу, вписанную в прямоугольник с левым
верхним углом в точке с координатами (x,y) (рис. 3.5). Параметр
startAngle задает угол, с которого будет начинаться дуга, а arcAngle
определяет угловое расстояние, на которое будет простираться
дуга. Углы задаются в градусах. Значение arcAngle 360° замкнет
дугу в окружность.
В классе Graphics отсутствуют методы для рисования точки и
треугольника. Точку можно нарисовать, используя линию, у кото(x,y)
arcHeight
height
arcWidth
width
Рис. 3.4. Прямоугольник с закругленными углами
(x,y)
height
startAngle
width
Рис. 3.5. Дуга
71
(x1,y1)
(x3,y3)
(x2,y2)
Рис. 3.6. Треугольник
рой координаты начала и конца совпадают: drawLine(x1,y1,x1,y1).
Треугольник рисуется при помощи трех линий (рис. 3.6):
drawLine(x1,y1,x2,y2);
drawLine(x2,y2,x3,y3);
drawLine(x3,y3,x1,y1).
Методы класса Graphics
для рисования закрашенных фигур:
• void fillRect(int x, int y, int width, int height) – рисует закрашенный прямоугольник;
• void fillRoundRect(int x, int y, int width, int height, int
arcWidth, int arcHeight) – рисует закрашенный прямоугольник c
закругленными углами;
• void fillArc(int x, int y, int width, int height, int startAngle,
int arcAngle) – рисует закрашенный сектор;
• void fillTriangle(int x1, int y1, int x2, int y2, int x3, int
y3) – рисует закрашенный треугольник.
Определение размеров экрана
Размеры экрана у разных мобильных телефонов могут серьезно
отличаться. При этом надо стараться разрабатывать приложения,
которые могли бы выполняться на различных аппаратах. Класс
Canvas содержит методы для определения размеров отображаемой
области экрана, которые остаются неизменными во время работы
приложения:
• int getHeight() – возвращает высоту отображаемой области
экрана;
• int getWidth() – возвращает ширину отображаемой области
экрана.
72
По умолчанию текущей областью для рисования является весь
экран. Но это можно изменить, используя метод void setClip(int x,
int y, unt width, int height), который устанавливает новую прямоугольную область рисования с левым верхним углом в точке (x,y)
шириной width и высотой height пикселей. Размеры текущей области рисования можно получить при помощи методов:
• int getClipHeight() – возвращает высоту текущей области для
рисования;
• int getClipWidth() – возвращает ширину текущей области для
рисования.
Управление цветом в J2ME
В настоящее время практически все мобильные телефоны имеют цветной дисплей. Менеджер дисплея имеет методы:
• boolean isColor() возвращает значение true, если телефон поддерживает работу с цветом;
• int numColors() возвращает число цветов, поддерживаемых
дисплеем.
В J2ME для управления цветом используется модель RGB, где
R – интенсивность свечения красного, G – интенсивность свечения
зеленого, B – интенсивность свечения синего. Доля каждого из этих
цветов задается целым числом от 0 до 255, что позволяет воспроизвести 16 777 216 цветов. Нулевая интенсивность всех цветов задает
черный цвет, а максимальная – белый цвет. Комбинация (0,0,255)
задает синий цвет.
Методы класса Graphics
для управления цветом
Для установки цвета рисования используются следующие методы класса Graphics:
• void setColor(int red, int green, int blue) – устанавливает цвет
рисования, заданный цветовыми компонентами red, green, blue;
• void setColor(int RGB) – устанавливает цвет рисования, заданный цветовыми компонентами, объединенными в одно число RGB.
Число формируется следующим образом: (red << 16) + (green <<
8) + blue. Например, зеленому цвету будет соответствовать число
0x00FF00 в формате RGB.
Узнать текущий цвет рисования можно при помощи следующих
методов:
73
• int getRedComponent() – получает красный компонент цвета;
• int getGreenComponent() – получает зеленый компонент цвета;
• int getBlueComponent() – получает синий компонент цвета;
• int getColor() – получает число в формате RGB.
Для получения нужного цвета в цифровом виде, представленном или в виде отдельных компонент, или в формате RGB, можно
воспользоваться тем или иным графическим редактором, например редактором Paint.
Методы класса Graphics для рисования текста
• void drawChar(char character, int x, int y, int anchor) – выводит на экран символ character, размещая его точку привязки, заданную аргументом anchor, в точке с координатами (x,y).
• void drawString(String str, int x, int y, int anchor) – выводит
на экран текстовую строку str в указанной позиции;
• void drawSubString(String str, int offset, int len, int x, int
y, int anchor) – рисует часть строки str длиной len символов, начиная с символа с индексом offset.
При отображении строки текста в интерфейсе высокого уровня
форматирование строки происходит автоматически. В интерфейсе
низкого уровня за размещение текста на экране отвечает программист. Позиция для текста задается при помощи точки привязки.
Для того чтобы вывести текст на экран, программе нужно вычислить воображаемый ограничивающий прямоугольник, в котором и
будет выведен текст (рис. 3.7).
Возможные варианты размещения текста относительно точки
привязки представлены в табл. 3.1.
Точка привязки определяется комбинацией вертикальной и горизонтальной констант класса Graphics. Расположение точки привязки на ограничивающем прямоугольнике показано на рис. 3.8.
На рисунке не показан параметр BASELINE. Основное его отличие от
параметра BOTTOM показано на рис. 3.9. Некоторые буквы (например, Q) имеют часть, расположенную ниже основной линии. Если
указан параметр BASELINE, то выравнивание будет производиться по
основной линии, а если указан параметр BOTTOM – то по самой нижней части строки.
PHONE
Рис. 3.7. Ограничивающий прямоугольник
74
HCENTER |TOP
LEFT |TOP
LEFT|BOTTOM
RIGHT |TOP
RIGHT |BOTTOM
HCENTER |BOTTOM
Рис. 3.8. Схема точек привязки текста
Q
BASELINE
BOTTOM
Рис. 3.9. Отличие параметров BASELINE и BOTTOM
Таблица 3.1
Константы класса Graphics
Параметр Значение
Описание
LEFT
4
Размещает левый край ограничивающего прямоугольника текста у координаты x
HCENTER
1
Размещает центр ограничивающего прямоугольника
текста у координаты x
RIGHT
8
Размещает правый край ограничивающего прямоугольника текста у координаты x
TOP
16
Размещает верхний край ограничивающего прямоугольника текста у координаты y
BOTTOM
32
Размещает нижний край ограничивающего прямоугольника текста у координаты y
BASELINE 64
Размещает нижнюю строку ограничивающего прямоугольника текста у координаты y
В качестве примера вывода текста на экран рассмотрим мидлет,
приведенный в листинге 3.1. В файле Файл DrawTextMIDlet.java
создается объект класса MyCanvas, который отображается на экране. В файле MyCanvas.java все операции рисования выполняются в
методе paint. Перед выводом текста экран очищается заливкой в белый цвет методом g.fillRect(0, 0, getWidth(), getHeight()). Задается черный цвет рисования и выводится текст, повторяющий схему
75
точек привязки (см. рис. 3.8). Отметим, что в конструкторе класса
MyCanvas обязателен вызов конструктора базового класса Canvas.
Листинг 3.1. Мидлет для вывода текста на экран.
Файл DrawTextMIDlet.java:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class DrawTextMIDlet extends MIDlet
{
private Display d;
private MyCanvas canvas;
public DrawTextMIDlet()
{
d = Display.getDisplay( this );
canvas = new MyCanvas();
d.setCurrent(canvas);
}
}
public void startApp() { }
public void pauseApp() { }
public void destroyApp(boolean destroy)
{ canvas = null; }
Файл MyCanvas.java:
import javax.microedition.lcdui.*;
public class MyCanvas extends Canvas
{
public MyCanvas()
{
super();
}
public void paint( Graphics g )
{
g.setColor(255,255,255);
g.fillRect(0, 0 , getWidth(), getHeight());
g.setColor(0,0,0);
g.drawRect(10,10,220,100);
g.drawString(«LEFT|TOP», 10, 10, Graphics.LEFT | Graphics.TOP) ;
g.drawString(«LEFT|BOT», 10, 110,
Graphics.LEFT | Graphics.BOTTOM) ;
g.drawString(«RIGHT|TOP», 230, 10, Graphics.RIGHT | Graphics.TOP);
g.drawString(«RIGHT|BOT», 230, 110,
Graphics.RIGHT | Graphics.BOTTOM) ;
g.drawString(«HCENTER|TOP», 120, 10,
Graphics.HCENTER | Graphics.TOP) ;
g.drawString(«HCENTER|BASELINE», 120, 110,
76
Рис. 3.10. Результат работы мобильного приложения
}
}
Graphics.HCENTER | Graphics.BASELINE) ;
Результат работы мидлета приведен на рис. 3.10.
Опишем еще некоторые методы класса Graphics, которые можно
использовать при создании мидлетов:
• void translate(int x, int y) – переносит начало координат в
точку с координатами (x,y);
• int getTranslateX() и int getTranslateY() – позволяют получить
текущее положение начала координат относительно левого верхнего угла экрана;
• void setStrokeStyle(int style) – задает стиль рисования линий,
дуг и прямоугольников. В качестве параметра style используется
одна из констант класса Graphics: SOLID – для рисования сплошных
линий, DOTTED – для рисования пунктирных линий;
• int getStrokeStyle() – получает текущий стиль штрихования.
• void drawImage(Image img, int x, int y, int anchor) – рисует
картинку, заданную параметром img, в точке привязки anchor с координатами (x,y).
Обработка событий низкоуровневого интерфейса
Пользователь может взаимодействовать с приложением низкоуровневого интерфейса одним из двух способов. Первый способ:
создать объект класса Command, добавить команду к объекту потомку
класса Canvas, используя метод addCommand, добавить блок прослушивания commandListener к объекту потомку класса Canvas, определить
метод CommandAction. Этот способ используется и в высокоуровневом
интерфейсе. Второй способ характерен только для низкоуровневого API и позволяет отслеживать нажатие любой клавиши.
Мобильные устройства имеют 12-клавишную клавиатуру стандарта ITU-T (рис. 3.11). Каждая клавиша имеет свой код. Платфор77
Рис. 3.11. ITU-T клавиатура
ма Java ME связывает с каждой кодом клавиши константу класса
Canvas (табл. 3.2).
Таблица 3.2
Стандартные коды клавиш
Константа
KEY_NUM0
KEY_NUM1
KEY_NUM2
KEY_NUM3
KEY_NUM4
KEY_NUM5
KEY_NUM6
KEY_NUM7
KEY_NUM8
KEY_NUM9
KEY_STAR
KEY_POUND
Клавиша
Клавиша 0
Клавиша 1
Клавиша 2
Клавиша 3
Клавиша 4
Клавиша 5
Клавиша 6
Клавиша 7
Клавиша 8
Клавиша 9
Клавиша *
Клавиша #
Код клавиши
48
49
50
51
51
53
54
55
56
57
42
35
Некоторые телефоны имеют дополнительные клавиши, связанные с игровыми действиями. Коды клавиш, не являющихся
стандартными, могут иметь различные значения в зависимости от
модели телефона и производителя. Константы класса Canvas, соответствующие этим клавишам, приведены в табл. 3.3.
Интерфейс низкого уровня формирует событие при нажатии любой клавиши. В зависимости от действий пользователя автоматически вызывается один из трех методов класса Canvas:
78
• void keyPressed( int keyCode ) – вызывается, если какая-либо
клавиша была нажата;
• void keyReleased( int keyCode ) – вызывается, если какая-либо
клавиша была отпущена;
• void keyRepeated( int keyCode ) – вызывается при длительном
нажатии клавиши.
Эти методы выполняют роль блока прослушивания событий
низкоуровневого интерфейса и имеют только один параметр –
код нажатой клавиши. Наиболее часто в приложениях используется метод keyPressed. Чтобы привязать какие-то действия к
событию, вызванному нажатием клавиши, надо в потомке класса Canvas переписать этот метод и там реализовать необходимые
действия.
Таблица 3.3
Константы игровых клавиш
Константа
UP
DOWN
LEFT
RIGHT
FIRE
GAME_A
GAME_B
GAME_C
GAME_D
Клавиша
Код игрового дествия
Клавиша со стрелкой вверх
1
Клавиша со стрелкой вниз
6
Клавиша со стрелкой влево
2
Клавиша со стрелкой вправо
5
Клавиша выбора или стрельбы
8
Определяется устройством
9
Определяется устройством
10
Определяется устройством
11
Определяется устройством
12
Ниже приведены примеры использования метода keyPressed для
обработки событий от стандартных (пример 3.1) и игровых (примеры 3.2 и 3.3) клавиш.
Пример 3.1
public
{
}
void keyPressed(int keyCode)
switch (keyCode)
case KEY_NUM0: y
case KEY_NUM1: y
case KEY_NUM2: y
}
{
= x; break;
= x + 1; break;
= x + 2; break;
79
Пример 3.2
public void keyPressed(int keyCode)
{
int act = getGameAction(keyCode);
switch (act) {
case UP: y––; break;
case DOWN: y++; break;
case LEFT: x––; break;
case RIGHT: x++; break;
}
}
Пример 3.3
public void keyPressed(int keyCode)
{
int upKey = getKeyCode(Canvas.UP);
int downKey = getKeyCode(Canvas.UP);
int leftKey = getKeyCode(Canvas.LEFT);
int rightKey = getKeyCode(Canvas.RIGHT);
switch (keyCode) {
case upKey: y––; break;
case downKey: y++; break;
case leftKey: x––; break;
case rightKey: x++; break;
}
}
Примеры 3.2 и 3.3 демонстрируют использование двух методов
класса Canvas:
• public int getGameAction( int keyCode ) – преобразует код нажатой клавиши в код игрового действия;
• void getKeyCode( int gameAction ) – преобразует код игрового
действия в код клавиши.
Пример, иллюстрирующий работу с низкоуровневым API, приведен в листинге 3.2. В конструкторе класса CircleMIDlet создается объект dr класса Draw, где класс Draw – потомок класса Canvas.
К объекту dr добавляется команда завершения работы приложения «Exit», блок прослушивания. Далее объект отображается на
экране. В файле Draw.java интерес представляют методы paint и
keyPressed. В методе paint содержимое экрана сначала очищается
(закрашивается белым цветом), а потом по центру экрана рисуется круг синего цвета с начальным радиусом 20 пикселей. В левом
верхнем углу экрана выводится строка с текущим значением радиуса. В методе keyPressed обрабатываются нажатия клавиш «1» и
«2» клавиатуры телефона. При каждом нажатии на клавишу «1»
80
радиус круга увеличивается на 1, а при каждом нажатии на клавишу «2» – уменьшается на 1. Также проводится проверка, чтобы
радиус круга находился в диапазоне от 10 до 100. В конце метода
вызывается метод repaint для перерисовки всего экрана.
Листинг 3.2. Мидлет для работы с низкоуровневым API.
Файл CircleMIDlet.java:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class CircleMIDlet extends MIDlet implements CommandListener
{
private Draw dr;
private Display d;
private Command exitMIDlet;
public CircleMIDlet()
{
}
exitMIDlet
= new Command( «Exit», Command.EXIT, 0 );
dr = new Draw();
dr.addCommand( exitMIDlet );
dr.setCommandListener( this );
d = Display.getDisplay( this );
d.setCurrent( dr );
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean destroy) {}
}
public void commandAction( Command c, Displayable s )
{
if( c == exitMIDlet )
{
destroyApp( false );
notifyDestroyed();
}
}
Файл Draw.java:
import javax.microedition.lcdui.*;
public class Draw extends Canvas
{
private int radius;
public Draw()
{
81
}
super();
radius = 20;
public void paint( Graphics g )
{
g.setColor( 255, 255, 255);
g.fillRect( 0, 0, getWidth(), getHeight() );
g.setColor( 0, 0, 255);
g.fillArc( (getWidth() – radius)/2, (getHeight()-radius )/2,
radius, radius, 0, 360 );
g.drawString( «radius = « + radius, 10, 10,
Graphics.LEFT | Graphics.TOP );
}
}
protected void keyPressed( int keyCode )
{
switch( keyCode )
{
case KEY_NUM1: if( radius < 100 )
{
radius++;
repaint();
}
break;
case KEY_NUM2: if( radius > 10 )
{
radius--;
repaint();
}
break;
default:
break;
}
repaint();
}
Результат работы мидлета приведен на рис. 3.12, а. Если в метод
paint добавить метод g.setClip(0, 0, 240, 150), т. е. ограничить область рисования до размера 240 × 150 пикселей, то результат будет
иметь вид, показанный на рис. 3.12, б. Видно, что нижняя часть
круга не выводится. Пример работы приложения при использовании метода g.translate(50, 50) приведен на рис. 3.13. Начало координат переносится в точку (50, 50).
Теперь попробуем составить мидлет, в котором объект будет самостоятельно изменять свои размеры, т. е. круг будет или уменьшаться, или расширяться без постоянного нажатия пользователя
на клавиши «1» и «2». Можно, например, попробовать зациклить
82
а)
б)
Рис. 3.12. Результаты работы мидлета: а – область рисования –
весь экран; б – область рисования – ограничена
Рис. 3.13. Результат работы со смещенным началом координат
действие, связанное с увеличением радиуса круга. Но тогда приложение не будет иметь возможности выхода из цикла и обрабатываь
нажатие клавиш. Решить проблему можно, используя многозадачность мобильной операционной системы. Язык Java имеет встроенную поддержку многопоточного программирования.
Потоки
Многопоточная программа может состоять из двух и более частей, способных выполняться одновременно. Каждую такую часть
83
принято называть потоком. Одновременность надо понимать так:
каждому потоку отводится определенное количество процессорного времени, в течение которого поток выполняется, после чего происходит переключение процессора на выполнение другого потока.
Сама по себе программа (мидлет) уже является потоком, причем
главным потоком. Главный поток может порождать другие потоки
(дочерние).
Для того чтобы породить дочерний поток, необходимо:
1. Класс, в котором будет размещен код потока, должен реализовывать интерфейс Runnable, который содержит лишь один метод
run(): public class Draw extends Canvas implements Runnable.
2. За работу с потоками отвечает класс Thread. Чтобы создать новый поток, необходимо создать объект этого класса: Thread t = new
Thread(this) (конструктор принимает в качестве аргумента объект,
реализующий интерфейс Runnable).
3. Запустить выполнение потока, используя метод Start:
t.start() (это приведет к вызову метода run потока, который напрямую вызывать нельзя).
Теперь рассмотрим, как организовать работу потока. Пример
многопоточного приложения представлен в листинге 3.3. Метод
run(), содержащий код потока, может содержать линейно выполняемый код. В таком случае после выполнения всего кода поток
будет завершен. В нашем случае поток должен выполняться циклически, отображая через определенные промежутки времени
круг на экране. Поэтому имеет смысл организовать внутри метода
run цикл while. Цикл будет выполняться до тех пор, пока значение
переменной sleeping равно false. Это значение задается переменной
при старте потока. При завершении работы приложения вызывается метод stop класса Draw, который присваивает переменной значение true, и работа потока завершается. Для приостановки работы
потока на определенное время вызывается метод sleep(), который
в качестве параметра принимает количество миллисекунд, на которое поток должен «уснуть» (в данном примере на 100 миллисекунд). Во избежание ошибок метод вызывается внутри конструкции try{}…catch(). В нашем случае цикл повторяется с задержкой
в 0,1секунды, что позволяет наблюдать изменение размеров круга
10 раз в секунду.
В методе keyPressed происходит присвоение значений переменным direction (клавиши LEFT и RIGHT) и stopping (клавиши UP и DOWN).
Переменная direction задает направление изменения радиуса кру84
га. При нажатии на клавишу LEFT круг будет увеличиваться в размерах, а при нажатии на клавишу RIGHT – уменьшаться. Нажатие на
клавишу DOWN запускает процесс автоматического изменения размеров круга, а нажатие на клавишу UP останавливает этот процесс.
Метод run() изменяет радиус круга и проверяет его на соответствие граничным значениям. Метод paint() рисует объект в соответствии с новым значением радиуса и выводит это значение в текстовой строке, размещенной в левом верхнем углу экрана. Результат работы мобильного приложения будет таким же, как в мидлете,
приведенном в листинге 3.2.
Листинг 3.3. Многопоточное приложение.
Файл CircleMIDlet.java:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class CircleMIDlet extends MIDlet implements CommandListener
{
private Draw dr;
private Display d;
private Command exitMIDlet;
public CircleMIDlet()
{
}
exitMIDlet
= new Command( «Exit», Command.EXIT, 0 );
dr = new Draw();
dr.addCommand( exitMIDlet );
dr.setCommandListener( this );
dr.start();
d = Display.getDisplay( this );
d.setCurrent( dr );
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean destroy) {}
}
public void commandAction( Command c, Displayable s )
{
if( c == exitMIDlet )
{
dr.stop();
destroyApp( false );
notifyDestroyed();
}
}
85
Файл Draw.java:
import javax.microedition.lcdui.*;
public class Draw extends Canvas implements Runnable
{
private int radius;
private boolean direction, stopping, sleeping;
public Draw()
{
super();
radius = 20;
direction = false;
stopping = true;
}
public void start()
{
Thread t = new Thread( this );
t.start();
sleeping = false;
}
public void stop()
{
sleeping = false;
}
public void run()
{
while( !sleeping )
{
if( !stop )
{
if( direction == false )
{
if( radius < 100 ) radius++;
}
if( direction == true )
{
if( radius > 10 ) radius--;
}
}
repaint();
try{ Thread.sleep(100); }
catch( java.lang.InterruptedException z ) {}
}
}
public void paint( Graphics g )
{
86
g.setColor( 255, 255, 255);
g.fillRect( 0, 0, getWidth(), getHeight() );
g.setColor( 0, 0, 255);
g.fillArc( ( getWidth() – radius )/2, (getHeight() – radius
)/2,
}
radius, radius, 0, 360 );
g.drawString( «radius = « + radius, 10, 10,
Graphics.LEFT | Graphics.TOP );
protected void keyPressed( int keyCode )
{
int actionCode = getGameAction(keyCode);
}
}
switch( actionCode )
{
case LEFT: direction = false;
break;
case RIGHT: direction = true;
break;
case UP: stopping = true;
break;
case DOWN: stopping = false;
break;
default: break;
}
3.2. Задание к лабораторной работе
1. Разработать мидлет 1, рисующий на дисплее мобильного телефона объект 1 и объект 2. Фигуры, соответствующие объектам и
цвета объектов, указаны в табл. 3.4.
Таблица 3.4
Объекты для отображения и их цвета
Номер
варианта
1
2
3
Объект 1
Объект 2
Цвет
объекта 1
Цвет
объекта 2
Прямоугольник
Круг
Синий
Фиолетовый
Эллипс
Прямоугольник
с закругленными
углами
Квадрат
Красный
Голубой
Линия
сплошная
Желтый
Черный
87
Окончание табл. 3.4
Номер
варианта
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Объект 1
Объект 2
Цвет
объекта 1
Параллелограмм Квадрат
Зеленый
Дуга
Эллипс
Малиновый
Треугольник
Прямоугольник
Серый
Прямоугольник
с закругленными Дуга
Черный
углами
Параллелограмм Круг
Голубой
Линия пунктирная Эллипс
Фиолетовый
Линия сплошная Трапеция
Фиолетовый
Параллелограмм Дуга
Голубой
Квадрат
Треугольник
Черный
Прямоугольник
Трапеция
с закругленными Серый
углами
Эллипс
Параллелограмм Малиновый
Прямоугольник
Трапеция
Зеленый
Круг
Линия пунктирная Желтый
Треугольник
Эллипс
Красный
Круг
Дуга
Синий
Цвет
объекта 2
Серый
Зеленый
Малиновый
Красный
Желтый
Синий
Желтый
Красный
Синий
Малиновый
Зеленый
Черный
Голубой
Фиолетовый
Серый
Координаты начального расположения объектов и названия
клавиш для обработки событий приведены в табл. 3.5. В нечетных вариантах при движении объектов и достижении ими границы экрана они появляются с противоположной стороны экрана, а
в четных вариантах – отражаются от границы экрана и движутся
в противоположном направлении. Размеры объектов выбираются
самостоятельно.
Реализуемые действия при нажатии на клавиши мобильного
телефона представлены в табл. 3.6. При однократном нажатии на
клавиши 1 и 2, объекты должны двигаться согласно табл. 3.6, а при
повторном нажатии на клавиши 1 и 2 в нечетных вариантах объекты останавливаются, а в четных – меняют направление движения
на противоположное. Шаг движения выбирается самостоятельно.
При однократном нажатии на клавишу 3 объект 1 должен изменить цвет (новый цвет выбирается произвольно), при повторном
нажатии цвет объекта должен восстановиться. При однократном
нажатии на клавишу 4 информация об объекте должна выводиться
в верхней строке экрана, при повторном нажатии – в нижней.
88
Таблица 3.5
Начальные координаты объектов и клавиши
для обработки событий
Номер
варианта
Начальные
координаты
объекта 1
Начальные
координаты
объекта 2
Клавиши
для обработки событий
(клавиши 1, 2, 3, 4)
1
(20,100)
(120,30)
1,2,3,Up
2
(50,50)
(30,70)
4,5,6,Left
3
(200,10)
(90,90)
7,8,9,Down
4
(30,90)
(80,30)
*,#,0,Right
5
(15,225)
(160,160)
1,3,6,Right
6
(120,180)
(10,10)
2,5,8,Down
7
(170,35)
(45,95)
0,#,9,Up
8
(60,80)
(5,5)
*,4,7,Left
9
(250,30)
(170,110)
0,1,6,Left
10
(35,55)
(115,25)
2,*,9,Up
11
(10,20)
(35,85)
3,7,#,Down
12
(5,290)
(195,240)
4,5,8,Right
13
(45,60)
(100,260)
Down,Up,0,9
14
(80,40)
(15,155)
Left,Right,1,8
15
(105,15)
(40,75)
Down,Left,2,7
16
(25,95)
(150,235)
Up,Right,3,6
17
(70,5)
(110,110)
Up,Left,4,#
18
(15,125)
(140,20)
Down,Rght,*,5
Для работы с объектами создать отдельный поток.
2. Разработать мидлет 2, внеся в мидлет 1 следующие изменения:
установить новые размеры области рисования (150 × 200 для нечетных вариантов и 200 × 150 – для четных);
• перенести точку начала координат в другую точку. Положение
новой точки выбирается произвольно.
3*. Добавить в мидлет 1 возможность определения столкновения объектов при их движении. Если необходимо, то изменить траектории движения объектов так, чтобы они пересекались. В случае
обнаружения столкновения ликвидировать оба объекта.
89
Таблица 3.6
Действия с объектами при нажатии на клавиши
Номер Действие с объек- Действие с объеквари- том 1 при нажатии том 2 при нажатии
анта
на клавишу 1
на клавишу 2
1,10
2,11
3,12
4,13
5,14
6,15
7,16
8,17
9,18
Действие с объектом при нажатии на клавишу 4
Вывод информации о координатах объекта 1
Вывод информации о назваДвижется влево Движется вверх
нии фигуры объекта 1
вывод информации о цвете
Движется влево Движется вниз
объекта 1
Вывод информации о размеДвижется влево Движется влево
рах объекта 1
Вывод информации о коордиДвижется вправо Движется вправо
натах объекта 2
Вывод информации о назваДвижется вправо Движется вверх
нии фигуры объекта 2
вывод информации о цвете
Движется вправо Движется вниз
объекта 2
вывод информации о размеДвижется вниз
Движется вниз
рах объекта 2
Вывод информации о назваДвижется вниз
Движется вверх
нии фигур двух объектов
Движется влево
Движется вправо
3.3. Содержание отчета
1. Титульный лист.
2. Цель работы.
3. Задание к лабораторной работе.
4. Листинги с кодом мидлетов 1 и 2.
5. Экранные формы с результатами работы мидлетов 1 и 2.
6*. Листинг мидлета 3.
7*. Экранная форма для мидлета 3.
8. Выводы по лабораторной работе.
90
Лабораторная работа № 4
Работа с изображениями в Java ME
Цель работы: изучение классов пользовательского интерфейса,
предназначенных для работы с изображениями, знакомство с форматом файлов.png, разработка мидлетов, формирующих модифицируемые и немодифицируемые изображения на экране.
4.1. Методические указания
Модифицируемые и немодифицируемые изображения
В Java ME можно отобразить на дисплее два типа изображений:
немодифицируемые (immutable) и модифицируемые (mutable). Немодифицируемые изображения можно загрузить из файла или другого ресурса. После того как изображение отобразится на экране,
оно не может быть изменено мидлетом. Такие изображения используются в компонентах высокоуровневого интерфейса. Модифицирумые изображения отображают на экране, используя методы
класса Graphics низкоуровневого интерфейса. После отображения
изображения на экране мидлет может перерисовать или все изображение, или его часть.
Создание изображений
Для работы с изображениями существует специальный класс
Image. В этом классе существуют следующие статические методы
для создания изображений:
• public static Image createImage(String name) – загружает изображение из файла, имя которого указывается в параметре name.
Файл должен находиться в каталоге res приложения и иметь расширение .png. Некоторые модели телефонов также поддерживают
работу с.gif и.jpg файлами. Но, для того чтобы приложение работало на разных телефонах, необходимо использовать формат PNG
(Portable Network Graphics – переносимая сетевая графика). Для
преобразования изображения из других форматов в формат PNG
можно использовать редактор Paint, программу Adobe Photoshop
и другие графические редакторы. При сохранении файла в формате PNG в программе Adobe Photoshop надо выставлять опцию
interlaced (чересстрочный). Кроме того, надо помнить, что изобра91
жения не должны быть слишком большого размера из-за ограниченной памяти телефона:
• public static Image createImage(byte[] data, int offset, int
length) – создает изображение из байтового массива данных data,
начиная с байта с индексом offset длиной length. Данные в байтовый массив могут быть занесены непосредственно в мидлете или
прочитаны из сети при взаимодействии по определенному сетевому
протоколу;
• public static Image createImage(int width, int height) – создает модифицируемое изображение высоты width пикселей и ширины height пикселей. Каждый пиксел изначально закрашен в белый
цвет. Метод используется для создания внеэкранного буфера, который можно использовать для программного создания изображения
с использованием методов рисования класса Graphics;
• public static Image createImage(Image source) – создает немодифицированную копию изображения, созданного предыдущим методом для возможного использования в высокоуровневом
API.
Для дальнейшей работы мы будем использовать изображение
из файла «wolf_400_313.png» размером 400 × 313 пикселей, приведенное на рис. 4.1. Файл размещаем в каталоге res проекта.
Вывод на экран немодифицируемых изображений
Для вывода немодифицируемого изображения на экран необходимо:
1. Создать объект класса Form.
Рис. 4.1. Исходное изображение
92
2. Создать изображение, используя метод createImage(String
name).
3. Добавить изображение на форму, используя метод append
класса Form, который также может быть использован для добавления строки текста и элементов класса Item.
4. Получить ссылку на дисплей при помощи метода getDisplay.
5. Вывести форму на экран, используя метод setCurrent.
Листинг 4.1 содержит код мидлета вывода немодифируемого
изображения на экран. Следует отметить, что при создании изображения используется конструкция try{} catch() на случай, если
файла изображения не окажется в каталог res. Результат работы
программы на экране телефона приведен на рис. 4.2. Размер картинки превышает размер экрана (320 × 240 пикселей), поэтому на
экране мы видим только часть картинки. При этом возможен вертикальный скроллинг изображения, но просмотр картинки по горизонтали невозможен. Для сокращения текста данного мидлета и,
в дальнейшем, не будем добавлять в мидлет команду завершения
приложения.
Подготовим файл изображения «wolf_200_157.png», уменьшив
размеры исходного изображения по ширине и высоте в два раза, и
поместим его в каталог res проекта. Поменяем в листинге 4.1 название файла в строке создания изображения. Результат работы приложения в этом случае будет приведен на рис. 4.3.
Листинг 4.1. Мидлет для вывода немодифицируемого изображения.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ImageMIDlet extends MIDlet
{
private Display d;
private Image im;
private Form f;
public ImageMIDlet()
{
f = new Form(«Image»);
try
{
im = Image.createImage(«/wolf_400_313.png»);
f.append(im);
}
catch(Exception ex) {}
93
d = Display.getDisplay(this);
d.setCurrent( f );
}
public void startApp() { }
public void pauseApp() { }
public void destroyApp(boolean unconditional)
}
{ }
Для вывода немодифицируемого изображения на экран можно
использовать также класс ImageItem. Для создания объекта класса
ImageItem используется следующий конструктор: ImageItem(String
label, Image image, int layout, String altText), где:
• label – метка для изображения;
• image – ссылка на объект класса Image, созданного при помощи
метода createImage();
• layout – параметр, задаваемый константой класса ImageItem
(табл. 4.1) и определяющий расположение изображения на
экране;
• altText – строка текста, высвечиваемая на месте изображения,
если изображение по какой-либо причине отсутствует.
Рис. 4.2. Отображение на экране
картинки из файла
«wolf_400_313.png»
94
Рис. 4.3. Отображение на экране
картинки из файла
«wolf_200_157.png»
Таблица 4.1
Константы класса ImageItem
Константа класса ImageItem
Описание
LAYOUT_DEFAULT
LAYOUT_LEFT
LAYOUT_RIGHT
LAYOUT_CENTER
LAYOUT_NEWLINE_BEFORE
Размещение по умолчанию
Размещение изображения слева
Размещение изображения справа
Размещение изображения по центру
Вывод новой линии до вывода изображения
LAYOUT_ NEWLINE_AFTER
Вывод новой линии после вывода изображения
Для вывода изображения на экран при этом необходимо:
1. Создать объект класса Form.
2. Создать изображение, используя метод createImage(String
name).
3. Создать объект класса ImageItem.
4. Добавить объект класса ImageItem на форму.
5. Получить ссылку на дисплей.
6. Вывести форму на экран.
Пример мидлета, иллюстрирующего работу класса ImageItem,
представлен в листинге 4.2. Результат работы приложения можно
увидеть на рис. 4.4.
Рис. 4.4. Отображение по центру экрана картинки из файла
«wolf_200_157.png»
95
Листинг 4.2. Мидлет демонстрации работы класса ImageItem.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ImageMIDlet extends MIDlet
{
private Display d;
private Image im;
private ImageItem imitm;
private Form f;
public ImageMIDlet()
{
f = new Form(«Image»);
try
{
im = Image.createImage(«/wolf_200_157.png»);
imitm = new ImageItem( «Wolf», im,
ImageItem.LAYOUT_CENTER, null );
f.append(imitm);
}
catch(Exception ex) {}
d = Display.getDisplay(this);
d.setCurrent( f );
}
public void startApp() { }
public void pauseApp() { }
public void destroyApp(boolean unconditional)
}
{ }
Выделим преимущества использования класса ImageItem:
1. Изображение можно расположить на экране в соответствии с
параметром layout (в примере картинка размещена по центру экрана).
2. К изображению можно добавить метку (в примере «Wolf»);
3. В случае отсутствия изображения на его месте будет отображен альтернативный текст (в примере это не используется и указывается параметр null).
Теперь рассмотрим вывод изображения на экран с использованием методов низкоуровневого интерфейса. Для вывода модифицируемого или немодифицируемого изображений на canvas используется метод public void drawImage(Image im, int x, int y, int anchor),
где:
• im – объект класса Image;
• x и y – координаты, используемые для определения расположения изображения на canvas;
96
• anchor – анкер, определяет точку привязки изображения к
ограничивающему прямоугольнику, внутри которого рисуется изображение. Точки привязки определяются дизъюнкцией констант
класса Graphics (рис. 4.5).
Следующий мидлет будет демонстрировать вывод на Canvas картинки из файла «wolf_400_313.png». При этом на экране можно
будет посмотреть любую часть картинки.
Для вывода изображения на canvas необходимо:
1. В основном классе мидлета создать объект класса Draw, производного от класса Canvas.
2. Получить ссылку на дисплей.
3. Отобразить объект класса Draw на экране, используя метод
setCurrent().
4. Внутри класса Draw cоздать изображение, используя метод
createImage(String name).
5. Внутри класса Draw реализовать метод paint(), в котором происходит заливка экрана белым цветом и вывод изображения на
экран при помощи метода drawImage(im, coord_x, coord_y, 0), где
переменные coord_x и coord_y определяют координаты левого верхнего угла выводимого изображения.
TOP | LEFT
TOP | HCENTER
VCENTER | LEFT
TOP | RIGHT
VCENTER | RIGHT
VCENTER | HCENTER
BOTTOM | LEFT
BOTTOM | HCENTER
BOTTOM | RIGHT
Рис. 4.5. Комбинации констант класса Graphics, определяющие привязку
изображения к ограничивающему прямоугольнику
97
6. Внутри класса Draw реализовать метод keyPressed(), который
отрабатывает нажатие клавиш «Left», «Right», «Up», «Down». По
нажатии этих клавиш происходит изменение переменных coord_x
и coord_y на пять единиц, что позволяет перемещать картинку по
экрану. Кроме того, при обработке нажатий клавиш выполняется
проверка координат, чтобы изображение не выходило за пределы
экрана. Для перерисовки изображения вызывается метод repaint().
Код мидлета приведен в листинге 4.3. Каждый класс содержится в
отдельном файле – ImageMIDlet.java и Draw.java. Результат работы
мобильного приложения после ряда нажатий на клавиши-стрелки
приведен на рис. 4.6.
Листинг 4.3. Мидлет для просмотра большого изображения.
Файл ImageMIDlet.java:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ImageMIDlet extends MIDlet
{
private Draw dr;
private Display d;
public ImageMIDlet()
{
dr = new Draw();
d = Display.getDisplay( this );
d.setCurrent( dr );
}
public void startApp() { }
public void pauseApp() { }
public void destroyApp(boolean destroy) { }
}
Файл Draw.java:
import javax.microedition.lcdui.*;
import java.io.IOException;
public class Draw extends Canvas
{
private int
coord_x = 0,
coord_y = 0;
private Image im;
public Draw()
{
super();
try
{
98
im = Image.createImage(«/wolf_400_313.png»);
}
catch( IOException ioe )
{ System.out.println( ioe.getMessage() );
}
}
public void paint( Graphics g )
{
g.setColor( 0xFFFFFF ); // white color
g.fillRect( 0, 0, g.getClipWidth(), g.getClipHeight() );
g.drawImage( im, coord_x, coord_y, 0 );
}
protected void keyPressed( int keyCode )
{
int code = getGameAction( keyCode );
switch( code )
{
case UP: if( coord_y – 5 + im.getHeight() > getHeight() )
coord_y -= 5; break;
case LEFT: if( coord_x – 5 + im.getWidth() > getWidth() )
coord_x -= 5; break;
case RIGHT: if( coord_x < 0 ) coord_x += 5; break;
case DOWN: if( coord_y < 0 ) coord_y += 5; break;
default:
break;
}
repaint();
}
}
Рис. 4.6. Результат работы мидлета
с возможностью перемещения картинки по экрану
99
Класс Graphics cодержит также метод void drawRegion(Image
src, int x_src, int y_src, int width, int height, int transform,
int x_dest, int y_dest, int anchor) для вывода части (региона)
изображения на Canvas, где параметры x_src, y_src, width и height
определяют прямоугольный регион изображения для отображения на экране. Регион будет отображен на экране согласно координатам x_dest, y_dest и параметру размещения anchor. Кроме
того, параметр transform позволяет задавать поворот изображения
на 90, 180 или 270°, а также зеркальное отображение изображения с последующим поворотом на такие же углы, используя константы класса Sprite. Класс Sprite используется для анимации и в
данной лабораторной работе не рассматривается. Для иллюстрации использования метода drawRegion изменим файл Draw.java из
листинга 4.3:
• добавим строку import javax.microedition.lcdui.game.*, так как
в этом пакете определен класс Sprite;
• заменим в методе paint вызов метода drawImage на вызов метода
drawRegion;
• исключим из класса Draw метод keyPressed(), так как нет необходимости в перемещении картинки по экрану. Модифицированный
файл Draw.java представлен в листинге 4.4. Результат работы приложения, использующего метод drawRegion, приведен на рис. 4.7.
Параметры вывода изображения подобраны так, чтобы на экране
Рис. 4.7. Результат работы мидлета, использующего метод drawRegion
100
отображался его фрагмент с волчьей мордой. Обратите внимание,
что изображение выводится по центру экрана за счет использования комбинации констант Graphics.HCENTER | Graphics.VCENTER.
Листинг 4.4. Использование метода DrawRegion.
Файл Draw.java:
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import java.io.IOException;
public class Draw extends Canvas
{
private int
coord_x = 0, coord_y = 0;
private Image im;
public Draw()
{
super();
try
{
im = Image.createImage( «/wolf_400_313.png» );
}
catch( IOException ioe )
{ System.out.println( ioe.getMessage() );
}
}
public void paint( Graphics g )
{
g.setColor( 0xFFFFFF ); // white color
g.fillRect( 0, 0, g.getClipWidth(), g.getClipHeight() );
g.drawRegion( im, 250, 70, 120, 140, Sprite.TRANS_NONE,
getWidth()/2,getHeight()/2, Graphics.HCENTER | Graphics.VCENTER
);
}
}
Следующий пример демонстрирует вывод картинки с использованием различных значений параметра anchor метода drawImage.
В листинге 4.5 приведен файл класса Draw, где изображение из файла «/wolf200_157.png» выводится в левой части экрана при нажатии на клавишу «0», по центру при нажатии на клавишу «2» и
в правой части экрана при нажатии на клавишу «1», что определяется соответствующей комбинацией констант. Перед выводом
изображения экран предварительно окрашивается в черный цвет.
Экранные формы, иллюстрирующие работу мобильного приложения, показаны на рис. 4.8.
101
102
Рис. 4.8. Отображение картинки в различных местах экрана
Листинг 4.5. Вывод изображения в разных частях экрана.
Файл Draw.java:
import javax.microedition.lcdui.*;
import java.io.IOException;
public class Draw extends Canvas
{
private int
anchor = 0;
private Image im;
public Draw()
{
super();
try
{
im = Image.createImage(«/wolf_200_157.png»);
}
catch( IOException ioe )
{ System.out.println( ioe.getMessage() );
}
}
public void paint( Graphics g )
{
g.setColor( 0 ); // black color
g.fillRect( 0, 0, getWidth(), getHeight() );
switch( anchor ) {
case 0: g.drawImage( im, 0, 0, Graphics.TOP | Graphics.LEFT );
break;
case 1: g.drawImage( im, getWidth(), getHeight(),
Graphics.BOTTOM | Graphics.RIGHT ); break;
case 2: g.drawImage( im, getWidth()/2, getHeight()/2,
Graphics.VCENTER | Graphics.HCENTER ); break;
default: break;
}
}
protected void keyPressed(
{
switch( keyCode )
{
case KEY_NUM0: anchor
case KEY_NUM1: anchor
case KEY_NUM2: anchor
default:
break;
}
repaint();
}
int keyCode )
= 0; break;
= 1; break;
= 2; break;
}
103
Вывод на экран модифицируемых изображений
При создании модифицируемого изображения можно использовать методы класса Graphics, чтобы сначала рисовать картинку во
внеэкранном буфере, а потом копировать результат рисования из
буфера на экран.
Алгоритм создания модифицируемого изображения
1. Создать объект класса Image, используя метод createImage
(width,height), шириной width пикселей и высотой height пикселей. Объект имеет по умолчанию координаты левого верхнего угла
экрана. Все пиксели окрашены в белый цвет.
2. Получить объект класса Graphics, используя метод public
Graphics getGraphics(). Этот объект имеет координаты левого верхнего угла изображения, изначально закрашенного в белый цвет. По
умолчанию для дальнейшего рисования задается черный цвет.
3. Нарисовать элементы изображения в буфере, используя методы класса Graphics.
4. Скопировать изображение из буфера на canvas, используя метод drawImage().
Этот алгоритм – алгоритм двойной буферизации, так как рисование происходит во внутреннем внеэкранном буфере и потом копируется на экран. Для мобильных устройств, которые не поддерживают двойную буферизацию, этот алгоритм может улучшить восприятие изображения на экране, скрывая весь процесс рисования,
и отображая только конечную картинку. Недостатком алгоритма
являются большие затраты памяти, чем при прямом отображении
изображения на экран.
Пример. Нарисуем модифицируемое изображение волчка
размером 32 × 32 пикселей. Для удобства можно построить матрицу пикселей, отображающую каждый пиксел изображения
(рис. 4.9). Формируемую картинку можно составить из прямоугольников разного цвета: 1 – красного (red), 2 – синего (blue), 3 –
желтого (yellow), 4 – зеленого (green) и 5 – малинового (magenta)
цветов. Для их отображения используем метод fillRectangle,
предварительно выставляя требуемый цвет окраски. Добавим
команду «See» для создания копии немодифицируемого изображения из модифицируемого, используя метод public static Image
createImage(Image source) с дальнейшим добавлением немодифицируемого изображения на форму.
104
1(red)
4(green)
2(blue)
3(yellow)
5(magenta)
3(yellow)
2(blue)
1(red)
4(green)
Рис. 4.9. Матрица пикселей для изображения
Код мидлета представлен в листинге 4.6. В файле ImageMIDlet.
java из листинга 4.3 изменим конструктор, передав в класс Draw
ссылку на дисплей. Это необходимо, так как в классе Draw происходит обработка команды «See» и отображение формы на экране.
В классе Draw создаем модифицируемое изображение im, используя вышеописанный алгоритм. В методе commandAction() выполняются действия по команде «See»: создается немодифицируемое
изображение im1 и добавляется на форму. Модифицируемое изображение в методе paint() рисуется по центру экрана, а немодифици-
Рис. 4.10. Вывод модифицируемого и немодифицируемого изображений
105
руемое изображение с меткой Image – в левом верхнем углу экрана
(рис. 4.10).
Листинг 4.6. Вывод модифицируемого и немодифицируемого
изображений.
public ImageMIDlet()
{
d = Display.getDisplay( this );
dr = new Draw( d );
d.setCurrent( dr );
}
Файл Draw.java:
import javax.microedition.lcdui.*;
public class Draw extends Canvas implements CommandListener
{
private Image im, im1;
private Command seeImage;
private Form f;
private Display d;
public Draw( Display disp )
{
super();
d = disp;
seeImage = new Command( «See», Command.SCREEN, 1 );
f = new Form(«Image»);
addCommand( seeImage );
setCommandListener( this );
}
public void commandAction( Command c, Displayable s )
{
if( c == seeImage )
{
im1 = Image.createImage( im );
f.append( im1 );
d.setCurrent( f );
}
}
public void paint( Graphics g )
{
int width = 32, height = 32;
int w = 4, x = 14, y1 = 2, y2 = 26;
// w – red rectangle width
// (x,y1) – top red rectangle coordinates
// (x,y2) – bottom red rectangle coordinates
106
g.setColor(0xFFFFFF);
g.fillRect( 0, 0, getWidth(), getHeight() );
im = Image.createImage( width, height );
Graphics img = im.getGraphics();
}
}
img.fillRect( 0, 0, width, height );
// fill by black color
img.setColor(0xFF0000); // red rectangles
img.fillRect(x,y1,w,3);
img.fillRect(x,y2,w,3);
img.setColor(0x0000FF); // blue rectangles
img.fillRect(x-3,y1+3,w+6,3);
img.fillRect(x-3,y2-3,w+6,3);
img.setColor(0xFFFF00); // yellow rectangles
img.fillRect(x-6,y1+6,w+12,3);
img.fillRect(x-6,y2-6,w+12,3);
img.setColor(0x00FF00); // green rectangles
img.fillRect(x-9,y1+9,w+18,3);
img.fillRect(x-9,y2-9,w+18,3);
img.setColor(0xFF00FF); // magenta rectangle
img.fillRect(x-12,y1+12,w+24,3);
g.drawImage(im, getWidth()/2, getWidth()/2,
Graphics.HCENTER | Graphics.VCENTER);
4.2. Задание к лабораторной работе
1. Получить у преподавателя файл изображения в формате
JPG.
2. Создать два файла в формате PNG. Первый – full.png (полного
размера), второй – half.png (1/2 от полного размера).
3. Написать мидлет 1, использующий класс ImageItem и выводящий изображение из файла half.png на экран, в соответствии с параметром layout (табл. 4.2).
Таблица 4.2
Параметр layout
Номер варианта
1, 6, 11, 16, 21
2, 7, 12, 17, 22
3, 8, 13, 18, 23
4, 9, 14, 19, 24
5, 10, 15, 20, 25
Параметр layout
LAYOUT_LEFT
LAYOUT_RIGHT
LAYOUT_CENTER
LAYOUT_NEWLINE_BEFORE
LAYOUT_ NEWLINE_AFTER
107
4. Составить мидлет 2, отображающий на экране изображение
из файла full.png на экран, с возможностью просмотра любой части
картинки.
5. Разработать мидлет 3, выводящий на экран фрагмент изображения из файла full.png, заданный преподавателем. Фрагмент вывести в различные места экрана (табл. 4.3) в зависимости от параметра anchor при нажатии на одну из трех клавиш.
6. Написать мидлет 4, отображающий на экране модифицируемое изображение, заданное преподавателем, в соответствии с параметром anchor (табл. 4.4).
7. Проверить работу мидлетов 1–4 на реальных мобильных телефонах.
8*. Составить мидлет 5 для реализации на экране графического
меню, использующего кнопки в виде картинок вместо стандартных
строк меню в классах List и ChoiceGroup.
Таблица 4.3
Параметр anchor для пункта 5 задания
Параметр anchor
Номер варианта
1, 10, 19
2, 11, 20,
3, 12, 21
4, 13, 22
5, 14, 23
6, 15, 24
7, 16, 25
8, 17
9, 18
TOP|LEFT, VCENTER|LEFT, BOTTOM|RIGHT
TOP|RIGHT, VCENTER|HCENTER, BOTTOM|LEFT
TOP|LEFT, TOP|HCENTER, TOP|RIGHT
VCENTER|LEFT, VCENTER|RIGHT, VCENTER|HCENTER
BOTTOM|LEFT, BOTTOM|RIGHT, BOTTOM|HCENTER
TOP|HCENTER, VCENTER|HCENTER, BOTTOM|HCENTER
TOP|RIGHT, VCENTER|RIGHT, BOTTOM|RIGHT
TOP|LEFT, VCENTER|LEFT, BOTTOM|LEFT
BOTTOM|LEFT, VCENTER|RIGHT, TOP|HCENTER
Таблица 4.4
Параметр anchor для пункта 6 задания
Номер варианта
1, 10, 19
2, 11, 20,
3, 12, 21
4, 13, 22
5, 14, 23
6, 15, 24
7, 16, 25
8, 17
9, 18
108
TOP|LEFT
TOP|RIGHT
TOP|HCENTER
VCENTER|LEFT
VCENTER|RIGHT
VCENTER|HCENTER
BOTTOM|LEFT
BOTTOM|RIGHT
BOTTOM|HCENTER
Параметр anchor
4.3. Содержание отчета
1. Титульный лист.
2. Цель работы.
3. Задание к лабораторной работе.
4. Изображения, хранящиеся в файлах full.png и half.png.
5. Модифицируемое изображение в виде матрицы пикселей для
мидлета 4.
6. Листинги с кодами мидлетов 1–4.
7. Экранные формы с результатами работы мидлетов 1–4.
8*. Листинг с кодом мидлета 5.
9*. Экранные формы для мидлета 5.
10. Выводы по лабораторной работе.
109
Библиографический список
1. Горнаков С. Г. Программирование мобильных телефонов на
Java 2 Micro Edition. М.: ДМК Пресс, 2008. 512 с.: ил.
2. Монахов В. Язык программирования Java и среда NetBeans.
СПб.: БХВ-Петербург, 2011. 704 с.
3. Пирумян В. Платформа программирования Java2ME для портативных устройств: пер. с англ. М.: КУДИЦ-ОБРАЗ, 2002. 352 с.
4. Буткевич Е. Л. Пишем программы и игры для сотовых телефонов. СПб.: Питер, 2006. 204 с.
5. Topley K. J2ME in a Nutshell. First Ed. O’Reilly Media, 2002.
480 c.
Интернет-ресурсы
http://www.java.sun.com
http://www.juga.ru
http://www.mobilab.ru
110
Содержание
Предисловие..................................................................... 3
Лабораторная работа № 1. Разработка мобильного
приложения на платформе Java ME...................................... 4
Лабораторная работа № 2. Высокоуровневый программный
интерфейс в Java ME.......................................................... 28
Лабораторная работа № 3. Низкоуровневый программный
интерфейс в Java ME.......................................................... 69
Лабораторная работа № 4. Работа с изображениями в Java ME. 91
Библиографический список................................................. 110
Интернет-ресурсы.............................................................. 110
111
Учебное издание
Марковский Станислав Георгиевич
Марковская Наталья Владимировна
ПРОГРАММИРОВАНИЕ ПРИЛОЖЕНИЙ
ДЛЯ МОБИЛЬНЫХ УСТРОЙСТВ
Лабораторный практикум
Редактор Г. Д. Бакастова
Верстальщик С. Б. Мацапура
Сдано в набор 30.05.11. Подписано к печати 04.07.11.
Формат 60×84 1/16. Бумага офсетная. Усл. печ. л. 6,51.
Уч.-изд. л. 6,90. Тираж 100 экз. Заказ № 309.
Редакционно-издательский центр ГУАП
190000, Санкт-Петербург, Б. Морская ул., 67
Документ
Категория
Без категории
Просмотров
7
Размер файла
2 929 Кб
Теги
markovskij1
1/--страниц
Пожаловаться на содержимое документа