![]() |
|
Sumário
Esta é a parte dois que explora JME com MIDP 2.0. "Parte 1: Criando MIDlets " mostra como adquirir, instalar e usar o Wireless Toolkit para desenvolver MIDlets. A parte 1 mostra também como desenvolver MIDlets sem usar o Toolkit, o qual é importante nesta ordem compreender a atividade envolvida por trás (behind-the-scenes) em criar um MIDlet. A parte 1 termina com uma exploração do ciclo de vida de um MIDlet, com uma guia passo a passo com os eventos na vida de um MIDlet.
Neste artigo, serão criados os elementos da interface do usuário (UI) de um MIDlet. Desde que a interação com o usuário seja um interesse primordial em todo o MIDlet, devido ao tamanho das telas, é importante para compreender o básico do lado MIDlets. Toda a interação com o usuário é feita através de um elemento UI. Quando criado o Date-Time MIDlet na parte 1, foi usado um tal elemento chamado "Alert" para mostrar uma mensagem de alerta na tela. Esta mensagem foi mostrada realmente na tela pela ajuda de um outro elemento UI chamado exposição.
Vamos começar com uma discussão da arquitetura total dos elementos UI
Traduzido do artigo original JME Tutorial, Part 2: User Interfaces with MIDP 2.0 by Vikram Goyal ( http://today.java.net/pub/a/today/2005/05/03/midletUI.html ).
Índice
O MIDP 2.0 fornece classes UI em dois pacotes, javax.microedition.lcdui e javax.microedition.lcdui.game, onde o lcdui padroniza um display de cristal líquido para interface com o usuário (LCD UI). Como esperado, o pacote de jogos contem classes para o desenvolvimento UI de um jogo sem conexão.
As classes UI do pacote de MIDP 2.0 javax.microedition.lcdui podem ser divididas em dois grupos lógicos: os grupos de nível elevado (high-level) e de baixo nível (low-level). As classes do grupo de nível elevado são perfeitas para o desenvolvimento de MIDlets que alvejam o número máximo dos dispositivos, porque estas classes não fornecem o controle exato sobre sua exposição. As classes de nível elevado são abstraídas pesadamente para fornecer o controle mínimo sobre o ver e sentir, o qual é deixado para o dispositivo em que são distribuídos para gerenciar, de acordo com suas capacidades. Estas classes são mostradas na figura 1.
![]() |
![]() |
![]() |
Canvas e Screen implementaa
interface Displayablepackage com.JME.part1;Listagem 1. DateTimeApp MIDlet
import java.util.Date;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
public class DateTimeApp extends MIDlet {
Alert timeAlert;
public DateTimeApp() {
timeAlert = new Alert("Alert!");
timeAlert.setString(new Date().toString());
}
public void startApp() {
Display.getDisplay(this).setCurrent(timeAlert);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
1.1. Alert
1.2. List![]() |
package com.jme.part2;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
public class ListExample extends MIDlet {
List fruitList1;
List fruitList2;
public ListExample() {
fruitList1 = new List("Select the fruits you like",
Choice.MULTIPLE);
fruitList1.append("Orange", null);
fruitList1.append("Apple", null);
fruitList1.insert(1, "Mango", null);
// inserts between Orange and Apple
String fruits[] = {"Guava", "Berry", "Kiwifruit"};
fruitList2 =
new List(
"Select the fruits you like - List 2",
Choice.IMPLICIT,
fruits,
null);
}
public void startApp() {
Display display = Display.getDisplay(this);
display.setCurrent(fruitList1);
try{
Thread.currentThread().sleep(3000);
} catch(Exception e) {}
display.setCurrent(fruitList2);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Listagem
2. Usando Lists 1.3. TextBox
package com.jme.part2;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
public class TextBoxExample extends MIDlet {
private TextBox txtBox1;
private TextBox txtBox2;
public TextBoxExample() {
txtBox1 = new TextBox(
"Your Name?", "", 50, TextField.ANY);
txtBox2 = new TextBox(
"Your PIN?",
"",
4,
TextField.NUMERIC | TextField.PASSWORD);
}
public void startApp() {
Display display = Display.getDisplay(this);
display.setCurrent(txtBox1);
try{
Thread.currentThread()Sleep(5000);
} catch(Exception e) {}
txtBox1.setString("Bertice Boman");
try{
Thread.currentThread()Sleep(3000);
} catch(Exception e) {}
// inserts 'w' at the 10th index to make the
// name Bertice Bowman
txtBox1.insert("w", 10);
try{
Thread.currentThread()Sleep(3000);
} catch(Exception e) {}
display.setCurrent(txtBox2);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Listagem
3. Usando TextBoxes
1.4. Form package com.jme.part2;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Spacer;
import javax.microedition.lcdui.ImageItem;
import javax.microedition.lcdui.TextField;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
public class FormExample extends MIDlet {
private Form form;
private Gauge gauge;
private Spacer spacer;
private ImageItem imageItem;
private TextField txtField;
private DateField dateField;
private StringItem stringItem;
private ChoiceGroup choiceGroup;
public FormExample() {
form = new Form("Your Details");
// a StringItem is not editable
stringItem = new StringItem("Your Id: ", "WXP-890");
form.append(stringItem);
// you can accept Date, Time or DateTime formats
dateField = new DateField("Your DOB: ", DateField.DATE);
form.append(dateField);
// similar to using a TextBox
txtField = new TextField(
"Your Name: ", "", 50, TextField.ANY);
form.append(txtField);
// similar to using a List
choiceGroup = new ChoiceGroup(
"Your meals: ",
Choice.EXCLUSIVE,
new String[] {"Veg", "Non-Veg"},
null);
form.append(choiceGroup);
// put some space between the items to segregate
spacer = new Spacer(20, 20);
form.append(spacer);
// a gauge is used to show progress
gauge = new Gauge("Step 1 of 3", false, 3, 1);
form.append(gauge);
// an image may not be found,
// therefore the Exception must be handled
// or ignored
try {
imageItem = new ImageItem(
"Developed By: ",
Image.createImage("/duke.gif"),
ImageItem.LAYOUT_DEFAULT,
"DuKe");
form.append(imageItem);
} catch(Exception e) {}
}
public void startApp() {
Display display = Display.getDisplay(this);
display.setCurrent(form);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Listagem 4.Usando Forms
![]() |
Usando images, tickers e gauges como elementos UI em MIDlets fica muito simples. Um gauge como viu na última seção, é um item que só pode ser exibido em um formulário para indicar o progresso ou para controlar uma característica de MIDlet (como volume). Um ticker, na outra mão, pode ser acrescentado a todo elemento UI que estender a classe abstrata Displayable, e resulta em rodar uma parte do texto que é exibido através da tela sempre que o elemento que é acrescentado é mostrado na tela. Finalmente, um image, pode ser usado com vários elementos UI, incluindo um formulário, como vimos na última seção.
Desde que o ticker pode ser usado com todos os elementos Displayable, fornece uma maneira acessível à informação exibida sobre o elemento atual na tela. A classe Displayable fornece o método setTicker(Ticker ticker) e o ticker pode ser o próprio criado, usando o construtor Ticker(String msg), com a mensagem que quiser mostrar no ticker. Usando setString(String MSG), pode alterar esta mensagem e esta alteração é efetuada imediatamente. Por exemplo, o formulário usado na seção precedente pode ter seu próprio ticker mostrado por atributo form.setTicker(new Ticker("Benvindo às indústrias!!!")). Isto resultará em um ticker no topo da tela (no emulador Toolkit), enquanto o usuário preenche o formulário. Isto é mostrado na Figura 6.
![]() |
Figura 6. Atribuindo um Ticker em um Displayable
Na seção precedente, vimos um exemplo de um gauge em uma modalidade non-interactive. Ali estava para representar o progresso de um formulário que está sendo preenchido pelo usuário de MIDlet. Um gauge non-interactive pode ser usado para representar o progresso de uma determinada tarefa; por exemplo, quando o dispositivo puder estar tentando fazer uma conexão de rede ou lendo um dados armazenados (datastore), ou quando o usuário estiver preenchendo um formulário. Na seção precedente, criamos um gauge especificando quatro valores. O label ("Step 1 de 3"), modalidade interativa (false), o valor máximo (3) e o valor inicial (1). Entretanto, quando não souber quanto tempo uma atividade particular estará atuando, poderá usar o valor de INDEFINITE para o valor máximo.
Um gauge non-interactive que tenha um valor máximo INDEFINITE adquire um significado especial. (não poderá criar um gauge interativo com um valor máximo INDEFINITE.) Este tipo de gauge poderá estar em um dos quatro estados, e este é refletido pelo valor inicial (que é também o valor atual de gauge). Estes estados são CONTINUOUS_IDLE, INCREMENTAL_IDLE, CONTINUOUS_RUNNING e INCREMENTAL_UPDATING. Cada estado representa o melhor esforço do dispositivo que deixa o usuário saber a atividade atual do MIDlet e poderá usá-los para representar estes estados. A listagem 5 mostra um exemplo, usando estes gauges non-interactive, junto com um exemplo de gauge interativo. Relembre que um gauge é um item UI e só poderá conseqüentemente ser exibido como parte de um Form.
Package com.jme.part2;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
public class GaugeExample extends MIDlet {
private Form form;
private Gauge niIndefinate_CI;
private Gauge niIndefinate_II;
private Gauge niIndefinate_CR;
private Gauge niIndefinate_IU;
private Gauge interactive;
public GaugeExample() {
form = new Form("Gauge Examples");
niIndefinate_CI =
new Gauge(
"NI - Cont Idle",
false,
Gauge.INDEFINITE,
Gauge.CONTINUOUS_IDLE);
form.append(niIndefinate_CI);
niIndefinate_II =
new Gauge(
"NI - Inc Idle",
false,
Gauge.INDEFINITE,
Gauge.INCREMENTAL_IDLE);
form.append(niIndefinate_II);
niIndefinate_CR =
new Gauge(
"NI - Cont Run",
false,
Gauge.INDEFINITE,
Gauge.CONTINUOUS_RUNNING);
form.append(niIndefinate_CR);
niIndefinate_IU =
new Gauge(
"NI - Inc Upd",
false,
Gauge.INDEFINITE,
Gauge.INCREMENTAL_UPDATING);
form.append(niIndefinate_IU);
interactive =
new Gauge(
"Interactive ",
true,
10,
0);
form.append(interactive);
}
public void startApp() {
Display display = Display.getDisplay(this);
display.setCurrent(form);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Listagem 5. Usando gauges
Cada dispositivo móvel usará seu próprio conjunto de images para representar estes gauges. Isto será no geral diferente dos gauges que verá se rodar esta lista no emulador fornecido com o Toolkit.
Poderá também associar uma image com um Alert e um elemento UI Choice-based. Quando uma image é criada, lendo de uma posição física ou fazendo uma image in-memory, só existe na memória off-screen. Deverá, conseqüentemente, ter cuidado ao usar images e restringir o tamanho dos images ao mínimo possível para evitar de encher a memória disponível do dispositivo.
A classe Image fornece diversos métodos estáticos para criar ou adquirir images para usar em MIDlets. Uma image que é criada in-memory, usando o método createImage(int width, int height), é mutável, que significa que poderá ser editado. Uma image criada neste caminho tem inicialmente todos seus pixels ajustados ao branco, e poderá adquirir um objeto gráfico nesta image usando o método getGraphics() para modificar o caminho que é devolvido na tela. Mais sobre o objeto Graphics será visto no item 4. Trabalhando com API de baixo nível.
Para adquirir uma image imutável, poderá usar um de dois métodos: createImage(String imageName) ou createImage(InputStream stream). O primeiro método é usado olharmos as images de um pacote associado de um arquivo .jar, enquanto o segundo método é bom para ler uma image sobre uma rede. Criar uma image imutável de dados in-memory, poderá usar createImage(byte[] imageData, int imageOffset, int imageLength) ou createImage(Image source). O primeiro método permite que formar uma image fora de uma respresentação do byte array, enquanto o segundo permite a criação de uma image de uma existência de image.
Note que os mandatos da especificação de MIDlet suporta para o formato das images, Portable Network Graphics (PNG) . Assim, todos os dispositivos que suportam MIDlets exibiram a image *.png . Estes dispositivos podem suportar outros formatos, especialmente formatos GIF e JPEG, mas isso não é uma garantia.
Já temos visto um exemplo de adquisição de uma image na seção formulários. Na Listagem 4, uma image foi empacotada em uma classe ImageItem de modo que pudesse ser exibida em um formulário. A image foi mantida no pasta res do MIDlet para que o Toolkit e o emulador a encontrasse. O método createImage(String imageName) usa o método Class.getResourceAsStream(String imageName) localizar realmente esta image. O Toolkit toma o cuidado de empacotar esta image na pasta certa quando cria um arquivo .jar . Neste caso, esta será a pasta .jar de nível acima (top-level). Certifique-se de que sempre que referenciar images em seu MIDlets que as images serão mantidas na posição certa. Por exemplo, se quiser manter todas suas images para um MIDlet em uma pasta image no final empacotada em um arquivo .jar e a pasta .jar não ser de nível acima (top-level), necessitará manter estas images abaixo de uma pasta image abaixo de uma pasta res própria. Para referencia de algumas destas images, necessitará assegurar-se de que referenciará a estas através desta pasta images. Por exemplo: createImage("/images/duke.gif"); referenciará a imagem duke.gif abaixo da pasta images.
3. Comando seguros de usuários
Nenhum dos elementos UI tão distante permitiram alguma interação com usuário! Um MIDlet interage com o usuário através de comandos. Um comando é o equivalente a um botão ou de um item de menu numa aplicação normal, e pode somente ser associado com um elemento Displayable UI. Como um ticker, a classe Displayable permite que o usuário acrescente um comando usando o método addCommand(Command command). Ao contrário de um ticker, um elemento displayable UI pode ter múltiplos comandos associados a ele.
A classe do Command retem a informação sobre um comando. Esta informação é encapsulada em quatro propriedades. Estas propriedades são: um short label, uma optional long label, um command type e uma priority. Você cria um comando fornecendo estes valores em seu construtor:
Command exitCommand = new
Command("EXIT", Command.EXIT, 1);![]() |
package com.jme.part2;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Spacer;
import javax.microedition.lcdui.ImageItem;
import javax.microedition.lcdui.TextField;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.CommandListener;
public class FormExample
extends MIDlet
implements CommandListener {
private Form form;
private Gauge gauge;
private Spacer spacer;
private ImageItem imageItem;
private TextField txtField;
private DateField dateField;
private StringItem stringItem;
private ChoiceGroup choiceGroup;
public FormExample() {
form = new Form("Your Details");
// a StringItem is not editable
stringItem = new StringItem("Your Id: ", "WXP-890");
form.append(stringItem);
// you can accept Date, Time or DateTime formats
dateField =
new DateField("Your DOB: ", DateField.DATE);
form.append(dateField);
// similar to using a TextBox
txtField = new TextField(
"Your Name: ", "", 50, TextField.ANY);
form.append(txtField);
// similar to using a List
choiceGroup = new ChoiceGroup(
"Your meals: ",
Choice.EXCLUSIVE,
new String[] {"Veg", "Non-Veg"},
null);
form.append(choiceGroup);
// put some space between the items
spacer = new Spacer(20, 20);
form.append(spacer);
// a gauge is used to show progress
gauge = new Gauge("Step 1 of 3", false, 3, 1);
form.append(gauge);
// an image may not be found,
// therefore the Exception must be handled
// or ignored
try {
imageItem = new ImageItem(
"Developed By: ",
Image.createImage("/duke.gif"),
ImageItem.LAYOUT_DEFAULT,
"Duke");
form.append(imageItem);
} catch(Exception e) {}
// create some commands and add them
// to this form
form.addCommand(
new Command("EXIT", Command.EXIT, 2));
form.addCommand(
new Command("HELP", Command.HELP, 2));
form.addCommand(
new Command("OK", Command.OK, 1));
// set itself as the command listener
form.setCommandListener(this);
}
// handle commands
public void commandAction(
Command com, Displayable dis) {
String label = com.getLabel();
if("EXIT".equals(label))
notifyDestroyed();
else if("HELP"Equals(label))
displayHelp();
else if("OK"Equals(label))
processForm();
}
public void displayHelp() {
// show help
}
public void processForm() {
// process Form
}
public void startApp() {
Display display = Display.getDisplay(this);
display.setCurrent(form);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Listagem 6. Adicionando comandos em formulário
A diferença da Listagem 4 são destacadas em negrito/realce. O comando ouvinte listener neste caso é a própria classe form, e conseqüentemente, implementa o método commandAction(). Note que este método aceita também um parâmetro displayable, que é muito útil. Porque os comandos são imutáveis, podem ser acrescentados aos múltiplos objetos displayable, e este parâmetro pode ajudar distinguir qual objeto displayable invocou o comando.
4. Trabalhando com API de baixo nívelA API de baixo nível para MIDlets é composto das classes Canvas e Graphics (discutiremos a classe GameCanvas no item seguinte). A classe Canvas é abstrata; deve criar suas próprias Canvas para escrita/desenho (write/draw) estendendo esta classe e fornecendo uma implemantação para o método paint(Graphics g), em que o desenho atual em um dispositivo é feito. As classes Canvas e Graphics trabalham juntos para fornecer o controle de baixo nível sobre um dispositivo.
Começaremos com uma simples Canvas. A Listagem 7 mostra um exemplo de Canvas que desenha um quadrado preto no meio da tela do dispositivo.
package com.jme.part2;
import javax.microedition.lcdui.Canvas;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
public class CanvasExample
extends MIDlet {
Canvas myCanvas;
public CanvasExample() {
myCanvas = new MyCanvas();
}
public void startApp() {
Display display = Display.getDisplay(this);
// remember, Canvas is a Displayable so it can
// be set on the display like Screen elements
display.setCurrent(myCanvas);
// force repaint of the canvas
myCanvas.repaint();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
class MyCanvas extends Canvas {
public void paint(Graphics g) {
// create a 20x20 black square in the center
g.setColor(0x000000); // make sure it is black
g.fillRect(
getWidth()/2 - 10,
getHeight()/2 - 10,
20, 20);
}
}
Listagem 7. Criando e mostrando um
Canvas
A classe MyCanvas estende a Canvas e ignora o método paint(). Embora este método é chamado logo que Canvas é feita ao elemento displayable atual (pelo setCurrent(myCanvas)), é uma boa idéia chamar o método repaint() nesta Canvas logo em seguida. O método paint() aceita um objeto Graphics, que fornece métodos desenhando objetos 2D na tela do dispositivo. Por exemplo, na listagem 7, um quadrado preto é criado no meio da tela usando este objeto Graphics. Observe esse antes de desenhar o quadrado, usando o método fillRect(), a cor atual do objeto Graphics é atribuído o preto, usando o método g.setColor(). Isto não é necessário, porque a cor default é preta, mas esta ilustra como alterá-la se quiser, caso queira.
Se rodar esta listagem, a saída no emulador será como mostrada na Figura 8.
![]() |
Figura
8. Desenhando um único quadrado no meio de uma
Canvas
g.setColor(0xffffff);
// sets the drawing color to white
g.fillRect(0, 0, getWidth(), getHeight());
// creates a fill rect which is the size of the screen
Note que os métodos getWidth()
e getHeight()
retornam o tamanho da tela de display
como a Canvas
inicial, que é toda tela display. Embora o
tamanho desta Canvas
não possa ser alterado, poderá alterar o tamanho
e
posição da área de corte em que as
operações interpretadas atuais são
feitas.
Uma área de recorte, em Graphics,
é a área em que as
operações desenhadas são
conduzidas. A classe Graphics,
fornece o método setClip(int
x, int y, int width, int height) para alterar esta
área de recorte, que em uma Canvas inicial
é a tela inteira, com o canto esquerdo superior como a
origem (0, 0). Assim, se usar o método getClipWidth() (ou getClipHeight()) no
objeto Graphics
passado para o método paint
na listagem 7, retornará um valor igual ao valor retornado
pelo método getWidth()
(ou getHeight())
de Canvas.
O objeto Graphics poderá ser usado para retornar não somente quadrados e retângulos, mas também, arcos, linhas, caracteres, imagens e texto. Por exemplo, para desenhar o texto "Hello World" no alto do quadrado na listagem 7, poderá adicionar o seguinte código antes ou depois que o quadrado é desenhado.
g.drawString("Hello World", getWidth()/2, getHeight()/2 - 10,
Graphics.HCENTER | Graphics.BASELINE);
Isto resultará na tela mostrada na Figura 9.
![]() |
Graphics
Text, characters e images são posicionados usando o conceito de pontos de ancora (anchor). A sintaxe cheia do método drawString() é drawstring(String text, int x, int y, int anchor). A ancora posicionada em torno das coordenadas x, y é especificada por duas constantes de bitwise ORing. Uma constante especifica o espaço horizontal (LEFT, HCENTER, RIGHT) e a outra especifica o espaço vertical (TOP, BASELINE, BOTTOM). Assim, para desenhar o texto "Hello World" no alto do quadrado, o espaço horizontal da ancora necessitará ser centrada em torno do meio de Canvas (getWidth()/2) e será usada a constante Graphics.HCENTER. Similarmente, o espaço vertical é especificado usando a constante BASELINE no alto em torno do quadrado (getHeight()/2 - 10). Poderá também usar o valor especial de 0 para a ancora que é equivalente para TOP | LEFT.
As imagens similarmente são desenhadas e posicionadas na tela. Poderá criar imagens off-screen usando o método estático createImage(int width, int height) da classe Image. Poderá começar um objeto Graphics associado com esta imagem usando o método getGraphics(). Este método poderá somente ser chamado em imagens que são mutáveis. Uma imagem carregada do sistema de arquivo ou o acima da rede, são considerados uma imagem imutável e toda a tentativa de começar um objeto Graphics em tal imagem resultará em um IllegalStateException durante a execução.
Usar pontos de ancora com imagens é similar a usá-los com text e characters. As imagens permitem uma constante adicional para o espaço vertical, especificada por Graphics.VCENTER. Também, desde que não exista nenhum conceito de uma linha de base para uma imagem, usando a constante BASELINE, jogará uma exceção se usado com uma imagem.A Listagem 8 mostra um pedacinho do código da classe MyCanvas do método paint() que cria uma imagem off-screen, modifica-o adicionando uma imagem carregada do sistema de arquivo e o desenha uma linha vermelha através dele. Note que necessitará da imagem duke.gif na pasta res do MIDlet CanvasExample.
// draw a modified image try {
// create an off screen image
Image offImg = Image.createImage(25, 19);
// get its graphics object and set its
// drawing color to red
Graphics offGrap = offImg.getGraphics();
offGrap.setColor(0xff0000);
// load an image from file system
Image dukeImg =
Image.createImage("/duke.gif");
// draw the loaded image on the off screen
// image
offGrap.drawImage(dukeImg, 0, 0, 0);
// and modify it by drawing a line across it
offGrap.drawLine(0, 0, 25, 19);
// finally, draw this modified off screen
// image on the main graphics screen
// so that it is just under the square
g.drawImage(
offImg, getWidth()/2,
getHeight()/2 + 10,
Graphics.HCENTER | Graphics.TOP);
} catch(Exception e) { e.printStackTrace(); }
Listagem 8. Criando, modificando e mostrando uma imagem off-screen numa Canvas
A tela resultante, quando combinada com o texto "Hello World" desenhado anteriormente, será como mostrado na Figura 10.
![]() |
Figura 10. Texto, um quadrado e uma imagem modificada desenhada em uma Canvas.
A classe Canvas fornece métodos para interagir com o usuário, incluindo ações pré-definidas de jogo, eventos chaves e se um dispositivo pontual estiver presente, eventos ponteiro. Poderá mesmo adiconar comandos high-level para uma Canvas, similar para comandos adicionados em um elemento UI high-level.
Cada classe de Canvas
recebe automaticamente os eventos chaves através da
invocação de keyPressed(int
keyCode), keyReleased(int keyCode) e keyRepeated(int keyCode).
As execuções default
destes métodos estão vazias, mas não
abstratas,
que permite somente ignorar os métodos que se
estão
interessados. Similar aos eventos chaves, se um dispositivo
pontual estiver presente, eventos ponteiro são enviados para
os
métodos pointerDragged(int
x, int y) e pointerReleased(int
x, int y).
A classe Canvas define constantes para os códigos chaves que são garantidos para estar presente em todos os dispositivos wireless. Estes códigos chaves definem todos os números (por exemplo, KEY_NUM0, KEY_NUM1, KEY_NUM2, e assim por diante) e estrela (*) e chaves cerquinha (#) (KEY_STAR e KEY_POUND). Esta classe faz-lhe mais fácil uniforme de capturar eventos de jogos, definindo algumas constantes básicas do jogo. Existem nove constantes que são relevantes para a maioria de jogos: UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C e GAME_D. Mas como um evento chave traduz a um evento de jogo?
Pelo uso do método getGameAction(). Alguns dispositivos fornecem um controle da navegação movendo-se em torno da tela, enquanto alguns dispositivos usam os números chaves 2, 4, 6 e 8. Para verificar qual a chave de ação do jogo foi pressionada, a classe da Canvas encapsula esta informação e fornece no formulário de ações do jogo. Todos, como um desenvolvedor, necessita fazer, deve-se manter o código chave pressionado pelo usuário no método certo e usar o método getGameAction(int keyCode) para determinar se a chave pressionada corresponde a uma ação do jogo. Desta forma, diversos códigos chaves podem corresponder a uma ação do jogo, mas o único código chave pode traçar, em sua maioria, uma única ação do jogo.
A Listagem 9 estende o código original da Listagem 7 para adicionar a manipulação do código chave. Nesta listagem, o quadrado no meio da tela é movido ao redor com a ajuda das teclas da navegação. Package com.jme.part2;
import javax.microedition.lcdui.Canvas;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
public class CanvasExample
extends MIDlet {
Canvas myCanvas;
public CanvasExample() {
myCanvas = new MyCanvas();
}
public void startApp() {
Display display = Display.getDisplay(this);
// remember, Canvas is a Displayable so it can
// be set on the display like Screen elements
display.setCurrent(myCanvas);
// force repaint of the canvas
myCanvas.repaint();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
class MyCanvas extends Canvas {
public void paint(Graphics g) {
// create a 20x20 black square in the center
// clear the screen first
g.setColor(0xffffff);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(0x000000); // make sure it is black
// draw the square, changed to rely on instance variables
g.fillRect(x, y, 20, 20);
}
public void keyPressed(int keyCode) {
// what game action does this key map to?
int gameAction = getGameAction(keyCode);
if(gameAction == RIGHT) {
x += dx;
} else if(gameAction == LEFT) {
x -= dx;
} else if(gameAction == UP) {
y -= dy;
} else if(gameAction == DOWN) {
y += dy;
}
// make sure to repaint
repaint();
}
// starting coordinates
private int x = getWidth()/2 - 10;
private int y = getHeight()/2 - 10;
// distance to move
private int dx = 2;
private int dy = 2;
}
Listagem 9. Eventos chaves para mover o quadrado
Observe que nesta lista, o código para pintar o quadrado foi modificado para co do exemplo. O método keyPressed() foi ignorado e conseqüentemente, sempre que o usuário pressiona uma chave, este método é invocado. O código verifica se a chave pressionada era uma chave de jogo e baseado no que chave do jogo era pressionada, alteram as coordenadas do quadrado. Finalmente, a chamada ao repaint() torna a chamar por sua vez o método paint(), que move o quadrado na tela como por coordenadas novas.
Neste artigo, foram criados os elementos UI e introduzidas as APIs de interface com o usuário para MIDlets.Vikram Goyal é um amante sério de Java com mais de oito anos de experiência.