Е. Буткевич Пишем программы и игры



страница8/15
Дата22.06.2019
Размер2.79 Mb.
ТипКраткое содержание
1   ...   4   5   6   7   8   9   10   11   ...   15
Глава 8. Стандартные средства пользовательского интерфейса

// создать новое меню

menu = new ListC",List.IMPLICIT.menuOptions.null);

// создать команду выбора пункта меню

ok = new Command("Ok". Command.OK. 1);

// добавить команду в меню

menu.addCommand(ok);

// установить блок прослушивания команд для меню

menu. setCommandListener(t his);

// получить ссылку на менеджер дисплея

display = Display.getDisplay(this):

// отобразить меню на экране

display.setCurrent(menu):



|#(l)«o(tia 7210 SDK: -::.^;\\

ggra

;Йе Tools ■ Hetp ■' ' :;;"/;; ':■} '' ■

•■

I

ГЧ1ОЮА




a-— "—"i




iNewGame




i Set Level ! High Score

L




ш^ ' i

pt «,.«3» Ж



: I .SL «a» M

ВРИ

I







Чтобы откомпилировать и посмотреть, что у нас получилось, нужно реализовать метод commandAction, представляющий блок прослушивания команд. Этот метод и будет предписывать те или иные действия в зависимости от выбранного пункта меню. Пока что можно оставить его пустым, откомпилировать приложение и по­смотреть, как выглядит меню на экране телефо­на (рис. 8.1).

Итак, мы видим на экране аппарата строки, пред­ставляющие пункты меню, заданные нами в мас­сиве menuOptions. Один из пунктов подсвечен си­ней полоской. Одна из функциональных клавиш связана с командой Ok, при нажатии на которую, правда, пока что ничего не происходит.

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

Обратить внимание следует на логику смены эк­


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

Класс SnakeGame 89

private void showNewScreen(String title. Command с Item item) {



II создать форму для нового экрана

Form newScreenForm = new Form(title):

// добавить команду для возврата из формы

newScreenForm.addCommand(c);

// добавить элемент в форму

newScreenForm.append( item);

// установить блок прослушивания команд

newScreenForm.setCommandListener(this);

// отобразить форму на экране

display. setCurrentCnewScreenForm); }

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

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

