355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Автор Неизвестен » Платформа J2Me » Текст книги (страница 9)
Платформа J2Me
  • Текст добавлен: 8 октября 2016, 11:48

Текст книги "Платформа J2Me"


Автор книги: Автор Неизвестен



сообщить о нарушении

Текущая страница: 9 (всего у книги 21 страниц)

Нажатием на кнопку Go вы на самом деле переключаете перемещение. Нажатие на кнопку во второй раз перемещает начало координат назад к верхнему левому углу дисплея.


Рисунок 6.9. Когда ваш Canvas впервые создан, начало координат его объекта Graphics, (0, 0), всегда относится к верхнему левому пикселю дисплея устройства



Рисунок 6.10. Дисплей после перемещения начала координат. Перемещение означает перенос начала координат объекта Graphics, а не дисплея

Листинг 6.8. После перемещения координаты, указанные процедурам рисования Graphics, не изменяются, поскольку они всегда связаны с началом координат контекста Graphics, а не дисплея


import javax.microedition.Icdui.Canvas;

import javax.microedition.Icdui.Command;

import javax.microedition.Icdui.CommandListener;

import javax.microedition.Icdui.Display;

import javax.microedition.Icdui.Displayable;

import javax.microedition.Icdui.Graphics;

/**

Демонстрирует преобразование контекста Graphics в Canvas.

@смотри javax.microedition.lcdui. Graphics


*/ public class TranslationDemo extends Canvas

implements CommandListener

{

private final int WHITE = OxFF «16 I OxFF «8 | OxFF;

private GraphicsDemo gDemo = GraphicsDemo.getlnstance ();

private Display display = Display.getDisplay(gDemo);

private static Command back = new Command("Back", Command.BACK, 1);

private static Command go = new Command("Go", Command.SCREEN, 1);

private static final int ORIGINAL_STATE = 1;

private static final int TRANSLATED_STATE = -1;

// Координата х начального рисунка, private int x = 20;

// Координата у начального рисунка, private int у = 20;

// Величина переноса в направлении х. private int deltaX = 30;

// Величина переноса в направлении у. private int deltaY = 30;

// Задает переменную, которая сообщает программе, рисовать ли на экране

// в первоначальной позиции или в преобразованной позиции,

private int state = ORIGINAL_STATE;

/**

Конструктор.


*/

public TranslationDemo()

{

super ();

addCommand(back);

addCommand(go);

setCommandListener (this);

display.setCurrent(this);

}

protected void paintClipRect(Graphics g)

{

int clipX = g.getClipX();

int clipY = g.getClipY();

int clipH = g.getClipHeight(); int clipW = g.getClipWidth();

int color = g. getColor();

g. setColor(WHITE);

g. fillRect(clipX, clipY, clipW, clipH);

g. setColor (color);

}

public void paint(Graphics g)

{

int w = 50;

int h = 50;

paintClipRect(g); g.fillRect(x, y, w, h);

}

// Переключает режим рисования. Этот метод вызывается во время

// обработки команды «Go», которая переключает перемещение.

private void toggleState()

{

state = – state;

}

// Переключает преобразование. Перерисовывает заново Canvas.

private void toggleTranslation()

}

if (state == ORIGINAL_STATE)

x = x + deltaX; у = у т deltaY;

}

else

{

x = x – deltaX;

у = у – deltaY; 1 toggleState();

// Запрашивает у реализации вызов метода paint() для восстановления

// Canvas. Это выражается в генерировании внутреннего события

// рисования, которое обрабатывается реализацией, repaint ();

*/

public void commandAction(Command c, Displayable d)

{

if (с == back)

GraphicsDemo.getInstanced.display!);

}

else if (c == go)

{

toggleTranslation();

}

}

}

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


Kaк рисуются компоненты

Вы, возможно, заметили, что метод toggleTranslation() в листинге 6.8 вызывает Canvas.repaint (). Этот вызов требует, чтобы реализация перерисовывала дисплей.

Вызов Canvas.repaint() выражается в событии внутренней реализации, представляя запрос обновления. Реализация обрабатывает событие внутренне. Она назначает вызов метода paint () Canvas, который выполняется реализацией, а не вашей программой.

