Esse artigo faz parte da revista Java Magazine edição 17. Clique aqui para ler todos os artigos desta edição.

-serif';">

Pinte o 7 com Java 2D – Parte 3: Animações e Impressão

 

public void run() {

  while (true) {

    this.repaint();

    try {

      Thread.currentThread().sleep(100);

    }   catch (InterruptedException ie) { }

    if (indice < nomeImagens.length - 1)  indice++;

    else  indice = 0;

  }

}

O código de paint() também é simples. Precisamos apenas desenhar a imagem do índice atual do Vector:

 

public void paint(Graphics g) {

   super.paint(g);

   Graphics2D g2 = (Graphics2D) g;

   g2.drawImage( (Image) imagens.get(indice), null, this );

}

 

A Figura 1 mostra a seqüência de imagens (em arquivos separados) que será exibida durante a animação. A Figura 2 mostra o JFrame exibindo a animação.

Mais sobre repaint()

Vimos na primeira parte da série como funciona o sistema de renderização do Java 2D, e trabalhamos bastante com o método paint(). Vimos também que este método não é chamado diretamente pela aplicação, mas sim pelo sistema de renderização, quando é necessário redesenhar o componente (por exemplo, quando o frame for redimen­sionado, maximizado etc.). Sendo assim, como podemos atualizar o frame durante a animação?

Como não é aconselhável chamar o méto­do paint() diretamente – mesmo porque para chamá-lo precisamos ter uma instância do contexto gráfico Graphics – é disponibilizado um método que pode ser invocado pela aplicação, sempre que se deseja diretamen­te redesenhar um componente. O método repaint() permite que a aplicação chame paint() de forma assíncrona. Internamente, ele solicita ao sistema de renderização que o componente seja redesenhado.

 

 Nem todas as chamadas a repaint() geram necessariamente chamadas a paint(). Por exem­plo, se uma segunda chamada chegar antes que paint() tenha sido chamado ainda para uma invocação anterior de repaint(), paint() será chamado apenas uma vez.

Swing, AWT e flicker

O que vimos até aqui se aplica ao re­desenho de componentes Swing (paco­te javax.swing.*). Os componentes AWT (java.awt.*), entretanto, têm uma ca­racterística adicional que precisamos
conhecer. Um método intermediário,
update(), é chamado para o desenho de componentes AWT. Chamar o método repaint() em um componente AWT invoca update(), que limpa a área do componente e
em seguida chama
paint(). Mas isso pode trazer um efeito indesejado de flicker (“piscado”) na animação, pois cada vez que o quadro é substituído, toda a área do componente é apagada, antes que o novo quadro seja renderizado. Para resolver esse problema, ao utilizar componentes AWT precisamos redefinir o método update(), e chamar paint() diretamente.

Veja na Listagem 2 o código de Panel
AnimacaoAWT
, utilizado para renderizar a animação. Ele é semelhante ao exemplo anterior; o que muda basicamente é a su­perclasse, que é java.awt.Panel (no exemplo anterior usamos javax.swing.JPanel). Note também que redefinimos o método update(), como recomendado. Experimente comen­tar esse método para verificar o efeito de flicker resultante.

Mais controle na animação

Vejamos agora um exemplo mais
elaborado de animação. Nele, teremos a opção de parar e reiniciar a animação, além de controlar o delay (tempo entre a mudança de quadros). Outro diferencial é que as imagens serão carregadas de
um arquivo único com várias imagens, como em um filme. Veja na Figura 3 a se­qüência de imagens utilizada; as imagens são carregadas no construtor da classe,
como a seguir:

 

for (int i = 0; i < NUMERO_FRAMES; i++) {

  BufferedImage bi = new BufferedImage(

    larguraImagem, alturaImagem,
    BufferedImage.TYPE_3BYTE_BGR

  );

  bi.createGraphics().drawImage(

      sequenciaImagens, 0, 0, larguraImagem,  alturaImagem,   

      larguraImagem * i, 0, larguraImagem + larguraImagem * i,

      alturaImagem, this

 );

  imagens.add(bi);

}

A Figura 4 mostra o frame contendo o PainelAnimacao. O controle que pára e reini­cia a animação usa a variável parado, que é checada dentro do método run(). Caso ela seja true, o método wait() é chamado, o que faz com que a thread pare e fique esperan­do por uma notificação (via notify()) para voltar a executar. Veja como fica o método ...

Quer ler esse conteúdo completo? Tenha acesso completo