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


Глава 4 Работа с графикой



страница4/15
Дата22.06.2019
Размер2.79 Mb.
ТипКраткое содержание
1   2   3   4   5   6   7   8   9   ...   15
Глава 4

Работа с графикой

В прошлой главе мы рассмотрели пример работы с пользовательским интерфейсом высокого уровня, который представлен иерархией класса Screen. При работе с объектами такого типа мы не имели прямого доступа к экрану аппарата, а пользова­лись форм ой как визуальной абстракцией высокого уровня. Изменения изображе­ния на экране осуществлялись с помощью методов формы и добавленных в нее объектов. То есть, работая с высокоуровневым интерфейсом, при всем желании нарисовать поперек экрана, например, жирную синюю полосу мы не сможем. Решить проблему непосредственного доступа к экрану нам поможет низкоуров­невый пользовательский интерфейс, который представлен второй веткой иерар­хии отображаемых объектов типа Displayable — классом Canvas.



Класс Canvas

Класс Canvas является абстрактным. Это значит, что мы не можем просто создать объект этого класса. Если все же попытаться создать такой объект, то компилятор подтвердит вышесказанное вот такими словами:

javax.microedition.lcdui .Canvas is abstract; cannot be instantiated Canvas с = newCanvasO:

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

В классе Canvas абстрактным является метод abstract void paintCGraphicsg), кото­рый отвечает за перерисовку экранаи получает в качестве аргумента объект клас­са Graphics, который создается автоматически при инициализации объекта Canvas.

Класс Graphics

Собственно класс Graphics и предоставляет возможности низкоуровневого гра­фического рисования. Возможности класса Graphics далеко не безграничны: он содержит методы для рисования и заливки базовых геометрических фигур, таких как линии, прямоугольники идуги. Также поддерживаются возможности отобра­жения текстовых символов и смены цвета для рисования.



Класс Graphics 43

Теперь все в наших руках, включая и все точки экрана, каждая из которых, кста­ти, имеет свои координаты по осям х и у. Начало координат (точка 0,0) находится в левом верхнем углу экрана. То есть нужно учесть, что ось у направлена вниз.

А теперь перейдем к рисаванию и рассмотрим методы класса Graphics, которые могут нам понадобиться. В первую очередь заметим, что размеры экрана у разных моделей могут серьезно различаться, поэтому сразу будем писать транспортабель­ные приложения. Таким образом, первым делом нам требуется получить размеры экрана конкретного аппарата. Делается это с помощью двух методов:


  • int getCl ipHeightO) — возвращает высоту текущей области для рисования;

  • int getClipWidth() — возвращает ширину текущей области для рисования.
    Сам класс Canvas также содержит методы для определения размеров отобража­
    емой области экрана, которые не зависят от текущей области для рисования
    и остаются неизменными во время работы приложения:




  • int getHeight() — возвращает высоту отображаемой области экрана;

  • int getWidthC) — возвращает ширину отображаемой области экрана.

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

■ void setClip(int x. inty. int width, int height) — устанавливает новую прямо­


угольную область рисования с левым верхним углом в точке (х, у), высотой
height и шириной width пикселов.

Иногда удобно сместить начало координат из левого верхнего угла в более удоб­ное место. Делается это с помощью метода void translate(int x. int у), который переносит начало координат в точку с координатами (х, у). Получить текущее положение начала координат относительно левого верхнего угла можно следу­ющими методами: int getTranslateXO и int getTranslateYO. После того как мы определились с областью для рисования и началом координат, рассмотрим несколько методов для отображения на экране базовых геометриче­ских фигур:



  • voiddrawLinednt xl, intyl, int x2. inty2) — рисует линию из точки с коорди­
    натами (Ж,,у,) в точку с координатами (х.22). В классе Graphics нет метода для
    рисования одной точки, поэтому отдельная точка рисуется с помощью линии,
    начало и конец которой заданы одними и теми же координатами;

  • void drawRect(int x. inty, intwidth, int height) — рисует прямоугольник с ле­
    вым верхним углом в точке (х, у), шириной width и высотой height пикселов;

  • voiddrawRoundRect(intx. inty. intwidth, int height, intarcWidth, intarcHeight) —
    рисует прямоугольник с закругленными углами. Первые четыре аргумента
    аналогичны аргументам предыдущего метода, acrWidth задает диаметр закруг­
    ляющей дуги вокруг оси х, arcHeight задает диаметр закругляющей дуги вок­
    руг оси у;