private byte getParameter(int index) { II массив параметров игры

byte buff[] = {0.0}:



try {

// открыть хранилище записей с именем "SNAKE" RecordStore recordStore = RecordStore.openRecordStore

("SNAKE", true);

// получить список записей хранилища RecordEnumeration re = recordStore.enumerateRecords

(null. null. false); // если хранилище не пусто if (re.numRecordsO!=0) {

// получить id и считать запись параметров игры buff • recordStore.getRecord(re.nextRecordldO):

} ) catch(RecordStoreException rse) {

I

// вернуть параметр



return buff[index]; 1

Перейдем к блоку прослушивания команд, который, собственно, и будет дири­жировать нашей программой и предписывать действия в зависимости от выб­ранного пункта меню. В обязательном к реализации методе commandAction есть два входных параметра, которые определяют вызванную команду и отобража­емый экран, из которого была вызвана команда. В зависимости от этих парамет-



90 Глава 8. Стандартные средства пользовательского интерфейса

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

public void comma ndAct i on ( Com(nand c. Displayable d) { // если была команда Ok из главного меню игры if (с — ok && d == menu) {

// получить выбранный пункт меню • int selIndex = menu.getSelectedlndexO; switch(se1Index) {

// первый пункт меню - новая игра case 0 :

// создать обьект змейки

curSnake = new SnakeO;

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

Thread moveThread = new Thread(curSnake):

//начать выполнение треда

moveThread. start()

// отобразить змейку на экране

display.setCurrent(curSnake);

break:

// второй пункт меню -установить уровень сложности case 1 :

// массив строк с названиями пунктов меню

String levelOptions[] = {"Level 1","Level 2". "Level 3". "Level 4"}:

// создать меню выбора уровня игры

levelChoice =

new ChoiceGroupt"".List.EXCLUSIVE,1evelOptions. nul1):

// выделить пункт меню

// соответствующий текущему уровню сложности

level Choice.setSelectedIndex(5-getParameter(l).true):

// отобразить новую(форму

showNewScreenC 'Set Level". set.level Choice):

break;

// третий пункт меню - посмотреть текущий рекорд case 2 :



// получить строку с текущим рекордом

String strScore = (new Integer(getParameter(0))) .toString();

// создать объект элемента-строки

Stringltem highScoreltem = new StringltemC".strScore);

// отобразить новую форму

showNewScreenC'HIGH SCORE" .ok, highScoreltem):

break:

II если была команда Ok. вызванная из формы if(c==ok && d!=menu)

Класс SnakeGame

91







// отобразить на экране стартовое меню display.setCurrent(menu):

Рис. 8.2. Демонстрация наилучшего результата

Итак, как мы видим из кода, меню установки уровня сложности представлено объектом клас­са Choi ceGroup, который принадлежит к иерархии класса Item, поэтому он может быть отображен с помощью формы. На этом примере мы наглядно видим использование полиморфизма объектно-ориентированного языка: метод showNewScreen при­нимает в качестве одного и того же аргумента раз­личные объекты классов Choi ceGroup и String ltem, порожденных одним классом Item. Из собственного опыта у меня сформировался следующий подход к программированию: при добавлении любой новой функциональности сто­ит запустить программу и убедиться, что все ра­ботает корректно. Такой подход позволяет вов­ремя отследить допущенные просчеты и ошибки. Именно поэтому рекомендую не пытаться напи­сать сразу всю программу целиком, чтобы потом ломать голову, где же в этой куче кода была до­пущена ошибка, а продвигаться от главы к главе постепенно. Это не детектив, чтобы заглядывать в конец книжки: кто же убийца? Полный листинг программы в конце приведен не для бездумного переписывания, а для дополнительного контро­ля и помощи в поиске ошибок. Для того чтобы откомпилировать и запустить программу на данном этапе, требуется несколь­ко дополнительных штрихов. Первое: требуется импортировать необходимые пакеты, классы которых мы будем использовать:

import javax.microedition.lcdui.Form; import javax.microedition.lcdui.Item; import javax.microedition.lcdui.ChoiceGroup; import javax.microedition.lcdui.Stringltem;

Второе: в классе SnakeGame мы завели два новых поля для реализации меню выбо­ра уровня игры:

private ChoiceGroup TevelChoice: // меню выбора уровня сложности игры
private Command set: // команда выбора уровня сложности игры

В стартовом методе мидлета startAppC) создадим объект команды выбора уровня сложности игры:

set = new Command("Set". Command.BACK, 1);

Вот теперь можно запустить игру. Обратите внимание, что обработка команды set в блоке прослушивания команд еще не реализована, поэтому пока что удов­летворимся просмотром текущего рекорда (рис. 8.2).



92 Глава 8. Стандартные средства пользовательского интерфейса

При нажатии функциональной клавиши формируется команда Ok, и приложение снова демонстрирует на экране стартовое меню. Выглядит это все, конечно, не очень презентабельно, что обусловлено ограниченностью возможностей формы. Например, наложить текст на картинку мы не сможем при всем желании. Так что в качестве самостоятельной работы можете попробовать использовать вместо формы класс, порожденный от класса Canvas. В методе paint можно будет нарисо­вать все, что душе угодно, а возврат в основное меню отработать с помощью мето­да keyPressed.

Однако не будем отвлекаться и допишем в блоке прослушивания команд обра­ботку команды set, где получим выбранный уровень сложности и запишем его в хранилище записей: if(с — set) { try {

// массив параметров игры

byte buff[] - {0.5}:

II открыть хранилище записей с именем "SNAKE"

RecordStore recordStore = RecordStore.openRecordStore

("SNAKE", true);

// получить список записей хранилища RecordEnumeration re - recordStore.enumerateRecords

(null. null. false); // если хранилище не пусто if (re.numRecords() !=0) {

// получить id записи параметров игры int id - re.nextRecordldO; // считать запись с параметрами игры buff = recordStore.getRecord(id); // вычислить текущий уровень игры buff[l] - (byte)(5 - level Choi ce.getSelectedlndexO); // записать параметры игры recordStore. setRecorddd, buff .0.2): ) else {

// добавить новую запись параметров игры recordStore.addRecord(buff. 0. 2):

) } catch(RecordStoreException rse) {

}

// отобразить на экране стартовое меню

di splay.setCurrent(menu); }

Теперь все пункты стартового меню полностью соответствуют заявленным дей­ствиям. Попробуем, как работает меню выбора уровня сложности игры (рис. 8.3).