Canvas должен быть закрашен для визуализации всех элементов, изображенных в его контексте, или для перерисовки поврежденных пикселей. Однако вы никогда не должны вызывать paint () прямо. Если вы желаете перерисовать ваш Canvas, вы должны создать вызов repaint (). Или вы можете вызвать следующую версию перегрузки, которая также определяется в классе Canvas:

void repaint(int x, int у, int width, int height)

Эта версия требует перерисовки прямоугольной области, определяемой параметрами, указанными в вызове.

Обратите внимание, что вы все равно должны перерисовать поврежденные пиксели, прежде чем создавать– вызов на перерисовку Canvas. Это требование отличается от требований приложений, написанных в AWT или Swing. В AWT и Swing вызов repaint() выполняет две операции: он сначала вызывает update(), а затем – paint (Graphics g). Вызов update () приводит к тому, что реализация стирает Panel, Canvas или JComponent. Такого вызова в МГОР нет, так что вы должны перерисовать поврежденные пиксели сами. Обратите внимание, что в листинге 6.6 метод paint (Graphics g) все равно вызывает метод paintClipRect(Graphics g).


Двойная буферизация

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

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

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

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

Листинг 6.9. Двойная буферизация использует два графических контекста. Единственный способ получить второй графический контекст в МЮР – через класс Image


import javax.microedition.lcdui.Canvas;

import javax.microedition.lcdui.Command;

import javax.microedition.lcdui.CommandListener;

import javax.microedition.lcdui.Display;

import javax.microedition.lcdui.Displayable;

import javax.microedition.lcdui.Graphics;

import javax.microedition.lcdui.Image;

import Java.io.lOException;

Демонстрирует двойную буферизацию графического контекста для отображения в Canvas.


public class DoubleBufferDerao extends Canvas

implements CommandListener