ш void drawArc(int x, inty, intwidth. int height, int startAngle. int arcAngle) — рисует дугу, вписанную в прямоугольник с левым верхним углом в точке с координатами (х,у). Параметр startAngle задает угол, с которого будет начи-

44 Глава 4. Работа с графикой

наться дуга, а параметр arcAngl e задает угловое расстояние, на которое будет простираться дуга. Углы задаются в градусах. Таким образом, чтобы нарисо­вать окружность, нужно в квадрат вписать дугу с угловым расстоянием 360. Линии, прямоугольники и дуги могут быть нарисованы двумя способами штри­хования — сплошной и пунктирной линиями. Стиль штрихования задается с по­мощью метода void setStrokeStyleCint style), в качестве аргумента style передает­ся одна из констант класса Graphics: SOLIO — для рисования сплошных линий, DOTTED — для рисования пунктирных линий. Получить текущий стиль штрихова­ния позволяет метод int getStrokeStyle().

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

Для начала необходимо узнать, цветной ли дисплей у телефона, который достал-■ ся в распоряжение нашей программе. Эту информацию можно извлечь из менед­жера дисплея, используя метод boolean isColorC), который вернет значение true, если аппарат поддерживает работу с цветом. Количество доступных цветов или, в некоторых моделях, количество градаций одного серого цвета можно получить с помощью метода int numColorsO.

В отличие от других языков программирования, в J2ME константы для определе­ния цвета не заданы, поэтому придется нам самим, как настоящим художникам, наносить на палитру три цветовых составляющих: красный, зеленый и синий (мо­дель образования цвета RGB). Доля каждого из этих цветов задается числом от 0 до 255. Например, комбинация (0,0,255) задает синий цвет, а (0,0,0) — черный. Наши краски не кончаются, поэтому экспериментировать мы можем сколько угодно. Цвет рисования устанавливается с помощью двух методов класса Graphi cs:



  • void setColorCint red, int green, int blue) — задает цвет рисования, заданный
    цветовыми составляющими red, green, Ыue;

  • void setColorCint RGB) — устанавливает цвет, заданный цветовыми составля­
    ющими, объединенными в одно число RGB, где каждые два байта представляют
    свою составляющую. Например, красному цвету (255,0,0) будет соответство­
    вать число RGB 0xFF0000.

Узнать текущий цвет рисования можно опять же двумя способами: либо полу­чить каждую цветовую компоненту по отдельности, используя методы int getRedComponentO, int getGreenComponentO и int getBlueComponentO, либо полу­чить число RGB с помощью метода int getColorO .

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



  • void fi11Rect(int x. int у. int width. int height) — рисует закрашенный прямо­
    угольник;

  • voidfillRoundRect(intx, int y, 1nt width, int height. intarcWidth. intarcHeight) —
    рисует закрашенный прямоугольник с закругленными углами;

  • void fillArcCint x, int y. int width, int height. int startAngle, int arcAngle) —
    рисует закрашенный сектор.

Класс Graph 45

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



Класс Graph

Самое время остановиться и попробовать использовать полученные знания на практике. В качестве примера нарисуем график параболы. Красная парабола на желтом фоне — разве это не прекрасно?!

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

import javax.microedition.midlet.MIDlet: import javax.microedition.lcdui .Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Graphics;

public class Graph extends Canvas ( // функция прорисовки экрана public void paint(Graphics g) {

П получить ширину экрана

int width - g.getClipWidthO:

// получить высоту экрана

int height = g.getClipHeightO:

// установить текущий цвет желтым

g.setColorC255.255.0):



// нарисовать закрашенный прямоугольник

// размером на весь экран

g. fillRect(0. 0. width. height);

// установить текущий цвет черным

g.setColor(O.O.O):

// нарисовать рамку

д. drawRect (O , O , wi dth -l.. he i ght -l);

