WirelessBR

WirelessBr é um site brasileiro, independente, sem vínculos com empresas ou organizações, sem finalidade  comercial,  feito por voluntários, para divulgação de tecnologia em telecomunicações 

Tutorial de programação J2ME 
Parte 4 - Pág. 3  
Plataforma Java 2 Micro Edição (J2ME)

Autor: Rodrigo P. Garcia Corbera 

BouncingTextCanvas.java  
 

import java.util.Random;  
import javax.microedition.lcdui.*;  
class BouncingTextCanvas extends Canvas implements CommandListener, Runnable {  

// os atributos do objeto com modificador final são referências a outros  
// objetos usados pela classe. Este não serão modificados durante a execução  
// da aplicação.

       private final BouncingTextMIDlet midlet;  
       private final Display display;  
       private final Command exitCommand;  
       private final Command reverseCommand;  
       private final BouncingText text;

// variáveis que contem cores de fundo e do texto a ser animado

       private int bgRGB;
       private int textRGB;

// animationThread conterá a referência à thread (linha de execução) da animação

       private volatile Thread animationThread = null;  

// construtor associado à classe:  
// guarda as referências a objetos importantes (midlet pai e display)

       BouncingTextCanvas (BouncingTextMIDlet midlet, Display display, String string) {  
              this.midlet = midlet;  
              this.display = display;  

// cria os comandos de softkey para sair e inverter o texto       

              setCommandListener(this);  
              reverseCommand = new Command("Inv", Command.SCREEN, 1);  
              exitCommand = new Command("Sair", Command.EXIT, 1);  
              addCommand(exitCommand);  
              addCommand(reverseCommand);  

// gera as cores de acordo com a capacidade gráfica do aparelho celular

              nti ch = getHeight();  
              int cw = getWidth();  
              initColors();

// cria uma instância do objeto que será animado

              text = new BouncingText(string, textRGB, 0, ch/2, cw, ch);  
       }  

// método que inicia a animação, criando uma nova linha de execução

       void startAnimation() {  
              animationThread = new Thread(this);
              animationThread.start();  
       }  

// método que para a animação sinalizando através da variável animationThread  
// que o loop de execução do método run() deve terminar, levando ao término  
// da linha de execução

       void stopAnimation() {  
              animationThread = null;  
       }  

// método que é executado durante a existência da linha de execução do objeto

       public void run() {

// tempo ideal de execução de cada quadro da animação - 100 milisegundos  
// equivalente a 10 FPS (quadros por segundo)

              int millis_per_tick = 100;

// toma o identificador da linha de execução corrente, a qual deverá
// apontar para esta própria execução...

              Thread currentThread = Thread.currentThread();  

// cuida das exceções referentes a este bloco de execução...

              try {

// se a animação não foi paralisada ...

                    while (currentThread == animationThread) {

// toma o relógio em milisegundos e anima o texto através de tick() ...

                           long startTime = System.currentTimeMillis();  
                           tick();

// solicita o redesenho da tela e fica bloqueado até que a tela tenha sido atualizada

                           repaint(0, 0, getWidth(), getHeight());  
                           serviceRepaints();

// não sabemos quanto tempo levou a execução dos passos anteriores, portanto  
// calculamos a diferença do tempo de espera de cada quadro

                           long elapsedTime = System.currentTimeMillis() - startTime;

// se a execução foi mais rápida que os 100 ms aguardamos pelo tempo restante

                           if (elapsedTime < millis_per_tick) {  
                                 synchronized(this) {  
                                        wait(millis_per_tick - elapsedTime);  
                                 }  
                           } else {

// caso contrário forçamos uma mudança de contexto para que outros processos  
// sejam executados pelo sistema, tais como organização da memória, ou outros threads

                                 currentThread.yield();  
                           }  
                    }  
              } catch(InterruptedException e) {  
              }  
       }  

// método executado quando a tela é desenhada

       public void paint(Graphics g) {  

// primeiro apagamos toda a tela com a cor de fundo

              g.setColor(bgRGB);  
              g.fillRect(0, 0, getWidth(), getHeight());

// em seguida desenhamos o texto na posição corrente

              text.draw(g);  
       }  

// trata da execução de comandos via softkey

       public void commandAction(Command c, Displayable d) {

// caso solicitemos a saída imediata da aplicação...

              if (c == exitCommand) {  
                    stopAnimation();
                    midlet.exitRequested();  
              } else if (c == reverseCommand) {

// ou se apenas pedimos a inversão do texto em animação...

                    text.reverse();  
              }  
       }       

// a cada quadro de 100ms da animação atualizamos a posição do texto
// criando a ilusão de uma animação livre, como o vôo de um mosquito

       private synchronized void tick() {

              text.updatePosition();  
       }  

// cuida da seleção de cores para o fundo e para o texto a ser animado

       private void initColors() {  
              int white = 0xffffff;  
              int black = 0x000000;  

// caso seja colorido, geramos uma cor aleatória para o texto e fundo

              if (display.isColor()) {  
                    Random random = new Random();  
                    textRGB = random.nextInt() & 0xffffff;

// a cor de fundo será contrastante em relação ao texto...

                    bgRGB = white - textRGB;  
              } else {

// neste caso - não colorido, usamos o velho branco e preto...

                    textRGB = black;  
                    bgRGB = white;  
              }  
       }  

// classe que controla um texto que é animado na tela

       class BouncingText {  

// atributos não modificáveis ao longo da execução...  
// largura e altura da tela - limita fronteiras de movimentação