{

// Константа, которая представляет белый цвет.

private static final int WHITE = OxFF «16 I OxFF «8 | OxFF;

private static Command back = new Command("Back", Command.BACK, 1);

GraphicsDemo gDemo = GraphicsDemo.getlnstance();

private Display display = Display.getDisplay(gDemo);

// Объект изображения, используемый для получения

// внеэкранного объекта Graphics, private Iraage offscreen;

// Переменная, используемая для определения того, осуществляет

// ли реализация автоматическую двойную буферизацию.

// Сохраняет значение true, если реализация автоматически

// осуществляет двойную буферизацию, иначе становится

false. private boolean autoDoubleBuffered = true;

/**

Конструктор No-arg.


* /

public DoubleBufferDemo()

super();

addCoramand(back); setCommandListener(this); display.setCurrent(this);

if (! isDoubleBufferedO)

{

// Если реализация не использует двойную буферизацию

// автоматически, извлеките Image для того, чтобы мы могли

// получить из него внеэкранный Graphics. Этот Image изменяемый!

// Его размерами являются высота и ширина данного Canvas.

offscreen = Image.createlmage(getWidth (),

getHeight ());

autoDoubleBuffered = false;

}

)

protected void paintdipRect (Graphics g)

int clipX = g.getClipX();

ir.t clipY = g.getClipY();

int clipH = g.getClipHeight();

int clipW = g.getClipWidth();

int color = g.getColor ();

g. setColor (WHITE);

g. fillRect(clipX, clipY, clipW, clipH);

g,setColor(color);

}

public void paint(Graphics g)

}

Graphics originalG = null;

int width = getWidth(); int height = getHeight();

if (!autoDoubleBuffered)

}

// Сохраняем первоначальный графический контекст и получаем

// новый внеэкранный Graphics из утилиты Image.

originalG = g;

g = offscreen.getGraphics ();

// Очищаем отсекаемый прямоугольник с помощью нового объекта

// Graphics. Таким образом, мы используем двойную буферизацию

// для очистки Canvas, следовательно, избегая мерцания.

// Очистка Canvas является рисованием, как и все другие

// операции по рисованию. paintdipRect (g);

}

else

{

// Очищаем Canvas с первоначальной графикой, поскольку

// реализация не выполняет двойной буферизации автоматически.

paintdipRect (g);

}

for (int x = 0, у = 0; (x < width /2); x = x + 2)

{

g. drawRect(x, y, (width – x) – x, (height – y) – y);

у +1; у +1;

}

// При рисовании изображения содержимое внеэкранного

// контекста Graphics изображения на самом деле копируется

// в контекст Graphics устройства. if (!autoDoubleBuffered)

{

originalG.drawlmage(offscreen, 0, 0,

Graphics.TOP | Graphics.LEFT);

{{

public void commandAction(Command c, Displayable d)

}

if (c == back)

GraphicsDemo.getInstance(). display!);

}

}

}

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


if (!isDoubleEuffered())

{

offscreen = Image.createlmage(getWidth(), getHeight());

autoDoubleBuffered = false;

}

Если реализация не поддерживает двойную буферизацию, приложению не нужно выполнять ее. Метод Canvas.IsDoubleBuffered() сообщает вам, не выполняет ли реализация двойную буферизацию неявно. Обратите внимание на конструкцию объекта Image. Этот вызов Image, create Image () создает изменяемый объект Image. Приложение нуждается в изменяемом Image, потому что оно выполняет рисование в контексте Graphics объекта Image, являющемся нужным вам внеэкранным буфером. Это единственный способ получения дополнительного Graphics в MIDP.

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


public void paint(Graphics g)

if (!autoDoubleBuffered)

originalG = g;

g = offscreen.getGraphics();

else

{

paintClipRect(g);

}

.

}

Временная переменная хранит ссылку на первоначальный объект Graphics, который представляет графический контекст устройства. Новый графический контекст получается через объект Image, созданный ранее. Этот Graphics связан с Image. Последовательность событий представлена схематично на рисунке 6.11.

Теперь метод paint (Graphics g) выполняет свои операции по рисованию во внеэкранном контексте Graphics. При выполнении он копирует содержимое внеэкранного Graphics в первоначальный контекст Graphics, что в результате формирует изображение на дисплее. Операция копирования совершается с помощью вызова метода Graphics.drawlmage(). Этот метод говорит по сути: «Копируй содержимое графического контекста этого аргумента изображения в меня».

Механизм двойной буферизации в MIDP отличается от двойной буферизации Swing. В Swing вы можете выполнять двойную буферизацию операций по рисованию в любом Component, не только в объектах Canvas. Приложения Swing вызывают Java. awt. Component.getGraphics () для получения внеэкранного графического контекста. Приложение может рисовать в этом контексте. Оно затем связывает этот внеэкранный графический контекст с самим устройством.


Рисунок 6.11. Левая половина предаавляет состояние во время первого ввода метода paint. Правая сторона представляет состояние после получения внеэкранного контекста Graphics. Ссылка сохраняет первоначальный контекст Graphics. Кодирование цвета показывает, что внеэкранный контекст Graphics связан с объектом изображения

MIDP не имеет такого вызова. Единственной ссылкой на объект Graphics, которая связана с реальным устройством, является та, что передается методу paint (Graphics g) Canvas.


Отображение изображения с помощью Canvas

Вы уже узнали в главе 5, что некоторые компоненты высокоуровневого пользовательского интерфейса MIDP умеют отображать изображения, например, как часть элемента в ChoiceGroup. Объекты Canvas также могут отображать изображения. Кроме рисования базовых геометрических фигур, объект Canvas может «рисовать» изображения с помощью того же контекста Graphics, который он использует для низкоуровневых функций рисования. MIDP поддерживает только формат изображений PNG.

На рисунке 6.12 показано изображение, отображаемое в Canvas. В листинге 6.10 показана исходная программа, создающая изображение, показанное на рисунке 6.12. Структура программы сходна с другими демонстрационными программами Canvas, приведенными в этой главе.



Рисунок 6.12. Canvas может отображать изображение, на самом деле рисуя изображение в контексте Graphics объекта изображения

Листинг 6.10. Чтобы отобразить изображение, Canvas просто «рисует» объект изображения с помощью процедуры рисования изображения объекта Graphics


import javax.microedition.lcdui.Canvas;

import javax.microedition.lcdui.Command;

import javax.microedition.lcdui.CommandListener;

import javax.microedition.lcdui.Display;

import javax.microedition.lcdui.Displayable;

import javax.microedition.lcdui.Graphics;

import javax.microedition.lcdui.Image;

import Java.io.lOException;

/*

Демонстрирует двойную буферизацию изображений в Canvas.

Изображения автоматически дважды буферизируются.

Эта программа демонстрирует, что вы ничего не должны делать для получения поведения двойной буферизации при отображении изображений.

Однако вам все равно придется провести двойную буферизацию операции, которая рисует фон Canvas, до рисования изображения.


*/

public class DoubleSufferlmageDemo extends Canvas

implements CommandListener

{

// Константа, которая представляет белый цвет.

private static final int WHITE = OxFF «16 I OxFF «8 I OxFF;

private static Command back = new Command ("Back", Command.BACK, 1);

private GraphicsDemo gDemo = GraphicsDemo.getlnstance();

private Display display = Display.getDisplay (gDerno);

// Ссылка на Image, которое отображает этот объект. Image image;

// Переменная, используемая для определения того, осуществляет

// ли реализация автоматическую двойную буферизацию.

// Принимает значение «true», если реализация осуществляет

// автоматическую двойную буферизацию,

«false» в ином случае, private boolean autoDoubleBuffered = true;

/**

Конструктор No-arg.


*/

public DoubleBufferlmageDemo()

{

super();

if (!isDoubleBuffered())

{

autoDoubleBuffered = false;

}

// Создайте изображение PNG. Изображение «нарисовано» в

// изменяемом объекте Image, который имеет свой собственный

// внеэкранный Graphics. Мы сейчас создаем изображение в

// конструкторе, вместо метода paint (),

//так что оно создается только один раз. try

}

image = Image.createlraage("/bottle80x80.png");

}

catch (lOException ioe)

{

System.out.println(ioe.getMessage()); ioe.printStackTrace();

}

addCommand(back); setCommandListener(this); display.setCurrent (this);

}