В данном случае мы использовали режим EXCLUSIVE, поэтому меню отличается от стартового внешним видом. Команда Select появилась автоматически и отвечает за выделение одного из пунктов меню точкой, так как перемещение подсвеченной

Класс Gauge

93







синей полоски по пунктам не приводит к выде­лению одного из них. Реализованная нами ко­манда Set вызывает запись нового уровня слож­ности, который учитывается при запуске новой игры. Теперь каждый может задать свой соб­ственный темп, что только добавит увлекатель­ности нашей игре.

о Level Z о Level 3

©Level 4

Класс Gauge

Благодаря гибкой реализации и полиморфиз­му, можно легко поменять реализацию выбора сложности игры, используя, например, не меню выбора ChoiceGroup, а шкалу Gauge. Шкала так­же принадлежит иерархии класса Item, поэто­му метод showNewScreen изменять не потребует­ся. Внешний вид шкалы, как и всех объектов пользовательского интерфейса высокого уров­ня, зависит от конкретной модели телефона. Например, в стандартном цветном эмуляторе шкала будет выглядеть так (рис. 8.4).

Здесь мы видим привычные глазу прямоуголь­нички, меняющие цвет в зависимости от выбо­ра. У разработчиков корпорации Nokia свое ви­дение шкалы, поэтому то же самое на эмуляторе Nokia 7210 будет выглядеть следующим образом (рис. 8.5).


Рис. 8.З. Меню выбора уровня сложности

Изменить внешний вид этого элемента у нас нет никакой возможности, поэтому придется до­вольствоваться имеющимися методами:

Gauge(String label, boolean interactive, int maxValue,

int initialValue) — конструктор класса Gauge. Создает шкалу с заголовком 1abel и возможным диа­пазоном значений от 0 до maxValue. Значение по умолчанию выставляется рав­ным параметру 1initial Value. Если параметр interactive имеет значение true, то значение шкалы можно изменять, иначе, как в стрип-клубе: смотреть — мож­но, трогать — нельзя;

int getMaxValue() — возвращает максимально возможное значение шкалы; int getValue() - возвращает текущее значение шкалы;

boolean isInteractiveO — возвращает значение true, если пользователь может

изменять значение шкалы;

void setLabel (String label) —устанавливает новый заголовок шкалы;

void setMaxValuednt maxValue) — устанавливает новое максимально возмож­ное значение шкалы;

void setValueCint value) — возвращает выбранное пользователем значение шкалы.


94

Глава 8. Стандартные средства пользовательского интерфейса









#(1) Nokia 72 10SDK







Рис. 8.4. Шкала в стандартном эмуляторе

Рис. 8.5. Шкала на эмуляторе Nokia 7210



Последний штрих для полного счастья — заставка, которая будет выводиться пе­ред запуском игры. Сохраним картинку для заставки в файле title.png и добавим в стартовом методе приложения startAppC) следующий код:

Image title = null; try {

// создать объект заставки

title - Image.createlmageC'/title.phg"); ) catch (IOException ioe) {} // создать новый элемент формы

Imageltem item - new ImageltemC". title. Imageltem. LAYOUT_CENTER,""); // отобразить заставку showNewScreent "SNAKE" ,ok ,item) ;

Для отображения заставки мы воспользовались все тем же универсальным мето­дом showNewScreen, который в качестве аргумента принимает объект класса Imageltem, содержащий картинку (рис. 8.6).

Вот теперь точно — все!


Класс Gauge

95



* * *

В этой главе мы разобрались с организацией меню с помощью пользовательского интерфей­са высокого уровня. На этом наше знакомство с компонентами интерфейса высокого уровня не заканчивается. Мы еще вернемся к некоторым из них в других примерах. Лучше всего такие вещи усваиваются на практике: почитал — сра­зу реализовал — и почувствовал силу в руках.

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


ГЯП2




■ Г-lxl




I







В-—*™-SNAKE——

11

1

a jf а к в




1

Oc |










I




^ i

Рис. 8.6. Теперь у игры есть даже заставка

Глава 9

Организация потоков, работа с файлами

Надеюсь, что вы старательно выполняете самостоятельные работы и к моменту чтения этой главы уже смогли похвастаться перед друзьями своими руками со­творенной «Змейкой». В этой игре мы выводили на экран, главным образом, картинки, графику и прочую визуализацию, которую приложение считывало из файлов-ресурсов. Ресурсами в этом случае являлись картинки в определенном, воспринимаемом телефоном, формате. На самом же деле ресурсами могут яв­ляться не только картинки. Любая информация в самом разнообразном виде может храниться в файле-ресурсе. Каким образом информация из файла title.png превратилась в картинку на экране мобильника, осталось для нас за кадром: мы просто вызвали метод createlmage и получили готовый объект Image. В этой гла­ве мы рассмотрим подробнее, что такое потоки, как работать с файлами-ресур­сами и как организовать процедуру чтения из файла.

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

Класс InputStream

Связь между источником данных и приложением осуществляется с помощью объекта класса InputStream, который можно сравнить с трубой, пропускающей че­рез себя поток данных. Класс InputStream является базовым для всех классов вво­да и предоставляет основные методы работы с потоком ввода:



  • i nt read О) — прочитать следующий байт из потока данных. Эта функция явля­
    ется абстрактной, то есть в любом классе-потомке обязательна ее реализация;

  • int read(byte[] b) — считать данные из потока в буфер. Функция читает все
    доступные данные, ограничиваясь размером буфера, и возвращает количество
    прочитанных байт;

  • int read(byte[] b. int off, int l en) —считать данные длины len из потока
    данных и разместить их в буфере, начиная с позиции off;

  • int avaiIabiе() — возвращает количество байт, доступных для чтения в данном
    потоке;

Класс InputStream 97

  • void mark(int readi imit) — помечает текущую позицию в потоке данных с це­
    лью предоставления возможности повторного чтения с этой позиции. Аргу­
    мент указывает, сколько байт может быть прочитано, прежде чем метка станет
    недействительной;

  • boolean markSupportedO) — проверка возможности повторного чтения данных
    с помеченной позиции. Возвращает true, если позиция была задана и число
    прочитанных после этого данных не превысило лимита;

  • void reset О — возвращает поток данных в состояние, сохраненное при послед­
    нем вызове функции mark;

  • 1ong skip(1ong n) — пропустить п байтов данных потока. Возвращает реальное
    количество пропущенных байт;

  • void close() — закрывает поток и освобождает все используемые им ресурсы.

Следует отметить, что в базовом классе InputStream такие функции, как avai I ablе, mark, reset, работать не будут. Они объявлены для последующей реализации в классах-потомках, а пока что не выполняют никаких действий и возвращают нулевое значение.

Рассмотрим использование класса InputStream на простом примере вывода текста из файла на экран телефона. Поместим текстовый файл pushkin.txtв папку ресур­сов приложения /res. Чтобы связать ресурс с потоком, воспользуемся методом getResourceAsStream(String name) класса Cl ass. Затем с помощью метода потока read считаем содержимое файла и поместим его на форму, связанную с экраном. При­мер кода будет выглядеть так:



import java.io.InputStream; import java.io.IOException;

Form form = new FormO :;

Display display = Display. getDisplay(this):

// связать файл с потоком is

InputStream is = getClass0. getResourceAsStreamC7pushkin.txt"): byte[] bArr - new byte[150]; try {

is.read(bArr): // считать содержимое потока в массив байт catchUOException e) { }

// сформировать строку из массива байт String str = new String(bArr);

form.append(str) ; // поместить строку в форму display.setCurrent(form); // отобразить форму на экране

Запускаем приложение в стандартном эмуляторе из WTK и получаем вот такой замечательный результат (рис. 9.1).

Эмулятор справился с заданием на твердую пятерку: навигацию нам реализовала форма, стрелочки перематывают текст вниз и вверх, на экране не появляется ника-

98


Каталог: Техника -> Информационные%20технологии
Информационные%20технологии -> Методические рекомендации по построению систем защиты узлов интернет 1 требования к системе защиты узла интернет 2
Техника -> Учебная программа для специальности: 1-23 01 73 Средства массовой информации
Техника -> Ремонт китайских телефонов
Техника -> Для профилактики и лечения насморка Зачем промывать нос во время насморка?
Техника -> Учебная программа для специальности: 1-23 01 73 Средства массовой информации


Поделитесь с Вашими друзьями:
1   ...   4   5   6   7   8   9   10   11   ...   15


База данных защищена авторским правом ©vossta.ru 2019
обратиться к администрации

    Главная страница