// нарисовать оси координат

g.drawLine(width/2. 0.width/2.height):

д.drawLine(0, height/2.width.height/2);

// сместить начало координат в центр экрана

g.translate(width/2. height/2);

// установить текущий цвет красным

g.setColor(255.0.0);

46

Глава 4. Работа с графикой

// для каждой точки по оси х fordnt x=-width/2; x// вычислить значение у по формуле

int у = -х*х/40;

// нарисовать точку параболы

g.drawline(x.y.x.y);

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

public void startAppO {

// создать объект графика

Graph graph = new GraphO;

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

display = Display.getOisplay(this);

// вывести график на экран

di splay.setCurrent(graph);


Рис. 4.1. Парабола, созданная средствами J2ME

Компилируем, запускаем и наслаждаемся полученным результатом (рис. 4.1).

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

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

Рисование текста 47

Рисование текста

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

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

■ BASELINE — размещение нижней границы текста по координате у.

■ ТОР — размещение верхней границы текста по координате у.
ш LEFT — размещение левой границы текста по координате х.


  • RIGHT — размещение правой границы текста по координате х.

  • HCENTER — размещение середины текста по координате х.

На рисунке показано расположение точек привязки на прямоугольнике, ограни­чивающем границы текста.

Left| Top Hcenter | Top Right | Тор

/тч --.Д^ /*т>

Ч? w tp

i Some text to draw .

Left | Baseline Hcenter | Baseline Right | Baseline Рис. 4.2. Схема точек привязки текста

Класс Graphics предоставляет следующие методы рисования текста:



  • void drawChar(char character, int x. int y. int anchor) — отображает символ
    character, размещая его точку привязки, заданную аргументом anchor, в точке
    с координатами (х,у);

  • voiddrawChars(char[] data, int offset. int length. int x. inty, int anchor) — ри­
    сует 1ength символов массива data, начиная с символа с индексом offset. Логи­
    ка размещения текста на экране остается прежней;

ш voiddrawString(Stringstr, intx, inty. intanchor) —рисует строку str в указан­ной позиции;

■ void drawSubst ring (String str, intoffset, intlen, intx, inty, intanchor) — ри­


сует len символов строки str, начиная с символа с индексом offset.

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



48 Глава 4. Работа с графикой

нительную константу VCENTER, которая размещает точку привязки в середине изоб­ражения по оси у. Метод для отображения картинки:

■ void drawlmage( Image Img, intx. inty. int anchor) — рисует картинку, заданную
аргументом img, разместив точку ее привязки anchor в координатах (х, у).

Обработка клавишных событий

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

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


  • void keyPressedCint keyCode) — вызывается, если какая-либо клавиша была на­
    жата;

  • void keyRel eased ( int keyCode) — вызывается, если какая-либо клавиша была от­
    пущена;

  • void keyRepeated(int keyCode) — вызывается при длительном нажатии клавиши.

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

  • KEY _NUM0, KEYJUM1, KEYJUM2,... KEYJUM9 - представляют цифры на клавиатуре
    телефона;

  • LEFT, RIGHT, UP, DOWN — представляют клавиши телефона, обозначенные стрел­
    ками;

  • KEY_POUND — представляет клавишу с символом # (решетка);

  • KEY_STAR — представляет клавишу с символом * (звездочка).

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

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

Реализуем класс Point, наследованный из класса Canvas, который будет содер­жать членами класса текущие координаты точки, размеры отображаемой облас­ти экрана, команду очистки экрана, а также флаг, управляющий очисткой экра­на. Блок прослушивания событий низкого уровня будет отслеживать нажатия клавиш и менять текущие координаты точки соответственно нажатой цифре. Блок прослушивания команд будет поднимать флаг в случае вызова команды очистки экрана.

Код класса Poi nt выглядит следующим образом:



public class Point extends Canvas implements Commandl_istener{ private int x: // координата х точки

Обработка клавишных событий 49

private int у; // координата у точки

private int width: // ширина экрана

private int height: // высота экрана

private boolean cirFlag - true: // флаг очистки экрана

private Command clear: // команда очистки экрана

// конструктор класса Point

public PointО {

// вызов конструктора родительского класса

superO:

// получить ширину экрана

width=getWidth():

// получить высоту экрана

height=getHeight();

П установить текущие координаты точки в центр экрана

x=width/2:

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

clear = new Command(«Clear», Command.OK. 1);

// добавить команду очистки экрана

addCommand(clear):

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

setCommandListener(this):



1

// метод перерисовки экрана public void paintCGraphics g) { // проверить флаг очистки экрана if (cirFlag) {

// установить текущий цвет белым

g.setColor(Oxffffff):

// залить прямоугольник размером с экран

g.fillRect<0. 0. width, height):

// сбросить флаг очистки экрана

cirFlag - false:

I

// установить текущий цвет точки красным

g,setColor<255.0.0):

// отобразить точку в текущих координатах

g.drawLine(x.y.x.y):

}

// метод, реализующий блок прослушивания команды public void commandActi on tCommand с. Displayable s) {. // если сработала команда очистки if tc - clear) {

// поднять флаг очистки экрана

cirFlag = true:

// установить текущие координаты точки в центр экрана

50 Глава 4. Работа с графикой

x=width/2: y=height/2:

// инициировать перерисовку экрана repaintO:

// блок прослушивания событий низкого уровня public void keyPressed(int keyCode) { switch (keyCode) {

// сместить текущие координаты точки // в соответствии с нажатой клавишей case KEYJIUM1: х-: у-; break: case KEYJUM2: у-; break; case KEYJUM3: х++; у-; break; case KEYJIUM4: х-: break; case KEY_NUM6: x++: break: case KEYJUM7: x-: y++: break: case KEY_NUM8: y++: break: case KEY_NUM9: x++: y++; break:

)

// инициировать перерисовку экрана



repaintO;

Обратим внимание на то, что в отличие от работы с формой, изменения изобра­жения не сразу отражаются на экране. Перерисовка экрана, реализованная в ме­тоде paint, должна быть вызвана явно, с помощью одного из следующих методов класса Canvas:



  • void repaintdnt х, inty, intwidth, int height) — перерисовка прямоугольной
    области экрана шириной width и высотой height, левый верхний угол которой
    находится в точке с координатами (х,у);

  • void repai ntO) — перерисовка экрана целиком. Аналогична такому вызову пре­
    дыдущего метода: repaint(0. 0, getWidthO. getHeightO).

Сам же метод paint вызывается внутренней реализацией, мы никогда не будем вызывать его явно.

Основная работа выполнена. Отображение управляемой точки на экране выпол­няется в стартовом методе мидлета точно так же, как и в предыдущем случае:

public void startAppO {

// создать объект управляемой точки

Point point = new PointO:

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

display = Display.getDisplay(this);

// вывести управляемую точку на экран

display.setCurrent( point); 1

Обработка клавишных событий

51


Немного поиграв вто, что получилось, мне удалось нарисовать вот такую картин­ку (рис. 4.3).



С этого примера мы начнем разработку законченной, качественной игры, ко­торой уже и не стыдно будет похвастаться даже перед профессионалами. Идея далеко не оригинальна: это знакомая нам с детства «Змейка», так любимая раз­работчиками корпорации Nokia. Самое время дать наш ответ заграничным Чем-берленам и укротить непослушную змею. На этом примере мы и будем постигать тонкости программирования под мобильные телефоны, постепенно усложняя и совершенствуя нашу игру. Но это будет уже в следующих главах...

* * *

В этой главе мы рассмотрели работу с пользова­тельским интерфейсом низкого уровня, а также графические возможности языка J2ME и логику обработки событий. Поскольку класс Canvas не является потомком класса Screen, он не исполь­зует ни одной высокоуровневой абстракции, оп­ределяемой иерархией класса Screen, например добавление заголовка или бегущей строки невоз­можно. С другой стороны, класс Canvas принад­лежит к иерархии отображаемых объектов типа Displayable, поэтому он может задействовать об­работку команд высокого уровня и реализовать блок прослушивания команд.



Рис. 4.3. Текст, написанный

с помощью «управляемой

точки»


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


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


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


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

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