protected void paintClipRect(Graphics g)

{

int clipX = g.getClipX{};

int clipY = g.getClipY ();

int clipH = g.getClipHeight();

int clipW = g.getClipWidth ();

int color = g.getColor();

g. setColor(WHITE);

g. fillRecc(clipX, clipY, clipW, clipH);

g. setColor (color);

/**

Рисует изображение на видимом Canvas этого объекта.


*/ public void paint(Graphics g)

Graphics originalG = null; int width = getWidth ();

int height = getHeight ();

if (image == null)

{

return; 1

// Мы все равно нуждаемся в двойной буферизации операций

// рисования, которые очищают графику Canvas, if (!autoDoubleBuffered)

{

// Сохраняет первоначальный графический контекст и использует

// внеэкранный Graphics из Image для очистки отсекаемого

// прямоугольника. originalG = g; g = image.getGraphics ();

paintClipRect (g);

}

else 1

// Нарисуйте фон с первоначальным Graphics, переданным в него. paintClipRect(g);

{

// Нам не нужна двойная буферизация вызова отображения Image.

// Вызов этого метода рисует изображение во

// внеэкранном Graphics объекта Image, копируя затем его

// содержимое в контекст Graphics устройства неявно.

g. drawlmage(image, 0, 0, Graphics.TOP I Graphics.LEFT);

public void commandAction(Command c, Displayable d)

{

if (c == back)

GraphicsDemo.getInstance(). display!);

}

}

}

Процедура довольно прямолинейна. Вы должны сначала создать объект изображения, что вы сделали, когда переслали изображение в компонент высокоуровневого пользовательского интерфейса MIDP. Программа вызывает Image.createlmage(String name) для создания объекта Image. Этот метод определяет местоположение файла изображения, чье имя пути указано относительно директории res/ проекта.

Затем вы пересылаете изображение в объект Graphics, указывая точку привязки и местоположение (х, у) точки привязки. После этого программа просто вызывает метод Graphics.drawlmage() для отображения изображения. Реализация MIDP пересылает объект Graphics в метод приложения paint (Graphics g). Он представляет физический графический контекст устройства. То есть выполнение Graphics.drawlmage() в контексте Graphics, пересланного в ваш метод Canvas, paint (Graphics g), выражается в результате в визуализации на дисплее устройства.

