GRFICOS EM JAVA
Miguel Jonathan DCC-IM-UFRJ - rev. junho 2010
Pode-se desenhar em qualquer componente, ou seja, em sub-classes das classes abstratas [Link] ou
[Link]. As hierarquias que interessam mais so as seguintes:
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link].Graphics2D
O melhor desenhar em uma subclasse de JPanel ou Canvas. possvel desenhar direto em uma subclasse de
JFrame, mas no conveniente, porque o espao da barra de ttulo precisa ser levado em conta no clculo das
coordenadas y.
Desenhar simples: dentro da classe do componente deve ser criado um mtodo com assinatura:
public void paint(Graphics g)
O parmetro g uma instncia de Graphics ou uma de suas subclasses, que ser passada diretamente pelo sistema para
o mtodo paint(). Atualmente passada uma instncia de Graphics2D.
Todo o desenho feito dentro do mtodo paint(), atravs dos mtodos de Graphics chamados a partir do parmetro g.
As coordenadas sero sempre considerando o ponto (0,0) como o canto superior esquerdo do componente, com x
avanando para a direita, e y para baixo. Mais adiante sero vistos alguns desses mtodos.
ATENO: O mtodo paint() nunca deve ser chamado diretamente.
Quando o componente criado, Java chama automaticamente o mtodo void paint(Graphics g) e lhe passa uma
instncia de Graphics. Depois, caso seja necessrio apagar e re-desenhar novamente sobre o componente, deve-se
chamar o mtodo repaint() do componente, sem qualquer argumento. Esse mtodo quem far com que o mtodo
paint() seja chamado assim que for possvel. (Note no programa exemplo que o mtodo paint() no chamado
diretamente).
Alguns mtodos de instncia da classe Graphics so mostrados abaixo.
Consulte a API da classe para ter uma viso mais completa.
Os mtodos devem ser chamados a partir da referncia a um Graphics, que ser o parmetro do mtodo paint() da classe
do componente onde queremos desenhar:
a) Para traar linhas retas:
drawLine(int x1, int y1 int,x2, int y2);
Traa uma linha do ponto (x1,y1) ao ponto (x2, y2) do componente.
b) Para desenhar caracteres e strings:
drawString (String s, int x, int y);
Desenha a string s a partir do ponto (x,y), usando a fonte default usada pela instncia de Graphics:
c) Para mudar a fonte das letras, possvel usar o mtodo:
setFont(Font f);
Uma fonte pode ser criada com o construtor:
Font(String nomeDaFonte, int estilo, int tamanho);
Veja no programa exemplo uma fonte criada de nome Serif, estilo Negrito (bold), e tamanho 14.
A classe Graphics permite desenhar outras formas, trocar cores, etc. Consulte a API.
A seguir sero mostrados alguns exemplos de uso de Graphics:
1. Desenha 3 Linhas:
O primeiro programa exemplo desenha 3 linhas e uma String sobre um componente que de uma sub-classe de JPanel.
Ele faz o seguinte:
a) Define uma subclasse de JFrame para ser a janela, e uma subclasse de JPanel para ser o componente onde sero
feitos os desenhos;
b) A classe do componente contm o mtodo para obter os valores a renderizar, e tambm o mtodo paint(), onde esto
as chamadas aos mtodos grficos do seu parmetro g. (obs: renderizar gerar um desenho a partir de um modelo de
dados. Por exemplo, gerar linhas a partir dos valores de seus tamanhos).
O mtodo paint() desenha 3 linhas de tamanhos 100, 200 e 300 pixels, separadas entre si por uma distncia de 20
pixels. Leia os comentrios para mais informaes sobre o que o programa faz.
c) O construtor da janela constri a instncia do componente e o insere na janela com add(<componente>);
d) O mtodo main() cria uma instncia da janela, define suas dimenses, e a torn visvel.
/*Desenha 3 linhas de comprimentos diferentes: 100, 200 e 300 pixels,
* separadas por uma distncia de 20 pixels.
* A primeira linha fica 20 pixels abaixo do limite superior da janela.
* As linhas comeam sempre na margem esquerda da tela (x=0).
* Aps isso a frase "Foram impressas 3 linhas de comprimentos 100, 200 e 300 pixels".
* ser escrita, 200 pixels abaixo,50 pixels direita da margem.
* A fonte das letras ser Serif, Negrito, tamanho 14.
* A janela ser aberta com as dimenses largura = 500, altura = 400.
* A origem da janela (canto superior esquerdo) est no canto superior esquerdo da tela.
*/
import [Link].*; // para Graphics e Font
import [Link].*; // para JPanel e JFrame
class Painel extends JPanel{
public void paint(Graphics g){
int compr; // comprimento da linha
int alt=0; // altura da linha
for(compr=100; compr<=300; compr+=100){
alt+=20;
[Link](0,alt,compr,alt);
}
Font font = new Font("Serif",[Link],14); // cria a fonte para escrever a frase
[Link](font); // estabelece a fonte que ser usada a partir daqui.
alt+=200; // define a altura 200 pixels abaixo da ultima linha desenhada.
[Link]("Foram impressas 3 linhas de comprimentos 100, 200 e 300 pixels", 50, alt);
}
}
class Janela extends JFrame{
public Janela(String titulo){
super(titulo);
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new Painel());
}
}
public class DesenhaTresLinhas{
public static void main(String[] args){
Janela f = new Janela("Teste de Linhas");
[Link](500,400);
[Link](true);
}
}
2. Desenho de um Gato:
O segundo exemplo mostra como desenhar formas geomtricas, como retngulos e crculos e como preencher com
cores, formando figuras construdas livremente:
// Exemplo de uso da classe Graphics
// Adaptado do original de Frans Coenen
// Dept. of Comp. Sci., University of Liverpool
import [Link].*; // Font, Color
import [Link].*;
class Painel extends JPanel {
public void paint(Graphics g) {
[Link]([Link]);
[Link](50,50,60,60); // Cabea
[Link](80,225,140,5); // Cauda
[Link]([Link]);
[Link](20,110,120,120); // corpo um circulo branco
[Link]([Link]);
[Link](20,110,120,120); // circunferencia do corpo em preto
[Link](75,75,10,10); // nariz
[Link]([Link]);
[Link](60,60,10,10); // olhos
[Link](90,60,10,10);
[Link]([Link]);
[Link](50,50,60,30); // orelhas
[Link](60,30,70,50);
[Link](110,50,100,30);
[Link](100,30,90,50);
[Link]([Link]);
[Link](60,80,40,20,180,180); // Boca
[Link]([Link]);
Font serif = new Font("Serif",[Link],18);
[Link](serif);
[Link]("Gato Java",200,50);
}
}
class Gui extends JFrame{
public Gui(String text) {
super(text);
setBackground([Link]); // fundo amarelo
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new Painel());
}
}
class DesenhaGato {
public static void main(String[] args) {
Gui gui = new Gui("Gato");
[Link](300,300);
[Link](true);
}
}
3. Jogo Quebra-Cuca
O terceiro exemplo mais complexo. Mostra um jogo interativo, e precisa usar repaint() para repintar o painel a cada
jogada. O jogo usa uma matriz para guardar o estado do jogo (o modelo). Nesse exemplo, o modelo, o controle e a vista
esto juntos (no usa MVC).
Alm da parte grfica, o exemplo usa um ouvinte para os eventos de clique do mouse. O ouvinte um exemplo de uma
instncia de uma classe annima interna que uma subclasse de Mouse Adapter. A classe Mouse Adapter uma classe
que implementa MouseListener, com todos os mtodos dessa interface com corpos vazios. No exemplo, uma instncia
de uma subclasse annima de MouseAdapter criada juntamente com a definio do nico mtodo redefinido que
mouseReleased().
Os comentrios inseridos nos mtodos ajudam a compreender o seu funcionamento:
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
class QuebraCuca extends Component{
int lado; // tamanho do lado de cada quadrado, em pixels
int matriz[][]; // a matriz do quebra-cabeca;
int linVazia,colVazia; // coordenadas da casa vazia
Dimension tam; //
MouseListener m;
QuebraCuca(int tamanho){
tam = new Dimension(tamanho, tamanho);
lado = tamanho/4; // sao 4 quadrados em cada linha
matriz = new int[4][4];
/****
* O cdigo abaixo usa uma classe local annima para gerar o ouvinte de eventos de mouse.
* O ouvinte ser referenciado pela varivel m.
* Essa classe sub-classe de MouseAdapter, e s redefine o mtodo MouseReleased.
* Os demais mtodos da interface MouseListener continuaro vazios.
****/
m = new MouseAdapter(){
public void mouseReleased(MouseEvent e){
int colClic = [Link]()/lado;
int linClic = [Link]()/lado;
if (
colClic < 4 &&
linClic<4 &&
colVazia==colClic &&
([Link](linVazia-linClic)==1) ||
linVazia == linClic &&
([Link](colVazia-colClic)==1)
){
matriz[linVazia][colVazia]= matriz[linClic][colClic];
matriz[linVazia=linClic][colVazia=colClic]=0;
repaint();
}
}
};
for (int lin =0;lin<4;lin++)
for (int col=0; col<4; col++)
matriz[3-col][3-lin] = 4*lin + col + 1;
linVazia=colVazia=0;
matriz[0][0]=0;
addMouseListener(m);
} // fim do construtor
void desenhaQuadr(Graphics g, int lin, int col) {
// somente o quadrado "vazio" nao ser desenhado (e ficar preto)
// note que a grade no precisa ser desenhada. Apenas nao preenchida com nada.
if(matriz[lin][col] !=0){
[Link](col*lado+1, lin*lado+1, lado-2, lado-2);
[Link](new Integer(matriz[lin][col]).toString(),
col*lado+ lado/2-4,lin*lado+lado/2+4);
}
}
public void paint(Graphics g) {
[Link](0,0,lado*4, lado*4); // pinta tudo de preto
for(int lin=0; lin<4;lin++)
for(int col=0; col<4; col++)
desenhaQuadr(g,lin,col);
}
public Dimension getPreferredSize() {
return tam;
}
public static void main(String[] args) {
JFrame f = new JFrame ("Quebra-cabeca");
[Link](400,420);
[Link](JFrame.EXIT_ON_CLOSE);
[Link](new QuebraCuca(400));
[Link](true);
}
}