"Платформа J2Me" - читать интересную книгу автора (неизвестен Автор)Глава 6. Низкоуровневый программный интерфейс приложения (API) MIDPВ этой главе вы узнаете, как использовать низкоуровневый программный интерфейс приложения MIDP, который является одним из двух программных интерфейсов приложения компонентов пользовательского интерфейса MIDP. О первом API MIDP, высокоуровневом, вы узнали в главе 4. Низкоуровневый API дает вам возможность делать то, что в высокоуровневом API осуществлять было невозможно: получать низкоуровневую информацию о событиях (такую, как информация о нажатии клавиш), которую получает ваш компонент; определять внешний вид своего компонента пользовательского интерфейса. Два класса составляют определение низкоуровневого API: javax.microedition.lcdui. Canvas; javax.microedition.lcdui.Graphics. На рисунке 6.1 воспроизводится часть диаграммы иерархии наследования MIDP, приведенной на рисунке 5.1. Вы можете видеть, что класс Canvas происходит из Displayable. Однако, поскольку класс Canvas не является типом Screen, он не использует ни одной абстракции, определяемой иерархией Screen, например, добавление заголовка или тикера невозможно. Класс В компоненте Однако, в дополнение к обработке высокоуровневых команд, класс Реализация MIDP передает информацию о событии низкого уровня объекту Название метода — Описание protected void keyPressed(int KeyCode) — Клавиша была нажата и отпущена protected void keyReleased.(int KeyCode) — Клавиша была отпущена protected void keyRepeated(int KeyCode) — Клавиша была нажата несколько раз protected void pointerPressed(int x, int y) — Указатель был нажат protected void pointerDragged(int x, int y) — Указатель был перемещен protected void pointerReleased(int x, int y) — Указатель был отпущен protected abstract void paint(Graphics g) — Произошел запрос Canvas на перерисовку Для выполнения обработки событий низкого уровня ваш конкретный подкласс В листингах 6.1 и 6.2 представлена простая схема обработки команд и событий в Canvas. Код в листинге 6.1 является кодом MID-лета для демонстрационной программы, большая часть которой выглядит знакомо. Код в листинге 6.2, однако, создает подкласс Canvas — Displayable, который согласно коду, показанному в листинге 6.1, размещается на экране. import javax.microedition.midlet.MIDlet; import javax.microedition.lcdui.Display; /" Определяет MID-лет, отображающий пустой Canvas на дисплее устройства. Отображаемый Canvas является Экземпляром класса Canvasl. @смотри Canvasl */ public class CanvasDemol extends MIDlet { // Поддерживает ссылку на экземпляр данного класса. private static CanvasDemol midlet; // Поддерживает ссылку на Canvas, который пользователь // видит на дисплее. private static Canvasl instance; private Display display; private Canvasl canvas; /** Конструктор No-arg. Вызывает конструктор no-arg класса MID-лета. */ public CanvasDemol() super(); display = Display.getDisplay(this); instance = canvas; midlet = this; { /** Возвращает ссылку на MID-лет, связанный с данным отображаемым объектом. @возвращает MID-лет, который отображает этот объект. **/ public static CanvasDemol getMIDlet() { return midlet; { public void startApp() { canvas = new Canvasl (); display.setCurrent(canvas); ( public void pauseApp() { } public void destroyApp(boolean destroy) { instance = null; canvas = null; void quit () { destroyApp(true); notifyDestroyed(); } } 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; /** Определяет подкласс Canvas, который отображается с помощью MID-лета CanvasDemol. Этот Canvas имеет единственную команду «Exit», так что пользователь может завершить работу демонстрационной программы. @Осмотри CanvasDemol */ public class Canvasl extends дополняет Canvas implements CommandListener { private Command exit = new Command("Exit", Command.EXIT, 1); /** Конструктор No-arg. */ public Canvasl () { // Обратите внимание на вызов super (), который является конструктором // r.o-arg Canvas! Это очень важно. Без вызова super() ваши экземпляры // Canvas не смогут действовать как настоящие Canvas. Они не будут // отображать правильно, они не будут рисовать должным образом и они // не смогут обрабатывать события, super (); addCommand(exit); setCommandListener (this); printCanvasInfo(); } /** Рисует внешний вид Canvas, видимый пользователю. В данном случае он не рисует ничего. Поэтому этот Canvas не имеет визуального представления. */ public void paint(Graphics g) { } public void commandAction(Command c, Displayable d) { if (c == exit) CanvasDemol.getMIDlet(). quit(); } /** Определяет, что обработка должна быть сделана в ответ на событие отпускания клавиши, произошедшее в данном Этот метод подменяет тот же самый метод в */ public void keyReleased(int keyCode) { printKeyEventlnfo(keyCode); } /** Определяет некоторую обработку событий, связанных с клавишами. Этот метод просто печатает в стандартном результате некоторую диагностическую информацию о событиях, связанных с клавишами, на Canvas. */ protected void printKeyEventlnfо(int keyCode) { System.out.println("Key code = " + keyCode); System.out.println("Key name = " + getKeyName(keyCode)); System.out.println("Game action = " + getGameAction(keyCode)); } /* * Печатает диагностическую информацию об атрибутах и возможностях объекта Canvas. "/ protected void printCanvasInfо () { System.out.println("Device height = " + getHeight ()); System.out.println("Device width = " + getWidth()); System.out.println("Pointer events = " + hasPointerEvents()); System, out. printl'n ("Pointer motion events = " + hasPointerMotionEvents()); System.cue.println("Repeat events = " + hasRepeatEvents()); } } Чтобы убедиться, что в Canvas все еще осуществима обработка высокоуровневых команд, запустите MID-лет, показанный в листинге 6.2. Вы увидите, что дисплей, показанный на рисунке 6.2, имеет экранную клавишу Exit (Выход), которая при активации завершает работу МID-лета. Класс Нажатие на любую клавишу клавишной панели приводит к формированию двух клавишных событий: событие нажатия клавиши и событие отпускания клавиши. Эта программа выводит информацию о событиях отпускания клавиши. Информация о клавишном событии включает название клавиши, код клавиши и, возможно, связанное с ним обозначение игрового действия. Название клавиши является String, которая представляет собой удобное для чтения представление клавиши, обычно сходное (если не такое же) с текстом, физически напечатанным на клавише устройства. Код клавиши является целым числом, чье значение однозначно представляет каждую клавишу. Для стандартных клавиш ITU-T, а именно от 0 до 9, * и #, код клавиши является значением уникода символа. Программы должны использовать предписанные константы класса Константа класса Canvas — Описание public static final int KEY NUMO — Представляет клавишу 0 клавишной панели public static final int KEY NUM1 — Представляет клавишу 1 клавишной панели public static final int KEY NUM2 — Представляет клавишу 2 клавишной панели public static final int KEY_NUM3 — Представляет клавишу 3 клавишной панели public static final int KEY NUM4 — Представляет клавишу 4 клавишной панели public static final int KEY NUM5 — Представляет клавишу 5 клавишной панели public static final int KEY_NUM6 — Представляет клавишу 6 клавишной панели public static final int KEY NUM7 — Представляет клавишу 7 клавишной панели public static final int KEY_NUM8 — Представляет клавишу В клавишной панели public static final int KEY NUM9 — Представляет клавишу В клавишной панели public static final int KEY POUND — Представляет клавишу * клавишной панели public static final int KEY STAR — Представляет клавишу # клавишной панели Для нестандартных (зависящих от устройства) клавишей, таких, как кнопки Up (Вверх), Down (Вниз), Left (Влево), Right (Вправо) и Select (Выбор) на мобильных устройствах, код клавиши является значением, зависящим от реализации, и должен быть отрицательным в соответствии со спецификацией MIDP. Опять же, однако, вы должны использовать предопределенные константы, показанные в таблице 6.3, и не думать о настоящем целом значении. Константа класса Canvas — Описание public static final int UP — Представляет клавишу панели со стрелкой вверх public static final int DOWN — Представляет клавишу панели со стрелкой вниз public static final int LEFT public static final int RIGHT — Представляет клавишу панели со стрелкой влево Представляет клавишу панели со стрелкой вправо public static final int FIRE — Представляет клавишу панели со стрелкой запуска (выбора] на мобильных устройствах В дополнение к константам, которые вы уже видели, класс Canvas определяет константы GAME_A, GAME_B, GAME_C, GAME_D и FIRE, которые представляют игровые действия, отражая влияние игровой индустрии в J2ME. Значения этих констант нестандартны и изменяются в зависимости от реализации. Игровые действия отражены на других клавишах, потому что большинство устройств не имеет клавиш или кнопок специально для игр. Значение игрового действия соответствует одному или более кодам клавиш, являющихся двоичными значениями, каждое из которых однозначно соответствует клавише. Вы можете определить определенное отображение с помощью следующих двух методов: public int getKeyCode (int gameAction) public int getGameAction(int keyCode) В листинге 6.2 эти методы используются для вывода диагностической информации о каждом полученном событии отпускания клавиши. Если вы запустите эту программу и исследуете результат, вы увидите, что не каждая клавиша имеет связанное с ней игровое действие. В данном случае метод Вы, несомненно, обратили внимание, что canvas, показанный на рисунке 6.2, был чистым за исключением экранной клавиши Exit (Выход). Причина этого кроется в том, что класс Canvasl не описывает свое визуальное представление. Все конкретные подклассы Canvas должны определять свой внешний вид для того, чтобы визуализировать какие-либо визуальные атрибуты. Для этого они должны привлекать помощь класса javax.microedition.lcdui.Graphics. Основная цель класса Graphics заключается в поддержке рисования на Canvas. Класс Graphics определяет возможности низкоуровневого графического рисования. Если вы уже разрабатывали программы на AWT или Swing, этот класс покажется вам очень знакомым. В действительности его свойства и программный интерфейс практически идентичны, хотя и являются подмножеством свойств класса Класс Каждый конкретный подкласс Объект Класс Graphics поддерживает следующие абстракции: — рисование и заливка двухмерных геометрических фигур; — выбор цветов для графической ручки; — выбор шрифтов для рисования текста; — отсечение областей для рисования (clipping); — перенос координатной системы Graphics. Устройства различаются в своей поддержке атрибутов, таких, как цвет. Поэтому класс public int isColorO public int numColors() так что вы можете получить информацию о поддержке данным устройством цвета и количестве предоставляемых цветов или поддержке какого-либо числа уровней шкалы серого цвета для устройств, не поддерживающих цвет. Первостепенной абстракцией, определяемой классом Класс Graphics предоставляет операции по рисованию и заливке следующих типов геометрических фигур: — линии; — прямоугольники; — дуги; — текстовые символы. Для всех операций по рисованию геометрических фигур класс Graphics использует графическую ручку, которая рисует линии шириной в один пиксель. Графическая ручка рисует слева направо и сверху вниз со своего координатного местоположения, как показано на рисунке 6.3. Взглянув на несколько примеров, вы лучше поймете принципы ее действия. Линии. На рисунке 6.4 показаны линии, нарисованные в Canvas. В листинге 6.3 показан исходный код, который создает рисунок 6.4, но я опустил код MID-лета, который отображает это. Вы можете найти полный исходный код по адресу http://www.phptr.com/. Для остальных примеров, приведенных в этой главе, предполагается, что отображаемые классы, которые вы видите здесь, созданы и отображаются MID-летом в стиле, сходном с примерами, которые вы видели в предыдущих главах. Исходя из этого, я покажу вам только новый код. 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.raicroedition.lcdui.Command; /* Рисует серию линий для демонстрации различных типов и стилей линий, которые могут быть нарисованы с помощью класса Graphics. @смотри javax.microedition.Icdui.Graphics */ public class LineDemo extends Canvas. implements CommandListener } // Константа, которая представляет белый цвет. private static final int WHITE = OxFF «16 | OxFF «8 I OxFF; private Command back = new Command("Back", Command.BACK, 1); private GraphicsDemo gDemo = GraphicsDemo.getlnstance(}; private Display display = Display.getDisplay(gDemo); /** Конструктор No-arg. */ public LineDemo() { super (); addCommand(back); setCommandListener(this); display.setCurrent(this); } /* * Рисует отсекаемый белый прямоугольник, эффективно стирающий все, что было изображено в Canvas перед этим. "/ protected void paintdipRect (Graphics g) } int clipX = g.getClipX (); int clipY = g.getClipY(); int clipH = g.getdipHeight (); int clipW = g.getClipWidth(); int color = g.getColor (); g. setColor(WHITE); g. fillRect(clipX, clipY, clipW, clipH); g. setColor (color); } / ** Отображает внешний вид этого подкласса Canvas. * / public void paint (Graphics g) { paintdipRect (g); int width = getWidth(); int height = getHeight (); g. drawLine (20, 10, width — 20, height — 34); g. drawLine(20, 11, width — 20, height — 33); g. drawLine(20, 12, width — 20, height — 32); g. drawLine(20, 13, width — 20, height — 31); g. drawLine(20, 14, width — 20, height — 30); g. setStrokeStyle(Graphics.DOTTED); g. drawLine(20, 24, width — 20, height — 20); g. drawLine(20, 25, width — 20, height — 19); g. drawLine(20, 26, width — 20, height — 18); g. setStrokeStyle (Graphics.SOLID); g. drawLine(20, 36, width — 20, height — 8); } public void commandAction(Command c, Displayable d) { if (c == back) { GraphicsDemo.getlnstanceO.display(); } } } Метод Ваша программа должна выполнять все свои операции по рисованию в методе Чтобы нарисовать линию, вы должны указать координаты (х, у) начальной и конечной точек. Координаты (х, у) определяются относительно точки (0, 0), которая, во время создания графического контекста, представляет пиксель, лежащий в верхнем левом углу дисплея, как показано на рисунке 6.3. Координата х определяет горизонтальное расстояние направо от колонки 0 (левый край дисплея), а координата у определяет вертикальное расстояние от строки 0, которая является верхним краем дисплея. Ширина линий составляет один пиксель. Чтобы нарисовать более толстую линию, вы должны рисовать прилегающие линии, как демонстрируется в листинге 6.3. Три линии, показанные на рисунке 6.4, созданные с помощью листинга 6.3, имеют ширину в пять, три и один пиксель соответственно. Кроме того, средняя линия отображена штрихпунктиром. Вы можете установить стиль штриховки для любого рисунка с помощью метода Прямоугольники. Вы можете рисовать два вида прямоугольников: обычный и закругленный. На рисунке 6.5 показаны несколько прилегающих прямоугольников. В листинге 6.4 показан исходный код paint (Graphics g) для этого примера. import javax.microedition.lcdui.Canvas; import javax.microedition.Icdui.Command; import javax.microedition.Icdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.Icdui.Displayable; import javax.microedition.Icdui.Graphics; import javax.microedition.Icdui.Command; /** Рисует прямоугольники на Canvas с помощью графических методов в классе javax.microedition.Icdui.Graphics. @смотри javax.microedition.Icdui.Graphics */ public class RectangleDemo extends Canvas implements CommandListener { // Константа, представляющая белый цвет. private static final int WHITE = OxFF «16 | OxFF «8 I OxFF; private Command back = new Command("Back", Command.BACK, 1); private Display display = Display.getDisplay(GraphicsDemo.get!nstance()); /** Конструктор No-arg. Вызывает конструктор no-arg Canvas. */ public RectangleDemo() } super (); addCommand(back); setCommandListener(this); display.setCurrent (this); } /** Рисует белый отсекаемый прямоугольник, эффективно стирающий все, что было отображено на Canvas перед этим. */ 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); } /** Отображает внешний вид этого подкласса Canvas. */ public void paint(Graphics g) { paintClipRect(g); int width = getWidthO; int height = getHeight(); int xO = 5; int yO = 5; int barW = 10; int initHeight = height — 10; int deltaH = 10; g. drawRect(xO, yO, barW, initHeight); g. fillRect(xO + barW, yO + deltaH, barW, initHeight — deltaH + 1); g. drawRect(xO + barW " 2, yO + deltaH * 2, barW, initHeight — deltaH * 2); g. setColor (255, 00, 00); g.fillRect(xO + bar» * 3, yO + deltaH * 3, barW, initHeight — deltaH * 3 + 1); g. setColor (0," 0, 0); g. drawRect(xO + barW * 4, yO + deltaH * 4, barW, initHeight — deltaH * 4); g. fillRect(xO + barW * 5, yO + deltaH * 5, barW, initHeight — deltaH * 5 + 1); g. drawRect(xO + barW * 6, yO + deltaH * 6, barW, initHeight — deltaH * 6); g.fillRect(xO + barW * 1, yO + deltaH * 1, barW, initHeight — deltaH * 7 + 1); } public void commandAction(Command c, Displayable d) { if (c == back) { GraphicsDemo.getlnstanceO.display!); } } } Дуги. Класс Graphics также поддерживает рисование дуг. Чтобы нарисовать дугу, вы должны указать шесть параметров. Эти параметры включают четыре размера, которые определяют ограничивающий дугу прямоугольник, ее начальный угол и ее конечный угол. Ограничивающий прямоугольник определяется теми же четырьмя параметрами, которые требуются для прямоугольников. Процедура рисования отслеживает дугу вдоль ее пути от начального угла к конечному углу в направлении против часовой стрелки. Угол в 0 градусов располагается вдоль положительной оси X координатной плоскости. На рисунке 6.6 показаны две дуги, нарисованные методом import javax.microedition.lcdui.*; /** Демонстрирует рисование дуг с помощью класса Graphics. @смотри javax.microedition.lcdui.Graphics */ public class ArcDemo extends Canvas implements ComraandListener { public void paint(Graphics g) { paintClipRect(g); } int width = getWidth(); int height = getHeight (); g. drawArc(5, 5, 80, 40, 90, 300); g. fillArc(5, 60, 80, 40, 0, 250); } . } Обратите внимание, что вторая дуга заполнена и что она была создана с помощью метода Текст. Класс Название метода отображения текста в Canvas — Описание public void drawString(String str, int x, int y, int anchor) — Рисует символы, которые формируют строковую переменную с указанной точкой привязки в позиции, определяемой координатами (х, у] public void drawSubstring(String str, int offset, int len, int x, int y, int anchor) — Рисует символы, которые формируют переменную подстроки, определяемую начальной точкой и сдвигом, с указанной точкой привязки в позиции, определяемой координатами (х, у) public void drawChar (Char char, int x, int y, int anchor) — Рисует символ с указанной точкой привязки в позиции, определяемой координатами (х, у) Эти методы вычисляют воображаемый ограничивающий прямоугольник, который описывает границы области, занимаемой текстом, вокруг текста, который необходимо изобразить, как показано на рисунке 6.7. Размеры этого прямоугольника зависят от длины строки и шрифта, используемого для отображения. Параметры (х, у) в только что показанных методах представляют расположение ограничивающего прямоугольника. Параметр привязки определяет точку привязки ограничивающего прямоугольника. Точка привязки определяет, которая из шести возможных точек по периметру текста ограничивающего прямоугольника должна быть размещена в позицию (х, у). На рисунке 6.7 показаны шесть точек привязки для регулирования расположения прямоугольника, ограничивающего текстовую строку. Значение точки привязки на самом деле является выбором нагрузки на точку ограничивающего прямоугольника. Два атрибута составляют нагрузку точки привязки: горизонтальная и вертикальная политики нагрузки. В таблице 6.5 описаны представляющие их константы класса Graphics. Они описывают public static final int. Некоторый отображаемый текст Константа привязки — Описание static int LEFT — Размещает левый край у координаты х static int HCENTER — Размещает горизонтальный центр у координаты х static int RIGHT — Размещает правый край у координаты х static int TOP — Размещает верх у координаты у static int BASELINE — Размещает нижнюю строку текста у координаты у static int BOTTOM — Размещает низ ограничивающего прямоугольника у координаты у static int VCENTER — Только для изображений, размещает вертикальный центр изображения у координаты у Класс Graphics описывает эти константы для текущих значений горизонтальной нагрузки, а также определяет значения для текущих значений вертикальной нагрузки. На рисунке 6.8 показан некоторый текст, отображаемый на Canvas, а в листинге 6.6 показан метод paint (Graphics g) исходного кода, который его отображает. import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.rnicroedition.lcdui.CornmandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; /** Отображает некоторый текст, «нарисованный» в Canvas. Демонстрирует использование процедур рисования текста в Graphics. @смотри javax.microedition.lcdui.Graphics */ public class TextDemo extends Canvas implements CommandListener } public void paint(Graphics g) } paintClipRect(g); int width = getWidth (); int height = "getHeight (); g. setFont(Font.getDefault Font()); g. drawStriny("Default", 5, 30, Graphics.LEFT I Graphics.BOTTOM); g. setFont (Font.get Font (Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE)); g.drawstring("Large", 5, 53, Graphics.LEFT | Graphics.BOTTOM); g. set Font(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_ITALIC, Font.SIZE_MEDIUM)); g. drawString("Medium", 5, 71, Graphics.LEFT I Graphics.BOTTOM); g. set Font(Font.get Font(Font.FACE_PROPORTIONAL, Font.STYLE_UNDERLINED, Font.SIZE_SMALL)); g. drawString("Small", 5, 90, Graphics.LEFT I Graphics.BOTTOM); g. setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM)); g. drawString ("V", width — 10, 20, Graphics.RIGHT I Graphics.BOTTOM) g. drawStringC'E", width — 10, 32, Graphics.RIGHT I Graphics.BOTTOM) g. drawString("R", width — 10, 44, Graphics.RIGHT I Graphics.BOTTOM) g. drawStringC'T", width — 10, 56, Graphics.RIGHT I Graphics.BOTTOM) g. drawString("I", width — 10, 68, Graphics.RIGHT I Graphics.BOTTOM) g. drawString ("C", width — 10, 80, Graphics.RIGHT | Graphics.BOTTOM) g. drawStringC'A", width — 10, 92, Graphics.RIGHT I Graphics.BOTTOM) g.drawString ("L", width — 10, 104, Graphics.RIGHT I Graphics.BOTTOM); g. drawChar('B', width — 25, 20, Graphics.RIGHT | Graphics.BOTTOM); g. drawChar(0, width — 25, 32, Graphics.RIGHT I Graphics.BOTTOM);: g. drawChar('L', width — 25, 44, Graphics.RIGHT I Graphics.BOTTOM);: g. drawChar ('D', width — 25, 56, Graphics.RIGHT I Graphics.BOTTOM); } . } Эта демонстрационная программа выбирает, где разместить текстовые строки «Default», «Large», «Medium» и «Small», располагая основные линии ограничивающих прямоугольников. Текст также выравнивается по левому краю. Обратите внимание, что логический OR горизонтальной и вертикальной политик привязки (LEFT | BOTTOM) указывают позицию привязки. Две строки «BOLD» и «VERTICAL» нарисованы вертикально простым размещением отдельных символов с помощью метода API Graphics также определяет другую константу, VCENTER, которая действительна только для указания вертикальной политики привязки при размещении изображений. Она недействительна для текста. VCENTER обуславливает то, что вертикальный центр изображения должен быть размещен в координатной точке (х, у). Вы узнаете о работе с изображениями далее в этой главе. Шрифты. Вы можете выбрать шрифт для любого текста, который вы изобразили в Canvas, как демонстрируется в листинге 6.6. Вы выбираете шрифт, указывая три атрибута шрифта: гарнитура, стиль и размер. Класс javax.microedition.lcdui.Font определяет для каждой из трех категорий константы, показанные в таблице 6.6. Константа атрибута — Описание static int FACE MONOSPACE — Значение атрибута гарнитуры static int FACE_PROPORTIONAL — Значение атрибута гарнитуры static int FACE SYSTEM — Значение атрибута гарнитуры static int STYLE BOLD — Значение атрибута стиля static int STYLE ITALIC — Значение атрибута стиля static int STYLE PLAIN — Значение атрибута стиля static int STYLE UNDERLINED — Значение атрибута стиля static int SIZE SMALL — Значение атрибута размера static int SIZE MEDIUM — Значение атрибута размера static int SIZE LARGE — Значение атрибута размера Вы должны были заметить, что спецификация MIDP не требует от реализаций предоставления всех этих размеров, стилей и гарнитур. Выводимый шрифт, которым реализация может управлять, будет как можно ближе соответствовать требуемому шрифту. В отличие от AWT и Swing, вам не придется иметь огромный набор шрифтов и несметное число размеров шрифтов. Более того, поскольку класс Font объявлен final и не имеет конструкторов public, вы не можете организовать его подклассы для определения новых шрифтов. Создатели MIDP решили ограничить число доступных шрифтов с учетом ограничений устройства. Вам необходимо получить ссылку на текущий объект Font для того, чтобы переслать его в метод Font.getFont(int face, int style, int size) Font.get Default Font () Указанный шрифт будет использоваться во всех последующих операциях по рисованию до тех пор, пока вы вновь его не измените. В листинге 6.6 шрифт был изменен до создания различных текстовых строк или символов для достижения желаемого эффекта. Когда ваше приложение вызывает метод Во время отображения некоторая группа пикселей дисплея может быть недействительной или поврежденной. Недействительный или поврежденный пиксель — это тот, который видим в результате предыдущей операции рисования, но не должен быть визуализирован в качестве части текущей операции рисования. Дисплей может быть поврежден другим MID-летом или даже «внешним» приложением — например, приложением по передаче сообщений, которое обновляет дисплей для отображения получения сообщения SMS вашим мобильным телефоном. Перед тем как приступить к самому рисованию, ваш Canvas обязан стереть все пиксели, появившиеся на экране, которые не должны быть частью его внешнего вида. Вы восстанавливаете экран, обновляя недействительные пиксели. Вы, несомненно, уже обратили внимание на наличие метода 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); } Проблема этого метода заключается в том, что он использует отсекаемый прямоугольник объекта Graphics. Отсекаемый прямоугольник является прямоугольной областью, которая содержит все недействительные пиксели экрана. Отсекаемый прямоугольник определяется его отклонением (х, у) от начала координат объекта Graphics, а также его шириной и высотой. Вы можете получить отсекаемый прямоугольник, вызвав следующие методы int getClipHeight () int getClipWidth () int getClipX() int getClipY() При вызове метода paint (Graphics g) отсекаемый прямоугольник всегда представляет область, которая содержит все поврежденные пиксели дисплея. В случаях, подобных примерам, приведенным в этой главе, где вы заменяете отображение экрана новым, отсекаемый прямоугольник представляет всю область дисплея устройства. Самый легкий способ «стереть» недействительные пиксели — это перерисовать каждый пиксель в отсекаемом прямоугольнике с помощью цвета фона экрана, таким образом гарантировав, что вы стерли все поврежденные пиксели. Затем вы выполняете операции по рисованию, которые определяются вашим Canvas, с помощью другого цвета. Обратите внимание, что в листинге 6.7 метод получает и сохраняет текущий цвет дисплея, который представляет цвет ручки, используемый для всех операций рисования. По умолчанию цвет обычно черный в большинстве реализаций. Код затем устанавливает текущий цвет на белый (который обычно является цветом фона) и заполняет отсекаемый прямоугольник белыми пикселями, эффективно «стирая» все поврежденные пиксели. В конце код восстанавливает первоначальный цвет объекта Graphics. Последующие операции по рисованию визуализируют пиксели некоторого цвета, отличающегося от белого, на белом фоне. В некоторых случаях отсекаемый прямоугольник может представлять некоторую часть дисплея. В этих случаях только некоторая часть дисплея была повреждена. Ваше приложение может выбрать простую перерисовку всего экрана, но ему необязательно делать это. Оно может просто также перерисовать лишь поврежденную область. Поврежденная область, которая нуждается в перерисовке, является пересечением области, используемой вашим Canvas, и отсекаемым прямоугольником. Вы можете определить, какие из пикселей вашего дисплея относятся к этой области, наложив отсекаемый прямоугольник на область, которую, как вы знаете, ваш Canvas использует для отображения. Метод void clipRect(int x, int у, int width, int height) устанавливает отсекаемый прямоугольник как пересечение текущего отсекаемого прямоугольника и прямоугольника, определенного аргументами, — области, используемой вашим Canvas. Ваше приложение может затем вычислить, какие из пикселей относятся к этому новому отсекаемому прямоугольнику, и перерисовать их. Вызов clipRect () всегда создает отсекаемый прямоугольник меньшего размера. Вы можете также установить любой размер отсекаемого прямоугольника с помощью следующего вызова: setClipfint x, int у, int width, int height) Ваш Canvas нуждается в перерисовке только тех пикселей, которые подпадают под область пересечения, поскольку отсекаемый прямоугольник гарантирует включение всех поврежденных пикселей. Конечно, вычисление этой области может быть более сложным, чем простая перерисовка всего Canvas. Но закрашивание только отсекаемого прямоугольника полезно для приложений, которые используют сложную или отнимающую много времени обработку при вычислении того, какие пиксели нужно закрашивать. Другим стандартным применением отсечения является разработка игр. Стандартное приложение является каркасом, в котором вы хотите переносить фантом, являющийся небольшим изображением или значком. Используя область отсечения, как показано в листинге 6.7, вы рисуете фон области, где фантом расположен в настоящее время, а затем вы рисуете фантом в его новой позиции. На самом деле на реальном устройстве, которое не поддерживает двойной буферизации, реализация, показанная в листинге 6.7, может производить довольно заметное и разрушительное мерцание экрана при его обновлении. Вы, вероятно, не заметите никакой вспышки лри использовании эмулятора из-за скорости вашего компьютера. В разделе «Двойная буферизация» далее в этой главе вам будет показано, как справиться с этой проблемой. Рисование — это процесс изменения состояния объекта Graphics. Визуализация — это процесс отображения закрашенных пикселей на экране. Вы никогда не сможете формировать изображение за пределами отсекаемого прямоугольника. Координаты, переданные процедурам рисования, всегда являются интерпретированными по отношению к первоначальному отсекаемому прямоугольнику. Операции по рисованию, которые лежат вне границ отсекаемого прямоугольника, не влияют на визуализацию, они не появляются на экране. Отрицательные значения координат х и у относятся к пикселям, лежащим за пределами отсекаемого прямоугольника. Хотя вы никогда не сможете формировать изображение за пределами отсекаемого прямоугольника, вы можете рисовать где угодно, даже за пределами отсекаемого прямоугольника. Вы можете даже рисовать за границами обьекта Graphics. Вы можете реализовать панорамирование или перемещение изображения, изменяя координаты х и у начала координат при рисовании. Как вы уже знаете, точка (х, у) указывает функции рисования место, расположенное относительно точки (0, 0). Точка (0, 0) является началом координат Graphics. Когда вы впервые получите ссылку на Graphics вашего Canvas, его начало координат, точка (О, О), всегда представляет верхний левый угол дисплея устройства. void translate(int x, int у) Аргументы являются координатами точки, которая станет новым началом координат объекта Graphics. Точка (0, 0) теперь является этим новым началом координат. Все операции по рисованию теперь относятся к этому новому началу координат. На рисунке 6.9 показан экран, созданный кодом, описанным в листинге 6.8. Он просто рисует заполненный квадрат в Canvas. При нажатии на кнопку Go начало координат Graphics переносится, а затем заполненный квадрат перерисовывается. На рисунке 6.10 показан обновленный дисплей после того, как кнопка Go была нажата в первый раз. Обратите внимание, что координаты, переданные вызовам методов рисования в методе paint (Graphics g) не изменились. Причина этого кроется в том, что эти координаты всегда связаны с началом координат Graphics, а не с верхним левым углом области дисплея устройства. Операции по рисованию всегда указываются относительно начала координат Graphics, безотносительно к точке места назначения, которое она представляет. Нажатием на кнопку Go вы на самом деле переключаете перемещение. Нажатие на кнопку во второй раз перемещает начало координат назад к верхнему левому углу дисплея. Рисунок 6.10. Дисплей после перемещения начала координат. Перемещение означает перенос начала координат объекта 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 для того, чтобы отобразить предыдущий внеэкранный рисунок. Вы, возможно, заметили, что метод 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 демонстрируется использование двойной буферизации. Код выполняет несколько простых функций рисования во внеэкранном буфере, затем копирует содержимое этого буфера в саму графическую среду, которая представляет дисплей устройства. Хотя процедуры рисования в этом примере относительно просты, реальное приложение может выполнять намного более сложное рисование, действительно подтверждая необходимость двойной буферизации. 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 lt; 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 () для получения внеэкранного графического контекста. Приложение может рисовать в этом контексте. Оно затем связывает этот внеэкранный графический контекст с самим устройством. MIDP не имеет такого вызова. Единственной ссылкой на объект Graphics, которая связана с реальным устройством, является та, что передается методу paint (Graphics g) Canvas. Вы уже узнали в главе 5, что некоторые компоненты высокоуровневого пользовательского интерфейса MIDP умеют отображать изображения, например, как часть элемента в ChoiceGroup. Объекты Canvas также могут отображать изображения. Кроме рисования базовых геометрических фигур, объект Canvas может «рисовать» изображения с помощью того же контекста Graphics, который он использует для низкоуровневых функций рисования. MIDP поддерживает только формат изображений PNG. На рисунке 6.12 показано изображение, отображаемое в Canvas. В листинге 6.10 показана исходная программа, создающая изображение, показанное на рисунке 6.12. Структура программы сходна с другими демонстрационными программами Canvas, приведенными в этой главе. 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. Название метода изображения — Описание 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. При рисовании изображений двойная буферизация осуществляется автоматически. |
||||||||||||||||||||||||
|