Класс Image имеет четыре версии перегрузки метода createlmage(). В таблице 6.7 показаны все четыре версии. Вы уже видели третью версию, эта версия единственная, которая производит изменяемый объект изображения. Это вам необходимо для записи во внеэкранном контексте Graphics объекта Image.

Таблица 6.7. Методы класса Image для создания объектов изображений

Название метода изображения – Описание

static Image createlmage (byte [] imageData, int imageOffset, int imageLength) – Создает изменяемое изображение из указанных данных изображения, беря изображения начиная с указанных смещения и длины

static Image createlmage (Image source) – Создает изменяемую копию указанного изображения

static Image createlmage (int width, int height) – Создает новое изменяемое изображение с указанной шириной и длиной

static Image createlmage (String name) – Создает изменяемый объект изображения из изображения с путем к ресурсам, указанным в файле JAR набора МID-летов

Другие версии создают изменяемые объекты Image. Каждая версия дает вам возможность создавать изображение из различных источников. Первая версия создает изображение из необработанных двоичных данных. Вторая создает изображение из другого объекта изображения. Четвертая версия загружает изображение из файла JAR набора MID-летов. Строковый аргумент указывает имя файла ресурса в файле JAR.

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

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

Метод paint () создает объект Image из файла ресурса, который представляет изображение PNG для отображения. Но этот объект Image уже имеет связанный с ним контекст Graphics, являющийся внеэкранным Graphics. Поэтому, когда метод paint () выполняет следующий оператор, он копирует содержимое контекста Graphics объекта Image – фактические биты, которые составляют изображение, – в графический контекст дисплея:

g. drawlmage (image, О, О, Graphics.TOP I Graphics.LEFT);

Таким образом, двойная буферизация изображений осуществляется автоматически.

Хотя при рисовании изображения двойная буферизация осуществляется автоматически, очистка отсекаемого прямоугольника, то есть рисование фона Canvas, – нет. Посмотрите внимательнее на метод paint (Graphics д)в листинге 6.10, и вы увидите, что он все еще проверяет, не осуществляет ли реализация автоматическую двойную буферизацию. Если нет, метод paint (Graphics g) использует внеэкранный графический контекст для очистки отсекаемого прямоугольника.

Этот код немного отличается от кода, описанного в листинге 6.9, в этом коде нет явной ссылки на внеэкранный Graphics. Причина этого заключается в том, что объект Image уже предоставил внеэкранную графику. Метод paint (Graphics g) может просто использовать ее как внеэкранный Graphics, необходимый для очистки отсекаемого прямоугольника.


Выводы по главе

Два класса в пакете javax.microedition.lcdui формируют определение низкоуровневого программного интерфейса приложения в MIDP: класс Graphics и класс Canvas. Низкоуровневый API MIDP дает вашему приложению возможность получать информацию о событиях низкого уровня, которые недоступны для компонентов высокоуровневого программного интерфейса приложения. Объекты Canvas могут получать информацию о событиях нажатия кнопки или движения указателя. Объекты Canvas являются объектами Displayable. По этой причине они все еще могут выполнять обработку команд, как и другие компоненты Displayable.

Чтобы использовать низкоуровневый API, вы должны создать подкласс Canvas. Затем вы должны описать метод paint (Graphics g) в вашем подклассе, для того чтобы создать видимый внешний вид его экземпляров. Метод подкласса paint (Graphics g) определяет этот видимый внешний вид.

Метод paint (Graphics g) рисует внешний вид компонента Canvas с помощью графического контекста, определенного классом Graphics. Класс Graphics поддерживает рисование и заполнение базовых геометрических фигур, таких, как линии, дуги, прямоугольники, текст и так далее. Он также поддерживает рисование в цвете. Другими поддерживаемыми свойствами являются выбор шрифта для рисования текста, отсечение и перенос начала координат Graphics.

Объекты Canvas могут также отображать изображения с помощью функциональных возможностей класса Graphics. Приложения загружают изображения из файлов, которые должны храниться в формате PNG.

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


    Ваша оценка произведения:

Популярные книги за неделю