DateField
На главном экране демонстрационного приложения UlComponent (смотри http://www.phptr.com/) вторым элементом списка является демонстрационная версия класса DateField. На рисунке 5.1 показано, что DateField является разновидностью Item; как таковой, он должен быть частью Form для того, чтобы быть отображаемым. В листинге 5.5 показан исходный код файла DateFieldDemo.java.
Другие экранные типы
Вы видели все компоненты MIDP за исключением одного: TextBox. В отличие от TextField TextBox является многострочной редактируемой текстовой областью. Взгляните еще раз на наглядную иерархию наследования, показанную на рисунке 5.1, и вы увидите, что TextBox является видом Screen, а не Item.
Поскольку TextBox является Displayable, вы должны создать объект MID-лета для демонстрации его использования, вы не можете разместить его в другом Screen или Form, как вы могли поступить с компонентами, происходящими от Item. На рисунке 5.11 показан экран TextBoxDemo.
Другие компоненты Item
В предыдущих примерах описывались некоторые компоненты, которые создают основу всех приложений MIDP. В оставшейся части главы вы увидите остальные компоненты пользовательского интерфейса.
Платформа программирования J2ME для портативных устройств
Класс Gauge также является производным от Item. Запуск GaugeDemo из основного экрана создает дисплей, показанный на рисунке 5.8.
Иерархия Компонентов пользовательского интерфейса MIDP
Диаграмма иерархии наследования MIDP, показанная на рисунке 5.1, повторяет то, что вы уже видели на рисунке 3.7 в главе 3. Вы уже видели некоторые из компонентов пользовательского интерфейса MIDP, показанные в этой иерархии, а именно Displayable, Screen, Form и Alert.
Вы знаете, что класс Displayable определяет природу основы любого компонента, который может быть отображен, и что класс Screen определяет базовую абстракцию пользовательского интерфейса MIDP - экран. Класс Screen является первым Displayable, который вы видели, a Form был первым конкретным типом используемого экрана.
В таблице 5.1 кратко описаны все компоненты пользовательского интерфейса MIDP в пакете javax.micfoedition.lcdui.
Imageltem
Несколько компонентов пользовательского интерфейса MIDP поддерживают отображение изображений. На рисунке 5.10 показано изображение, отображенное в форме. В листинге 5.9 показан исходный код для программы, которая отображает рисунок 5.10.
Рисунок 5.10. Несколько компонентов пользовательского интерфейса MIDP поддерживают отображение изображений. Здесь форма содержит компонент Image Item, который отображает изображение
Экранная навигация
На данный момент вы познакомились со следующими компонентами пользовательского интерфейса:
MIDlet;
Display;
Displayable;
Form;
List;
Alert;
ChoiceGroup;
TextField.
Вы уже можете создавать приложения MIDP -с их помощью. Демонстрационная программа, показанная в листинге 5.3, обращается к другому атрибуту программ с графическим пользовательским интерфейсом: экранной навигации. Если вы возвратитесь назад и взглянете на приложение, описанное в листинге, более внимательно, вы увидите, что вы можете перейти назад к предыдущему экрану из любой точки. Это свойство присутствует в большинстве программ с графическим интерфейсом пользователя.
Однако такое поведение в MIDP не является автоматическим. Только один Displayable видим в любой момент времени и реализация не отслеживает какой-либо информации об отображаемых экранах.
Переход «вперед» легок. Как демонстрируется в приложениях, вы просто создаете следующий Displayable и делаете запрос на его отображение. Но переход «назад» немного сложнее. Вам придется убедиться, что у вас есть действующая ссылка на экранный объект, к которому вы хотите возвратиться.
Обратите внимание, что каждый класс, который вы видели до сих пор в демонстрационной программе, поддерживает ссылку на экземпляр, созданный приложением. В UIComponentDemo.java, например, это следующее объявление элемента:
projected static Displayable instance;
Это объявление имеет следующий сопутствующий метод:
public static Displayable getlnstance()
{
return instance;
}
Данйый метод объявляется с модификатором static, так что на него можно легко создать Ссылку из любого места в приложении без создания экземпляра класса, содержащего этот метод - таким образом можно избежать неправильного цикла работы приложения.
Приложение AlertDemo предоставляет экранную клавишу Back (Назад) на экране Build Alert (Создание уведомления), показанном на рисунке 5.3. Если вы нажмете эту клавишу, вы вернетесь обратно в главное окно. Посмотрите вновь на метод commandActionO данной программы, которая показана в листинге 5.4.
Экраны и экранные элементы
Первый пример в этой главе показывает вам основную разницу между двумя типами компонентов пользовательского интерфейса MIDP: компонентами Displayable и компонентами Item. Иерархия наследования, изображенная на рисунке 5.1, ясно отображает Эти две категории. Иерархия Displayable заключает в себе экраны, которые вы отображаете. Иерархия Item классифицирует элементы, которые могут быть собраны в один экран. Следующие примеры демонстрируют использование различных компонентов пользовательского интерфейса MIDP. Мы объясняем их использование по мере ознакомления с каждым.
В листинге 5.1 показан файл под названием UIComponentDemo.java, который определяет исходный код новой программы, демонстрирующий использование элементов MIDP. Этот файл использует код в других файлах, которые вместе составляют полную демонстрационную программу компонента пользовательского интерфейса.
Исходный код UlComponentDemo
import javax.raicroedition.midlet.MIDlet;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui .CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.Icdui.List;
/**
Демонстрируется использование высокоуровневых компонентов
пользовательского интерфейса MIDP. Этот демонстрационный класс создает
список демонстрационных программ для выбора пользователем. Элементы
в списке являются на самом деле именами первичных классов
демонстрационных программ. MID-лет создает экземпляр класса,
представленного среди элементов списка, выбираемого пользователем
и затем выполняемого им.
*/
public class UlComponentDemo extends MIDlet
implements CommandListener
private Command exit = new Command("Exit", Command.EXIT, 1);
// Имена различных демонстрационных программ: Элементы в этом списке
// являются именами первичных .классов для каждой демонстрационной
// программы, private static String [] demos =
"AlertDemo",
"DateFieldDemo",
"GaugeDemo",
"StringltemDemo", "TickerDemo",
"ImageltemDemo"
}i;
private static UIComponentDemo instance = null;
// Реальный компонент List, который отображает элементы,
// перечисленные в списке «demos» выше.
private List mainMenu = new List ("Select demo", Choice.IMPLICIT,
demos, null) ;
// Конструктор No-arg. public UIComponentDemo()
// Обратите внимание на вызов super(). Он выполняет
// конструктор no-arg в классе MID-лета. super () ;
instance = this;
}
/**
Возвращает один экземпляр этого класса. Вызов этого метода перед
созданием объекта возвратит пустой указатель.
^возвращает экземпляр этого класса.
*/
public static UIComponentDemo getlnstance()
{
return instance;
{
public void startApp()
{
Display display;
mainMenu.addCommand(exit);
mainMenu.setCommandListener(this) ;
*
display = Display.getDisplay(this);
display.setCurrent(mainMenu) ;
public void pauseAppf)
{
}
void quit() ,;
destroyApp(true);
notifyDestroyed();
)
public void destroyApp(boolean destroy)
(
}
public void display!)
}
Display.getDisplay(this).setCurrent(mainMenu);
}
public void commandAction(Command c, Displayabie d)
{
Displayabie displayable = null;
if (c == List.SELECT_COMMAND)
{
int index = mainKenu.getSeiectedlndex();
try
{
displayable = (Displayable)
Class.forName(demos[index]).new!nstance();
if (displayable == null)
}
return;
}
Display display = Display.getDisplay(this);
display.setCurrent(displayable);
}
catch (Exception e)
{
System.out.println("Got exception here!!!");
e.printStackTrace() ;
return;
}
}
else if (c == exit) 1 quit() ;
}
}
}
Код, описанный в листинге 5.1, является первым примером, потому что он создается с использованием одного вида экранного объекта. Экран является ядром организационной основы всех MID-летов.
В листинге 5.1 определяется MID-лет. Его высокоуровневый экран является компонентом List, который отображает список вариантов, отражающих различные элементы, которые демонстрирует программа. На рисунке 5.2 показан список верхнего уровня демонстрационных приложений, которые вы можете запустить. Этот основной экран является экземпляром List.
Обратите внимание на стрелку на экране, указывающую вниз. Она указывает, что существуют еще элементы, для которых недостаточно места на экране. Если вы прокрутите немного вниз, стрелка, указывающая вниз, исчезнет, и вместо этого появится стрелка, указывающая наверх. Эти стрелки размещены на экране реализацией компонента List.
List является видом Screen, который, конечно, является Displayable, и приспосабливается к знакомой ему общей структуре приложения. Вы можете видеть в листинге 5.1, что экземпляр List является отображаемым в настоящее время, по существу это объект, который получает события вызова команды. Сам MID-лет является блоком прослушивания таких событий, регистрируя себя как CommandListener для этих событий.
Он реализует интерфейс CommandListener, а также определяет метод commandAction () .
Альтернативным способом создания блоков прослушивания является создание самого компонента блока прослушивания событий, которые в нем происходят. Чтобы выполнить это, однако, вам бы пришлось создать в классе компонента подклассы, в данном случае создав подкласс класса List. Я выбрал первый подход и использую стандартный класс List без создания подклассов.
На рисунке 5.2 изображен список демонстрационных программ компонентов пользовательского интерфейса. Имена, которые вы видите, являются именами основных классов для каждой демонстрационной программы. При выборе одного из них выполняется соответствующая демонстрационная программа. Конечно, вы должны откомпилировать демонстрационные программы прежде, чем пытаться их запустить. Иначе вы получите ошибку ClassNotFoundException.
Если вы используете J2ME Wireless Toolkit, вам нужно только поместить ваши исходные файлы в директорию проекта UIComponents/src/. Затем создайте проект. Wireless Toolkit откомпилирует все исходные файлы в директории sic/. Он запустит верификатор предварительной проверки и, наконец, разместит файлы .class в директории проекта classes/. С этого момента вы можете выполнять демонстрационные программы, перечисленные в основном окне MID-лета.
В следующем примере я сначала компилирую, а затем делаю доступной программу AlertDemo, первый элемент в списке. Чтобы запустить откомпилированную демонстрационную программу, просто выберите AlertDemo из списка, показанного на рисунке 5.2. Повторяйте эти шаги создания и выполнения для каждой из остальных демонстрационных программ.
На рисунке 5.3 показан экран, который появляется, когда вы выбираете элемент AlertDemo из списка демонстрационных программ верхнего уровня. Этот экран отображает другой набор элементов - набор типов уведомлений - с помощью другого компонента MIDP, называемого ChoiceGroup. Экран, содержащий типы уведомлений, создается кодом в файле AlertDemo.java, показанном в листинге 5.2.Выбор одного из элементов на этом экране создает и отображает экземпляр этого типа компонента Alert.
Иерархия наследования, изображенная на рисунке 5.1, показывает, что ChoiceGroup не является ни Screen, ни Displayable. Это вид Item. Вспомните из главы 3, что Item является компонентом, который может быть агрегирован в Form. Обратите внимание, что класс AlertDemo дополняет Form, который дает ему возможность агрегировать элементы TextField и ChoiceGroup.
На рисунке 5.3 вы видите Form - экземпляр AlertDemo - который содержит объекты ChoiceGroup и TextField. Вспомните, что Form является единственным компонентом MIDP, который может включать другие компоненты. Таким образом, программа AlertDemo должна использовать Form для хранения элементов ChoiceGroup и TextField.
Уведомления являются
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.Icdui.TextField;
/**
Демонстрирует использование объектов Alert.
*/
public class AlertDemo extends Form implements CommandListener
{
private Command go = new Command("Go", Command.SCREEN, 1);
private Command back = new Command ("Back", Command.BACK, 1);
private ChoiceGroup type; private TextField tPref;
private String [] elements =
{
"Alarm", "Confirmation", "Error", "Information", "Warning" );
// Это необходимо/ чтобы другие экраны могли ссылаться
// на экземпляр этого класса, private static Displayable instance;
/**
Конструктор.
*/
public AlertDemo()
{
'super ("Build alert");
type = buildAlertTypeSelection ();
tPref = buildTimeoutPrefPrompt();
append(type);
appendftPref) ;
addCommand(go);
addCommand(back);
setCommandListener(this) ; instance = this;
}
/**
Возвращает единственный экземпляр этого класса.
Вызов этого метода перед созданием объекта возвращает Пустой указатель.
@возвращает экземпляр этого класса.
*/
static Displayable getlnstance ()
{
return instance;
}
private ChoiceGroup buildAlertTypeSelection ()
{
// He работает, если это Choice.IMPLICIT. Смотри документацию Choice.
// Тип IMPLICIT действителен только для объектов List,
return new ChoiceGroup ("Alert Type", Choice.EXCLUSIVE, elements, null);
}
private TextField buildTimeo-utPref Prompt ()
}
String MAX_TIMEOUT_VALUE = "5"; int MAX_SIZE = 8;
return new TextField("Timeout (sec.)", MAX_TIMEOUT_VALUE,
MAX_SIZE, TextField.NUMERIC);
}
public void comraandAction(Command c, Displayable d)
{
UIComponentDemo demo = UIComponentDemo.getlnstance();
Display display = Display.getDisplay(demo);
int timeSec; int timeMillis;
if (c == go)
// Уведомления не принимают определенные приложением команды.
String title = elements[type.getSelectedlndex()]; 1;
Alert alert = new Alert (title) ;
alert.setString("A '" + title + "' alert");
timeSec = Integer . parselnt(tPref.getString());
timeMillis = timeSec * 1000; if (timeMillis <= 0)
(
timeMillis = Alert.FOREVER;
}
alert.setTimeout(timeMillis);
display.setCurrent(alert, AlertDemo.getlnstance());
}
if (c == back)
(
UIComponentDemo.getlnstance().display ();
}
)
}
Когда вы будете экспериментировать с этим приложением, обратите внимание, что вы можете прокрутить List вверх и вниз, выделяя различные элементы List, но программного выбора событий не осуществляется. Подобным образом на экране Build Alert (Создание уведомления) вы можете прокручивать и многократно выбирать элементы ChoiceGroup без активации какого-либо действия.
В обоих случаях событий не генерируется, пока вы не вызовете активацию команды. На экране List вы должны нажать на кнопку выбора Select, чтобы перейти к экрану Build Alert (Создать уведомление). Когда вы окажетесь на экране Build Alert (Создать уведомление), вы должны выбрать экранную кнопку Go, чтобы просмотреть отображенный Alert. Изменение выбора в любой реализации Choice не активирует какую-либо Command в компоненте.
Оба экрана, изображенные на рисунках 5.2 и 5.3, показывают наборы элементов, из которых пользователь может сделать выбор. Оба компонента List и ChoiceGroup реализуют интерфейс javax.microedition.ldcui.Choice, который указывает характеристики поведения компонентов, поддерживающих выбор одного или более своих элементов. Интерфейс Choice определяет три константы:
IMPLICIT (Неявный): выбирается элемент, на котором в настоящее время сфокусировано внимание.
EXCLUSIVE (Исключающий): может быть выбран один-единственный элемент.
MULTIPLE (Множественный): могут быть выбраны несколько элементов.
Только объекты List могут устанавливать активацию IMPLICIT. Когда вы активизируете клавишу выбора Select устройства при неявном List, какой бы элемент List и был бы выделен в данный момент, он будет выбран. Листинг 5.1 демонстрирует эту неявную команду. ChoiceGroup не может быть неявным. Конструктор ChoiceGroup сбрасывает IllegalArgumentException, если вы пытаетесь создать его экземпляр с типом Choice.IMPLICIT.
Есть еще один тип информации, которая может быть собрана из этого неявного List. Ранее я говорил, что событие команды посылается в Displayable в ответ на нажатие пользователем кнопки Select на устройстве. Тип этой команды, однако, отличается от любого из типов, которые определяет класс Command.
Класс List определяет особый объект Command, List.SELECT_COMMAND. Активация списка IMPLICIT генерирует эту особую команду и посылает ее в блок прослушивания команд без какой-либо явной операции выбора, осуществляемой пользователем. Истинная цель этой команды заключается в том, чтобы дать возможность методу блока прослушивания commandAction() распознать активацию операции выбора устройства. В листинге 5.3 показано, как метод UIComponentDemo.commandAction() использует эту специальную константу.
Блок прослушивания
public .class UIComponentDemo extends MIDlet .
implements CommandListener
{
public void cornrnandAction (Command c, Displayable d)
{
Displayable displayable = null;
if (c == List.SELECT_COMMAND)
}
int index = mainMenu.getSelectedlndex ();
try i displayable = (Displayable)
Class.forName(demos[index]).new Instance));
Display display = Display.getDisplay(this);
display.setCurrent(displayable);
}
,catch (Exception e)
}
e.printStackTrace();
return;
}
}
else
{
return;
}
}
Названия типов выбора EXCLUSIVE и MULTIPLE говорят сами за себя. Реализации MIDP , визуализируют значки отображения выбора различно для исключающего и множественного списков. Исключающие списки выбора имеют кружок слева от текста элемента, сходный с селективными кнопками в приложениях AWT и Swing, и внутреннюю точку, показывающую выбранный элемент. Множественные списки выбора визуализируют компонент с квадратиком слева от текста элемента, сходным с кнопками для отметки в приложениях AWT и Swing.
Вы уже видели пример Alert в главе 3, здесь вы видите его вновь. Метод commandAction() класса AlertDemo создает пять различных уведомлений в зависимости от данных, которые пользователь вводит в экран Build Alert (Создание уведомления), показанный на рисунке 5.3. Конструктор класса Alert принимает значение AlertType, которое отражает тип уведомления, изменяющийся в зависимости от создания. Класс AlertType определяет пять констант, которые представляют собой возможные типы уведомлений, показанные в таблице 5.2.
Таблица 5.2. Константы класса AlertType, которые представляют собой возможные типы объектов Alert
Константа класса AlertType | Описание | ||
ALARM (внимание) | Уведомление, которое отображает появление аварийного события | ||
CONFIRMATION (подтверждение] | Диалоговое окно, которое запрашивает у пользователя подтверждение действия | ||
ERROR (ошибка) | Диалоговое окно, которое уведомляет пользователя об ошибке | ||
INFO (инфо) | Диалоговое окно, в котором присутствует информационное сообщение для пользователя | ||
WARNING (предупреждение) | Диалоговое окно, которое показывает предупреждение |
Внешний вид уведомления не изменяется в зависимости от типа уведомления. Цель типов уведомлений заключается в том, чтобы дать программисту возможность более легко различать различные объекты уведомлений. Это также дает реализации возможность отображать отдельные типы уведомлений по-разному.
Тип уведомления не влияет на его поведение. Вы видели сходную организацию объектов Command в приложениях HelloWorld. Простое присвоение определенного типа Command не изменяет его поведение никоим образом. Выбор остается за вами как за программистом в создании последовательности тем способом, которым вы обращались со сходными типами объектов Command и Alert.
Если вы запустите программу, приведенную в примере, вы увидите, что экраны уведомлений не имеют команд, связанных с ними, на самом деле они и не могут их иметь. Вы также заметите, что экраны уведомлений исчезают через 5 секунд и возвращают экран Build Alert (Создание уведомления). Причина этого кроется в том, что программа установила по умолчанию 5-секундную длительность для всех уведомлений.
Величина длительности появления уведомления должна быть больше 0. Установление значения менее 0 приведет к IllegalArgumentException. Вы устанавливаете время истечения уведомления с помощью метода Alert.setTimeout(). Если вы укажете константу Alert.FOREVER, реализация поместит экранную клавишу Done (Готово) на уведомление. Уведомление будет оставаться открытым до тех пор, пока пользователь не нажмет Done (Готово).
В демонстрационной программе (которую вы можете найти в Web на сайте http://www.phptr.com), прокрутите вниз экран Build Alert (Создание уведомления) и вы увидите объект текстового поля, который содержит строку «5». Вы можете отредактировать этот объект TextField, который является другим компонентом пользовательского интерфейса, чтобы изменить значение времени истечения. Если вы укажете 0, приложение создаст уведомление с FOREVER (НИКОГДА) в качестве времени истечения.
TextField является последним новым компонентом, который вводит эта демонстрационная программа.TextField также является разновидностью Item, как показано на рисунке 5.1. TextField - это один из двух компонентов для ввода текста. Другим является TextBox, который мы обсудим далее в этой главе. Компоненты для ввода текста используют понятие ограничения ввода, которое ограничивает ввод до определенного набора разрешенных знаков, определяемого действующими ограничениями компонента.
Класс TextField определяет различные виды ограничений, устанавливаемые константами, перечисленными в таблице 5.3.
Блок прослушивания
public void commandAction(Command c, Displayable d)
{
UIComponentDemo jiemo = UIComponentDemo.get Instance ();
Display display = Display.getDisplay(demo);
int timeSec;
int cimeMillis;
if (c == go)
}
// Уведомления не принимаются приложением, определяющим Commands.
String title = elements[type.getSelectedlndex()];
Alert alert = new Alert(title) ;;
alert.setString("A '" + title + "' alert");
timeSec = Integer.parselnt(tPref.getString());
timeMillis. = timeSec * 1000;
if (timeMillis <= 0)
}
timeMillis = Alert.FOREVER;
}
alert.setTimeout(timeMillis);
display.setCurrent(alert, AlertDemo.getlnstancef));
}if (c == back)
}
UIComponentDemo.getInstance().display!);
}
Если команда является командой Back (Назад), этот метод показывает предыдущий экран, пересылая экземпляр List, созданный в UIComponentDemo.java, в метод Display.setCurrent(). Если UIComponentDemo.getlnstance() не был объявлен static, получить ссылку на объект List будет сложно.
В соответствии с этой идиомой метод AlertDemo.getlnstance () возвращает ссылку на экземпляр, к которому дисплей должен вернуться, после того как уведомление будет закрыто. В таком случае может быть использована ссылка this. Но метод getlnstance() может стать доступным, если приложение будет позже усовершенствовано. Тем не менее, важным моментом является использование идиомы, которая делает ссылки на экраны легко доступными.
Первыми двумя строками метода commandAction () являются следующие:
UIComponentDemo demo = UIComponentDemo.get Instance ();
Display display = Display.getDisplay(demo);
Эти строчки используют ту же идиому для легкого получения ссылки на MID-лет. Класс UIComponentDemo определяет этот статический метод, который освобождает вас от вынужденного кодирования следующей строки каждый раз, когда вам понадобится создать ссылку на дисплей:
Display.getDisplay(UIComponentDemo.getMIDiet() ) ;
Конечно, это не единственный способ осуществлять экранную навигацию. Другой метод заключается в поддержке набора ссылок на объекты Displayable. Вы можете поместить объект Displayable в набор, когда вы сделаете его текущим отображаемым объектом. Чтобы перейти назад к предыдущему экрану, вытолкните его из стека и установите его текущим Displayable.
Безотносительно к методу, который вы выбрали, смысл в том, что ваша программа должна «знать» следующий экран для отображения. Иногда вы захотите вернуться назад к предыдущему экрану. В других случаях вы можете захотеть перейти на два или более экрана назад или к некоторому произвольному экрану. Вы можете даже использовать комбинацию вышеописанных подходов для выполнения нужной вам навигации.
Поскольку экраны
import Java.util.Date;
import Java.util.Calendar;
import Java.util.TimeZone;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.Displayable;
import javax.
microedition.lcdui.Form;
/**
Демонстрирует использование класса DateField пользовательского интерфейса MIDP.
@смотри javax.microedition.Icdui.DateField
public class DateFieldDemo extends Form implements CommandListener
private Command back = new Command("Back", Command.BACK, 1);
private static Displayable instance;
private DateField date = new DateField("Date/Time in GMT",
DateField.DATE_TIME, TimeZone.getDefault () ) ;
/**
Конструктор.
*/
public DateFieldDemo()
}
super ("DateField Demo");
Calendar cal = Calendar.getlnstance();
date.setDate(cal.getTime()) ;
append(date);
addCommand (back);
setCcmmar.dListener (this) ;
instance = this;
}
/**
Возвращает один экземпляр этого класса. Вызов этого
метода перед созданием объекта возвращает пустой.указатель.
@Возвращает экземпляр этого класса.
*/
public static Displayable getlnstance ()
{
return instance;
}
public void commandAction(Command c, Displayable d)
{
if (c == back)
{
UI ComponentDemo.get Instance().display() ;
}
}
}
Прежде всего, обратите внимание, что DateFieldDemo дополняет класс Form. Конструктор просто добавляет объект DateField к форме и необходимая структура сформирована. Другие методы класса DateFieldDemo сходны с предыдущими примерами, так что я не буду их описывать здесь еще раз.
DateField является простым текстовым элементом, который отображает дату и время. На рисунке 5.4 показан экран дата/время, отображаемый DateFieldDemo.
Первая строка на рисунке 5.4 «Date/Time in GMT» («Дата/время в GMT») является меткой и определяется в первом аргументе конструктора. Вторая строчка является датой, а третья - временем. Конструктор no-arg DateFieldDemo в листинге 5.5 демонстрирует, как устанавливать дату в объекте DateField с помощью объекта Java.util .Calendar.
В этом примере указываются дата и время, потому что вызов конструктора устанавливает отображение обоих значений. Класс DateField определяет три константы (перечисленные в таблице 5.4), которые позволяют вам контролировать то, какая информация отображается.
Таблица 5.4. Константы DateField для управления отображением информации о дате и времени
Константа DateField | Описание |
public static int DATE | Отображает только дату |
public static int DATE TIME | Отображает дату и время |
public static int TIME | Отображает только время |
Вызов конструктора DateField может определять временную зону, которая не поддерживается вашей реализацией MIDP. Если временная зона, которую вы указали в конструкторе, не поддерживается вашей реализацией MIDP, ваша программа все равно будет выполняться без ошибки или предупреждения, но временная зона объекта DateField будет представлять собой какую-либо зону, поддерживаемую реализацией, но не ту, которую вы запрашивали. И время, отображаемое на экране, будет отражать временную зону, используемую объектом DateField, вместо временной зоны, которую вы указали в вызове конструктора.
Объекты DateField являются редактируемыми. Чтобы отредактировать их,
Во-первых, выберите поле даты, показанное на рисунке 5.4.
Нажмите на кнопку выбора Select эмулятора устройства. Вы увидите, что дисплей изменился на тот, что изображен на рисунке 5.5.
Прокрутите вверх и вниз, чтобы выделить год, месяц или день, и измените каждый из них по желанию.
Обратите внимание, что реализация размещает экранные клавиши Back (Назад) и Save (Сохранить) на экране. Такое представление интерфейса типично для всех редактируемых компонентов.Когда вы закончите редактирование и вернетесь к предыдущему экрану, время и дата, показываемые на дисплее, изменятся.
На главном экране DateFieldDemo, показанном на рисунке 5.4, вы можете прокрутить до поля времени и, нажав, выбрать его. Дисплей затем покажет экран, изображенный на рисунке 5.6.
Четырьмя параметрами
import javax.microedition.Icdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.Icdui.Displayable;
import javax.microedition.Icdui.Form;
import javax.microedition.Icdui.Gauge;
/**
Этот класс демонстрирует использование класса
Gauge пользовательского интерфейса MIDP.
Усмотри javax.microedition.Icdui.Gauge
*/
public class GaugeDemo extends Form
implements CommandListener
}
private String gaugelLabel = new String("Interactive gauge");
private Gauge interactiveGauge = new Gauge("Interactive", true, 50, 15);
private String gauge2Label = new String("Non-interactive");
private Gauge staticGauge = new Gauge ("Static", false, 50, 25);
/**
Конструктор.
*/
public GaugeDemol)
}
super("Gauge Demo");
append(gaugelLabel);
append(interacciveGauge);
append(gauge2Label);
append(staticGauge);
}
addCommand(back);
setCoramandListener(this);
instance = this;
}
...
}
В отличие от демонстрационной версии, настоящее приложение, вероятно, также изменяет значение измерителя в течение своего жизненного цикла, используя следующие методы в классе Gauge:
public void setValue(int value) public int getValuel)
Исходный код демонстрационной программы Ticker
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.raicroedition.lcdui.Ticker;
import javax.raicroedition.lcdui.Form;
/**
Этот класс демонстрирует использование класса
Ticker пользовательского интерфейса MIDP.
@see javax.microedition.lcdui.Gauge
*/
public class TickerDerno extends Form
implements CommandListener
}
private String str = "This text keeps scrolling until the demo stops...";
private Ticker ticker = new Ticker(str);
private Command back = new Command("Back", Command.BACK, 1);
private static Displayable instance;
/**
Конструктор.
*/
public TickerDemo()
{
super("Ticker demo");
instance = this;
addCommand(back);
setTicker(ticker) ; setCommandListener(this);
{
...
}
Однако вы можете связать один и тот же объект Ticker с несколькими экранами. Реализация отображает Ticker на некоторой постоянной части дисплея, в данном случае наверху дисплея.
Взглянув на рисунок 5.1 еще раз, вы заметите, что Ticker не является Item. Он является производным непосредственно от Java.lang.Object, что подсказывает вам, почему Ticker может быть привязан к дисплею, а не к экрану. Его не нужно извлекать из Item, поскольку он на самом деле не является чем-то, что размещено в Form.
Конструктор создает
import javax.microedition.lcdui.Command;
import javax.microedition.Icdui.ComraandListener;
import javax.microedition.Icdui.Displayable;
import javax.microedition.Icdui.Form;
import javax.microedition.Icdui.Image;
import javax.microedition.Icdui.Imageltem;
import Java.io.lOException;
/**
Этот класс демонстрирует использование класса
Imageltem пользовательского интерфейса MIDP.
Усмотри javax.microedition.Icdui.Imageltem
*/
public class ImageltemDemo extends Form implements CommandListener
{
private Imageltem imageltem;
/**
Конструктор.
@сбрасывает lOException, если указанный ресурс изображения не может быть найден.
public ImageltemDemo() throws lOException
*/
super("Imageltem Demo");
String path = "/bottle80x80.png";
Image image = Image.createlmage(path);
imageltem = new Imageltem)"Ship in a bottle", image,
Imageltem.LAYOUT_CENTER,
"Image not found");
append(imageltem);
addCommand(back);
setCommandListener(this) ;
instance = this;
}
...
}
В листинге 5.9 демонстрируется использование класса Imageltem компонента пользовательского интерфейса MIDP. Imageltem является подклассом Item, так что он должен быть размещен в Form, как было продемонстрировано в листинге.
Прежде чем вы сможете отобразить изображение, вы должны создать объект изображения. Класс javax.microedition.lcdui.Image определяет изображения. Чтобы создать экземпляр Image, укажите имя пути к файлу изображения. Файлы изображений должны храниться в формате Portable Network Graphics (PNG). J2ME поддерживает работу с изображениями только в этом формате.
Обратите внимание, что в листинге 5.9 имя пути файла изображения связано с директорией res/ директории проекта UlComponents. Директория res/ содержит все файлы ресурсов, включая файлы изображений. Если вы разместите свои изображения где-либо еще, они не будут найдены и ваша программа сбросит lOException, когда попытается открыть файл.
В листинге 5.9 конструктор создает Imageltem с помощью только что созданного объекта Image.
Параметрами конструктора являются строка заголовка, которая отображается над изображением, объект изображения, указание размещения изображения и текстовая строка, которая будет показана в случае, если изображение не может быть отображено по какой-либо причине.
Класс Imageltem является единственным классом, который предоставляет контроль расположения изображений, но некоторые из компонентов пользовательского интерфейса MIDP также используют изображения. В таблице 5.5 перечислен полный набор компонентов интерфейса пользователя MIDP, которые используют изображения.
Таблица 5.5. Компоненты пользовательского интерфейса MIDP, которые используют изображения
Компонент пользовательского интерфейса MIDP | Описание |
Alert | Изображение отображается вместе с текстом |
ChoiceGroup | Изображение отображается слева от текста каждого элемента |
List | Изображение отображается слева от текста элемента |
Imageltem | Предоставляет контроль размещения самого объекта изображения |
Текстовые окна являются экранами и не нуждаются в форме, в которой можно существовать
import jav,ax.micro etiition.lcdui. Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
/**
Этот MID-лет демонстрирует использование отображаемого
элемента TextBox пользовательского интерфейса MIDP.
Усмотри javax.microedition.Icdui.TextBox
* /
public class TextBoxDemo extends MIDlet implements CommandListener
private Command quit = new Command("Exit", Command.EXIT, 1);
private static TextBoxDemo instance;
// Компонент пользовательского интерфейса TextBox. private TextBox textBox;
// Максимальное число знаков, которое TextBox может
// поддерживать. private int MAX_SIZE = 100;
// Первоначальный текст в TextBox. private String initialText =
"You can edit the contents of this TextBox";
/**
Конструктор.
*/
public TextBoxDemo()
super () ; instance = this;
}
public void pauseApp()
{
. . .
}
public void destroyApp(boolean destroy)
}
textBox = null; initialText = null; instance = null;
}
void quit()
}
destroyApp (true);
notifyDestroyedf);
public void startApp()
{
texcBox = new TextBoxC'A TextBox", initialText, MAX_SIZE,
TextField.ANY);
сextBox.addCommand(quit);
textBox.setCommandListener(this);
display();
}
/**
Возвращает единственный экземпляр этого класса.
Вызов этого метода до создания объекта возвратит пустой указатель.
@возращает экземпляр класса.
*/
public static TextBoxDemo getlnstance()
return instance;
}
public void display!)
{
Display. getDisplay(this).setCurrent(textBox);
}
public void commandAction(Command c, Displayable d)
if (c == quit)
{
quit();
}
}
}
Вы можете видеть из конструктора, что TextBox сходен с TextField, за исключением того, что он является многострочной текстовой областью. Аргументами являются заголовок, первоначальный текст, максимальное количество знаков, которое он может поддерживать, и ограничения ввода.
Ограничения являются абсолютно теми же, что и в классе TextField.
На рисунке 5.11 изображен первоначальный текст, используемый для создания экземпляра TextBox. Как и в случаях с другими редактируемыми объектами, вы просто выбираете TextBox с помощью кнопки выбора Select эмулятора и затем редактируете содержимое. Вы можете переходить с помощью четырех клавиш стрелок, стирать знаки с помощью клавиши Clear (Очистить) и вводить их с помощью кнопочной панели, либо компьютерной клавиатуры при использовании эмулятора. Конечно, программа может также манипулировать содержимым с помощью API, который поддерживает вставку, удаление, установку максимального размера, установку ограничений и так далее. На рисунке 5.12 показан экран после выбора текстового окна для редактирования.
Рисунок 5.12. Конкретный интерфейс, предоставляемый для редактирования текстового окна, зависит от реализации
Stringltem
Класс Stringltem определяет двухсоставный компонент дисплея. Объекты Stringltem содержат метку и какой-либо неизменяемый текст. На рисунке 5.7 показан экран, отображаемый классом StringltemDemo, который вы можете запустить из окна, в котором указаны основные компоненты пользовательского интерфейса.
Рисунок 5.7. Строковые элементы состоят из двух частей: текстовая метка и текстовое значение
В листинге 5.6 показаны имеющие отношение к этому классу части кода StringltemDemo. Вы можете соотнести текст в двух параметрах аргумента конструктора с текстом, отображаемым на дисплее. Это очень простой компонент интерфейса пользователя.
Листинг 5.6. Строковые элементы являются формами
import javax.raicroedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Stringltem;
/**
Это? класс демонстрирует использование класса
Stringltem пользовательского интерфейса MIDP.
@see javax.microedition.lcdui.Stringltem
*/
public class StringltemDemo extends Form implements CommandListener
private Command back = new Command("Back", Command.BACK, 1);
private static Displayable instance;
private Stringltem si = new Stringltem("Stringltem's title",
"Immutable item text");
/**
Конструктор.
"/
public StringltemDemo()
super("Stringltem Demo"); append(si); addCoramand(back);
setCommandListener(this);
}
instance = this;
}
...
}
Объекты Stringltem предоставляют вам удобный способ связать метку со значением. Вы можете вложить String в Form вместо использования объекта Stringltem, но Stringltem имеет преимущество, выражающееся в том, что его реализация гарантирует, что строки метки и значения останутся на дисплее вместе.
Описание всех компонентов интерфейса пользователя MIDP
Имя класса компонента, Ul MIDP | Описание | Принадлежность к- API MIDP | |||
Alert | Информационное всплывающее окно, может быть модальным или рассчитанным по времени | Высокоуровневый | |||
AlertType | Определяет типы объектов Alert | Высокоуровневый | |||
Canvas | Экран, в котором вы можете рисовать графические объекты и получать низкоуровневые события ключ/перо | Низкоуровневый | |||
ChoiceGroup | Группа выбираемых элементов, находится в Form | Высокоуровневый | |||
Command | Семантическая инкапсуляция событий пользовательского интерфейса | Как высокоуровневый, так и низкоуровневый | |||
DateField | Компонент, который отображает дату и время | Высокоуровневый | |||
Display | Класс, который извлекает структуры данных дисплея устройства | Высокоуровневый | |||
Displayable | Прародитель всех компонентов, которые могут быть отображены | Как высокоуровневый, так и низкоуровневый | |||
Font | Класс, предоставляющий шрифты для экранного текста | Высокоуровневый | |||
Form | Экран, который собирает элементы для отображения | Высокоуровневый | |||
Gauge | Тип визуального измерителя | Высокоуровневый | |||
Graphics | Отображение контекста графических элементов устройства | Низкоуровневый | |||
Image | Отображение изображений в формате Portable Network Graphics [PNG, переносимая сетевая графика] | Как высокоуровневый, так и низкоуровневый | |||
Imageltem | Form, размещающий отображение изображения | Высокоуровневый | |||
List | Список выбираемых объектов | Высокоуровневый | |||
Screen | Абстрактный прародитель всех типов экранов | Высокоуровневый | |||
Stringltem | Form, размещающий отображение строки | Высокоуровневый | |||
TextBox | Многострочный, многоколонковый текстовой контейнер | Высокоуровневый | |||
TextField | Однострочный текстовой контейнер | Высокоуровневый | |||
Ticker | Отображение тикера | Высокоуровневый |
Типы ограничений, устанавливаемые классом TextField
Константа ограничения | Описание | ||
ANY | Любые буквенно-цифровые знаки | ||
EMAILADDR | Только синтаксически правильный e-mail | ||
NUMERIC | Только цифровые знаки | ||
PASSWORD | Знаки не отображаются на дисплее | ||
PHONENUMBER | Только цифровые знаки, реализация предоставляет задание формата | ||
URL | Только синтаксически правильный LJRL |
Вы определяете ограничения в конструкторе, чтобы создать экземпляр с желаемыми текстовыми атрибутами. Чтобы создавать экземпляры, которые поддерживают обработку комбинации текстовых категорий, перечисленных в таблице 5.3, укажите логический AND этих категорий. Вы можете определить установленные ограничения, исследовав поле CONSTRAINT_MASK объекта TextField.
Ticker
Тикер (Ticker) является объектом, предоставляющим прокручиваемый текст наверху дисплея. TickerDemo в листинге 5.8 создает дисплей, показанный на рисунке 5.9.
Рисунок 5.9. Тикер размещается на дисплее, но не на экране. Реализация определяет место для тикера независимо от какого-либо экрана, позволяя использовать его множеству различных экранов
Ticker связан с дисплеем, но не с экраном. Вы размещаете Ticker на экране с помощью метода Screen.setTicker (Ticker t), как показано в коде листинга 5.8.
с полным набором классов компонентов
Эта глава знакомит вас с полным набором классов компонентов пользовательского интерфейса MIDP. Существует две общие категории компонентов интерфейса пользователя: те, что расположены под Displayable в иерархии, и те, что находятся под иерархией Item.
Класс Screen происходит непосредственно из Displayable и определяет основные абстракции в MIDP. Приложения MIDP в своей основе базируются на экранах.
Form, вид Screen, является только разновидностью экрана, которая может включать другие компоненты. Form может содержать объекты String, изображения, определяемые классом Image, и объекты, чьи типы являются подклассами класса Item.
Стандартное приложение MIDP должно быть способно переходить с экрана на экран. Поэтому экраны должны уметь передавать ссылки в экземпляр объекта экрана, который дисплей должен отображать следующим. Стандартная идиома заключается в предоставлении статического метода, возвращающего такую ссылку в каждом классе, который определяет экран.
В главе 3 представлена полная программная структура и метафоры программирования. В главе 4 описан высокоуровневый API MIDP. Эта глава дополняет все это знакомством с компонентами MIDP, которые реализуют высокоуровневый API.
В следующей главе вы познакомитесь с низкоуровневым API MIDP.
Базовое геометрическое рисование
Класс Graphics предоставляет операции по рисованию и заливке следующих типов геометрических фигур:
линии;
прямоугольники;
дуги;
текстовые символы.
Для всех операций по рисованию геометрических фигур класс Graphics использует графическую ручку, которая рисует линии шириной в один пиксель. Графическая ручка рисует слева направо и сверху вниз со своего координатного местоположения, как показано на рисунке 6.3. Взглянув на несколько примеров, вы лучше поймете принципы ее действия.
Линии. На рисунке 6.4 показаны линии, нарисованные в Canvas.
Двойная буферизация
Термин двойная буферизация относится к технике буферизации графического контекста перед его отображением. Эта идиома требует, чтобы вы использовали два графических контекста - или буфера - отсюда ее название.
Вы сначала рисуете графические данные во вторичном графическом контексте, а затем копируете его содержимое в графический контекст, представленный дисплеем устройства. Этот вторичный графический контекст называется внеэкранным буфером. Внеэкранный буфер не отображает на дисплее.
Смысл этой технологии заключается в ограниченности производительности. Операции по рисованию могут в результате привести к быстрым обновлениям дисплея, заставляя пользователя воспринимать мерцание. Чтобы избежать мерцания, вы должны сначала выполнить ваше рисование во внеэкранной графической среде, а затем скопировать весь внеэкранный графический контекст в оригинальную графику устройства. Операция копирования обычно быстрее, чем множество операций по рисованию, требуемых даже относительно сложными Canvas, так что это будет сделано практически без заметного мерцания.
В листинге 6.9 демонстрируется использование двойной буферизации. Код выполняет несколько простых функций рисования во внеэкранном буфере, затем копирует содержимое этого буфера в саму графическую среду, которая представляет дисплей устройства. Хотя процедуры рисования в этом примере относительно просты, реальное приложение может выполнять намного более сложное рисование, действительно подтверждая необходимость двойной буферизации.
Графическая модель
Класс Graphics определяет возможности низкоуровневого графического рисования. Если вы уже разрабатывали программы на AWT или Swing, этот класс покажется вам очень знакомым. В действительности его свойства и программный интерфейс практически идентичны, хотя и являются подмножеством свойств класса Graphics J2SE.
Класс Graphics определяет модель, которая позволяет приложениям рисовать- или раскрашивать на языке Java - базовые двухмерные фигуры на Canvas. Описанным методом public void paint(Graphics g) осуществляется рисование в вашем подклассе Canvas, подменяя объявленный метод protected abstract в Canvas. Класс Canvas имеет пустое paint(Graphics g) определение, что объясняет, почему он не создает какого-либо визуального представления.
Каждый конкретный подкласс Canvas имеет доступ к объекту Graphics. Этот объект Graphics является копией графического контекста устройства и извлекает зависящий от реализации графический контекст устройства, являющийся частью программного обеспечения операционной системы устройства.
Объект Graphics, с которым вы работаете, создан реализацией Canvas при инициализации объекта Canvas. Это одна из главных причин, почему вы должны убедиться, что ваш конструктор подкласса Canvas вызывает super()! Реализация пересылает графический объект в ваш Canvas, когда он вызывает метод вашего класса paint (Graphics g).
Графическое рисование
Вы, несомненно, обратили внимание, что canvas, показанный на рисунке 6.2, был чистым за исключением экранной клавиши Exit (Выход). Причина этого кроется в том, что класс Canvasl не описывает свое визуальное представление. Все конкретные подклассы Canvas должны определять свой внешний вид для того, чтобы визуализировать какие-либо визуальные атрибуты. Для этого они должны привлекать помощь класса javax.microedition.lcdui.Graphics. Основная цель класса Graphics заключается в поддержке рисования на Canvas.
Игровые действия
В дополнение к константам, которые вы уже видели, класс Canvas определяет константы GAME_A, GAME_B, GAME_C, GAME_D и FIRE, которые представляют игровые действия, отражая влияние игровой индустрии в J2ME. Значения этих констант нестандартны и изменяются в зависимости от реализации.
Игровые действия отражены на других клавишах, потому что большинство устройств не имеет клавиш или кнопок специально для игр. Значение игрового действия соответствует одному или более кодам клавиш, являющихся двоичными значениями, каждое из которых однозначно соответствует клавише. Вы можете определить определенное отображение с помощью следующих двух методов:
public int getKeyCode (int gameAction)
public int getGameAction(int keyCode)
В листинге 6.2 эти методы используются для вывода диагностической информации о каждом полученном событии отпускания клавиши. Если вы запустите эту программу и исследуете результат, вы увидите, что не каждая клавиша имеет связанное с ней игровое действие. В данном случае метод getGameAction () возвращает значение 0. Более того, не все устройства реализуют GAME_A, GAME_B, GAME_C и GAME_D. Примером устройства, которое не использует эти игровые действия, является Motorola Accompli 008.
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).
Класс Graphics
Класс Graphics поддерживает следующие абстракции:
рисование и заливка двухмерных геометрических фигур;
выбор цветов для графической ручки;
выбор шрифтов для рисования текста;
отсечение областей для рисования (clipping);
перенос координатной системы Graphics.
Устройства различаются в своей поддержке атрибутов, таких, как цвет. Поэтому класс Display предоставляет методы:
public int isColorO
public int numColors()
так что вы можете получить информацию о поддержке данным устройством цвета и количестве предоставляемых цветов или поддержке какого-либо числа уровней шкалы серого цвета для устройств, не поддерживающих цвет.
Первостепенной абстракцией, определяемой классом Graphics, является представление о Canvas, как о двухмерной сетке точек или пикселей. На рисунке 6.3 представлено схематичное изображение этой области для рисования. Графический контекст определяет эту координатную плоскость (х, у), в которой координаты лежат между пикселями, практически так же, как и курсор вашего любимого текстового редактора всегда лежит между двумя символами.
Клавишные события
Класс Canvas 1 подменяет метод keyReleased() в Canvas. Поскольку объект регистрируется как блок прослушивания событий, он получает клавишные события в ответ на действия пользователя, связанные с клавиатурой.
Нажатие на любую клавишу клавишной панели приводит к формированию двух клавишных событий: событие нажатия клавиши и событие отпускания клавиши. Эта программа выводит информацию о событиях отпускания клавиши. Информация о клавишном событии включает название клавиши, код клавиши и, возможно, связанное с ним обозначение игрового действия.
Название клавиши является String, которая представляет собой удобное для чтения представление клавиши, обычно сходное (если не такое же) с текстом, физически напечатанным на клавише устройства. Код клавиши является целым числом, чье значение однозначно представляет каждую клавишу. Для стандартных клавиш ITU-T, а именно от 0 до 9, * и #, код клавиши является значением уникода символа.
Программы должны использовать предписанные константы класса Canvas вместо значений уникода нажатой клавиши при проверке того, какая клавиша была нажата. Такой подход делает вашу программу более транспортабельной. Класс Canvas определяет константы для каждого из кодов клавиш, показанные в таблице 6.2.
Демонстрационной
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();
}
}
Чтобы использовать Canvas, вы должны создать подкласс 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;
/**
Определяет подкласс 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! Это очень важно. Без вызова superf) ваши экземпляры
// 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();
}
/**
Определяет, что обработка должна быть сделана в ответ на
событие отпускания клавиши, произошедшее в данном Canvas.
Этот метод подменяет тот же самый метод в Canvas.
*/
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-лета.
Демонстрационная
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() ;
}
}
}
Метод paint (Graphics g) является основным в этом примере. Поскольку Canvas описывает этот метод как абстрактный, подклассы должны предоставлять конкретное описание. На экране, созданном программой в листинге 6.2, ничего не появляется, поскольку ее метод paint (Graphics g) не описывает никаких операций по рисованию.
Ваша программа должна выполнять все свои операции по рисованию в методе paint (Graphics g) на объекте Graphics, переданном ей. Вы запускаете стандартные операции по рисованию, предназначенные для класса Graphics, в этом экземпляре, который передан вашему Canvas.
Чтобы нарисовать линию, вы должны указать координаты (х, у) начальной и конечной точек. Координаты (х, у) определяются относительно точки (0, 0), которая, во время создания графического контекста, представляет пиксель, лежащий в верхнем левом углу дисплея, как показано на рисунке 6.3. Координата х определяет горизонтальное расстояние направо от колонки 0 (левый край дисплея), а координата у определяет вертикальное расстояние от строки 0, которая является верхним краем дисплея.
Ширина линий составляет один пиксель. Чтобы нарисовать более толстую линию, вы должны рисовать прилегающие линии, как демонстрируется в листинге 6.3. Три линии, показанные на рисунке 6.4, созданные с помощью листинга 6.3, имеют ширину в пять, три и один пиксель соответственно.
Кроме того, средняя линия отображена штрихпунктиром. Вы можете установить стиль штриховки для любого рисунка с помощью метода setStrokeStyle (), как демонстрируется в программе. Конкретное отображение линий, которые используют стиль штрихования Graphics.DOTTED, зависит от реализации.
Прямоугольники. Вы можете рисовать два вида прямоугольников: обычный и закругленный. На рисунке 6.5 показаны несколько прилегающих прямоугольников.
Демонстрационная
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 = getHeightf);
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 показаны две дуги, нарисованные методом paint (Graphics g) в листинге 6.5.
Дуги могут быть нарисованы в виде очертания или заполненными, как и прямоугольники
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);
}
. . . .
}
Обратите внимание, что вторая дуга заполнена и что она была создана с помощью метода f illArc () вместо метода drawArc ().
Текст. Класс Graphics также поддерживает «рисование» текстовых символов в Canvas. Три метода, перечисленные в таблице 6.4, являются методами класса Canvas, поддерживающими размещение текста в Canvas.
Чтобы создать текст
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» нарисованы вертикально простым размещением отдельных символов с помощью метода drawChar(). Они определяются сдвигом от правого края дисплея. С помощью политики привязки RIGHT код вычисляет положение правого края ограничивающего прямоугольника, вычитая некоторое количество пикселей из координаты крайнего справа пикселя дисплея.
API Graphics также определяет другую константу, VCENTER, которая действительна только для указания вертикальной политики привязки при размещении изображений. Она недействительна для текста. VCENTER обуславливает то, что вертикальный центр изображения должен быть размещен в координатной точке (х, у). Вы узнаете о работе с изображениями далее в этой главе.
Шрифты. Вы можете выбрать шрифт для любого текста, который вы изобразили в Canvas, как демонстрируется в листинге 6.6. Вы выбираете шрифт, указывая три атрибута шрифта: гарнитура, стиль и размер. Класс javax.microedition.lcdui.Font определяет для каждой из трех категорий константы, показанные в таблице 6.6.
Вы должны стереть
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, а также его шириной и высотой.
Вы можете получить отсекаемый прямоугольник, вызвав следующие методы 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. Вы можете реализовать панорамирование или перемещение изображения, изменяя координаты х и у начала координат при рисовании.
После перемещения
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 для того, чтобы отобразить предыдущий внеэкранный рисунок.
Двойная буферизация
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 = getWidthf);
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 () для получения внеэкранного графического контекста. Приложение может рисовать в этом контексте. Оно затем связывает этот внеэкранный графический контекст с самим устройством.
Чтобы отобразить
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.printStackTracef);
}
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.
Oбработка команд и событий
В компоненте Canvas вы можете добавлять и удалять высокоуровневые команды и устанавливать один блок прослушивания команд на Canvas, как и в других отображаемых компонентах. Canvas также может внедрять CommandListener и регистрироваться как свой собственный блок прослушивания.
Однако, в дополнение к обработке высокоуровневых команд, класс Canvas также обрабатывает низкоуровневые команды. Компоненты Canvas сами являются источниками низкоуровневых событий клавиш и указателя, которые генерируются действиями пользователя по вводу с клавиатуры и перемещением указателя на устройстве. Они также являются своими собственными блоками прослушивания низкоуровневых событий. Класс Canvas определяет интерфейс для обработки низкоуровневых событий как часть своего собственного API, другого интерфейса блока прослушивания не реализуется.
Реализация MIDP передает информацию о событии низкого уровня объекту Canvas, вызывая соответствующий метод в объекте Canvas. В таблице 6.1 перечислены возможные методы.
Отображение изображения с помощью Canvas
Вы уже узнали в главе 5, что некоторые компоненты высокоуровневого пользовательского интерфейса MIDP умеют отображать изображения, например, как часть элемента в ChoiceGroup. Объекты Canvas также могут отображать изображения. Кроме рисования базовых геометрических фигур, объект Canvas может «рисовать» изображения с помощью того же контекста Graphics, который он использует для низкоуровневых функций рисования. MIDP поддерживает только формат изображений PNG.
На рисунке 6.12 показано изображение, отображаемое в Canvas. В листинге 6.10 показана исходная программа, создающая изображение, показанное на рисунке 6.12. Структура программы сходна с другими демонстрационными программами Canvas, приведенными в этой главе.
Отсечение областей для рисования
Когда ваше приложение вызывает метод Display.setCurrent(), он запрашивает реализацию об отображении вашего Displayable. Для объектов Canvas реализация делает ваш компонент текущим отображаемым и вызывает метод вашего класса paint (Graphics g). Реализация генерирует внутреннее событие рисования, которое пересылается в текущий отображаемый элемент. В этом кроется причина того, что метод paint() указан в таблице 6.1 как часть обработки событий API, определяемой Canvas.
Во время отображения некоторая группа пикселей дисплея может быть недействительной или поврежденной. Недействительный или поврежденный пиксель - это тот, который видим в результате предыдущей операции рисования, но не должен быть визуализирован в качестве части текущей операции рисования. Дисплей может быть поврежден другим MID-летом или даже «внешним» приложением - например, приложением по передаче сообщений, которое обновляет дисплей для отображения получения сообщения SMS вашим мобильным телефоном.
Перед тем как приступить к самому рисованию, ваш Canvas обязан стереть все пиксели, появившиеся на экране, которые не должны быть частью его внешнего вида. Вы восстанавливаете экран, обновляя недействительные пиксели.
Вы, несомненно, уже обратили внимание на наличие метода paintClipRect (Graphics g) в листинге 6.3. В листинге 6.7 повторяется этот метод. Это первый код, вызываемый методом paint (Graphics g) каждого приложения. Его цель состоит в удалении всех пикселей, которые были нарисованы предыдущей операцией рисования.
Преобразование
Как вы уже знаете, точка (х, у) указывает функции рисования место, расположенное относительно точки (0, 0). Точка (0, 0) является началом координат Graphics. Когда вы впервые получите ссылку на Graphics вашего Canvas, его начало координат, точка (О, О), всегда представляет верхний левый угол дисплея устройства.
Преобразование Graphics означает перенос его начала координат. После перемещения начало координат Graphics представляет некоторую точку, отличную от левого верхнего пикселя. Вы переводите начало координат Graphics с помощью метода
void translate(int x, int у)
Аргументы являются координатами точки, которая станет новым началом координат объекта Graphics. Точка (0, 0) теперь является этим новым началом координат. Все операции по рисованию теперь относятся к этому новому началу координат. На рисунке 6.9 показан экран, созданный кодом, описанным в листинге 6.8. Он просто рисует заполненный квадрат в Canvas.
При нажатии на кнопку Go начало координат Graphics переносится, а затем заполненный квадрат перерисовывается. На рисунке 6.10 показан обновленный дисплей после того, как кнопка Go была нажата в первый раз. Обратите внимание, что координаты, переданные вызовам методов рисования в методе paint (Graphics g) не изменились. Причина этого кроется в том, что эти координаты всегда связаны с началом координат Graphics, а не с верхним левым углом области дисплея устройства. Операции по рисованию всегда указываются относительно начала координат Graphics, безотносительно к точке места назначения, которое она представляет.
Нажатием на кнопку Go вы на самом деле переключаете перемещение. Нажатие на кнопку во второй раз перемещает начало координат назад к верхнему левому углу дисплея.
Методы уведомления о событиях низкоуровневого API
Название метода | Описание | ||
protected void keyPressedfint 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 на перерисовку |
Для выполнения обработки событий низкого уровня ваш конкретный подкласс Canvas должен подменять один или больше методов, перечисленных в таблице 6.1. Не подменяя пустые описания класса Canvas, вы пропускаете события и вышеупомянутую возможность их обработки. Кроме того, ваш подкласс Canvas должен описывать метод paint (), который объявляется абстрактным в Canvas.
В листингах 6.1 и 6.2 представлена простая схема обработки команд и событий в Canvas. Код в листинге 6.1 является кодом MID-лета для демонстрационной программы, большая часть которой выглядит знакомо. Код в листинге 6.2, однако, создает подкласс Canvas - Displayable, который согласно коду, показанному в листинге 6.1, размещается на экране.
Константы класса Canvas, представляющие клавиши ITU-T
Константа класса 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, которые поддерживают изображение текста на Canvas
Название метода отображения текста в 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) исходного кода, который его отображает.
Графические константы, которые определяют атрибуты шрифтов
Константа атрибута | Описание | ||
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 для того, чтобы переслать его в метод Graphics.setFontf). Вы можете получить объект Font, только вызвав один из двух методов static:
Font.getFont(int face, int style, int size)
Font.get Default Font ()
Указанный шрифт будет использоваться во всех последующих операциях по рисованию до тех пор, пока вы вновь его не измените. В листинге 6.6 шрифт был изменен до создания различных текстовых строк или символов для достижения желаемого эффекта.
Методы класса 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 набора МЮ-летов |
Другие версии создают изменяемые объекты 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, необходимый для очистки отсекаемого прямоугольника.
lcdui формируют определение низкоуровневого программного
Два класса в пакете 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. При рисовании изображений двойная буферизация осуществляется автоматически.