              private final int w;
              private final int h;

// cor do texto

              private final int textRGB;

// gerador de seqüência pseudo aleatória

              private final Random random;  

// atributos variáveis ao longo da execução...  
// texto a ser animado

              private String string;

// posição do texto na tela em pixels  
              private int x;  
              private int y;

// largura e altura do texto em pixels

              private int strWidth = 0;  
              private int strHeight = 0;

// vetor de direção da animação

              private int xdir = 1;  
              private int ydir = 1;  

// construtor inicia os atributos do objeto

              BouncingText(String string, int textRGB, int x, int y, int w, int h) {
                    this.string = string;  
                    this.x = x;  
                    this.y = y;  
                    this.w = w;  
                    this.h = h;  
                    this.textRGB = textRGB;  
                    random = new Random();  
              }  

// atualizamos a posição do texto de forma aleatória ...

              private void updatePosition() {  
                    int vx = random.nextInt() & 0x07;  
                    int vy = random.nextInt() & 0x07;  

// verificamos se não atingimos as fronteiras laterais da tela  
// caso no qual devemos mudar a direção da animação

                    if ((xdir == 1) && ((x + vx) >= maxAnchorX())) {  
                           xdir = -xdir;  
                    } else if ((xdir == -1) && ((x - vx) < 0)) {  
                           xdir = -xdir;  
                    }

// caso a nova posição não jogue o texto para fora da tela, atualizamos a mesma

                    int xnew = x + (vx * xdir);
                    if ((xnew >= 0) && (x < maxAnchorX())) {
                           x = xnew;  
                    }  

// verificamos se não atingimos as fronteiras de fundo e topo da tela 
// caso no qual devemos mudar a direção da animação

                    if ((ydir == 1) && ((y + vy) >= maxAnchorY())) {
                           ydir = -ydir;  
                    } else if ((ydir == -1) && ((y - vy) < 0)) {  
                           ydir = -ydir;  
                    }

// caso a nova posição não jogue o texto para fora da tela, atualizamos a mesma

                    int ynew = y + (vy * ydir);  
                    if ((ynew >= 0) && (y < maxAnchorY())) {  
                           y = ynew;  
                    }  
              }  

// método para desenho do texto

              private void draw(Graphics g) {

// caso não tenhamos atualizado a altura e largura do texto em pixels...

                    if (! (strHeight > 0)) {  
                           Font f = g.getFont();  
                           strHeight = f.getHeight();  
                           strWidth = f.stringWidth(string);  
                    }

// desenhamos o texto na tela na posição correta

                    g.setColor(textRGB);
                    g.drawString(string, x, y, Graphics.TOP|Graphics.LEFT);
              }  

// calcula o valor máximo de x para não jogar o texto para fora da tela

              private int maxAnchorX() {  
                    return w - strWidth;  
              }  

// calcula o valor máximo de y para não jogar o texto para fora da tela

              private int maxAnchorY() {
                    return h - strHeight;  
              }  

// método que inverte o texto -- exemplo <--> olpmexe

              private void reverse() {

// convertemos o texto em uma cadeia de caracteres

                    char[] carray = string.toCharArray();

// para em seguida do fim para o início criar a cadeia de caracteres invertida

                    for (int old = string.length() - 1, nu = 0; old >= 0; old--, nu++) {  
                           carray[nu] = string.charAt(old);
                    }

// por fim atualizamos o texto com seu conteúdo invertido...

                    string = new String(carray);  
              }  
       }  
}  


Exercícios propostos: 

A fim de que o estudante tenha como exercitar o que aprendeu, proponho alguns exercícios que aumentam em grau de complexidade. Tratam-se de modificações que devem ser feitas ao código original a fim de implementar algumas alterações, as quais podem ser acumuladas, produzindo um novo código final melhorado. 

1)     Na classe TextInputScreen seria interessante modificar o código a fim de não permitir que o usuário altere o texto a ser animado para uma cadeia vazia de caracteres. Se isto ocorrer, não haverá efeito gráfico da animação. Experimente para isso modificar o método commandAction() dessa classe. 

2)     Na atual implementação, o texto a ser animado só pode ser modificado no início da execução e somente uma única vez. Tente modificar o código de forma a permitir que o mesmo seja modificado durante a animação. Crie um comando adicional para implementar essa nova funcionalidade, alterando o fluxo das telas. 

3)     Implemente controle de velocidade. Atualmente a velocidade é recalculada a cada 100 ms através de tick() e de updatePosition(). Faça com que a velocidade seja calculada de forma aleatória uma única vez a fim de que o texto se mova suavemente a uma velocidade constante pela tela. 

4)     Em seguida implemente através das teclas de direção do celular um controle de velocidade horizontal e vertical. Por exemplo, as teclas de setas para cima e para baixo aumentam e diminuem a velocidade vertical, enquanto as teclas de setas para esquerda e direita controlam a velocidade horizontal. Para isso será necessário implementar um dos métodos descritos anteriormente (keyPressed, keyRepeated ou keyReleased). 

5)     Altere a classe BouncingTextCanvas e BouncingText de forma a permitir múltiplos textos animados ao mesmo tempo. Adicione o controle do botão “KEY_POUND”, por exemplo, para adicionar um novo texto e animá-lo. Adicione o controle do botão “KEY_STAR” para eliminar o último texto animado adicionalmente criado sem deixar que pelo menos fique um texto sendo animado na tela. 

Com isso finalizamos nossa série de tutoriais. Bons estudos!

 

Anterior               Home WirelessBR