Este documento é um guia técnico abrangente sobre a construção de interfaces gráficas com o Java AWT (Abstract Window Toolkit). A cobertura inclui gerenciamento de containers, diversos gerenciadores de layout, componentes comuns, tratamento de eventos, desenho de gráficos e manipulação de imagens.
- Containers no AWT
1.1 Hierarquia de Herança
- Janela (Window): Um container de nível superior que pode existir independentemente. Utiliza o
BorderLayoutcomo gerenciador de layout padrão. - Painel (Panel): Um container genérico que não pode existir de forma isolada. Deve ser inserido dentro de outro container. Seu layout padrão é o
FlowLayout. - Painel de Rolagem (ScrollPane): Um container com barras de rolagem integradas, também dependetne. O
BorderLayouté seu layout padrão.
1.2 API Comum para Componentes
A classe base Component fornece métodos para controlar a aparência e o posicionamento dos elementos da interface.
| Método | Descrição |
|---|---|
setLocation(int x, int y) |
Define a posição do componente. |
setSize(int width, int height) |
Define as dimensões do componente. |
setBounds(int x, int y, int width, int height) |
Define posição e tamanho simultaneamente. |
setVisible(boolean b) |
Controla a visibilidade do componente. |
A classe Container adiciona métodos para gerenciar seus componentes filhos.
| Método | Descrição |
|---|---|
Component add(Component comp) |
Adiciona um componente ao container. |
Component getComponentAt(int x, int y) |
Retorna o componente na posição especificada. |
int getComponentCount() |
Retorna o número total de componentes. |
Component[] getComponents() |
Retorna um array com todos os componentes. |
1.3 Exemplos de Uso de Containers
Exemplo de Janela (Frame)
import java.awt.*;
public class JanelaBasica {
public static void main(String[] args) {
Frame minhaJanela = new Frame("Minha Primeira Janela");
minhaJanela.setBounds(200, 150, 600, 400);
minhaJanela.setVisible(true);
}
}
Exemplo de Painel (Panel)
import java.awt.*;
public class PainelSimples {
public static void main(String[] args) {
Frame janelaPrincipal = new Frame("Uso de Painel");
Panel painelDeConteudo = new Panel();
painelDeConteudo.add(new Label("Etiqueta de teste"));
painelDeConteudo.add(new Button("Botão de teste"));
janelaPrincipal.add(painelDeConteudo);
janelaPrincipal.setBounds(200, 150, 600, 400);
janelaPrincipal.setVisible(true);
}
}
Observação sobre Codificação: Em alguns sistemas, caracteres acentuados podem aparecer incorretamente no console. Isso geralmente pode ser resolvido adicionando o parâmetro de JVM -Dfile.encoding=GBK ou -Dfile.encoding=UTF-8 conforme o sistema operacional.
Exemplo de Painel com Rolagem (ScrollPane)
import java.awt.*;
public class PainelComRolagem {
public static void main(String[] args) {
Frame janela = new Frame("Testando ScrollPane");
ScrollPane painelRolagem = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
painelRolagem.add(new Label("Texto dentro do painel de rolagem"));
painelRolagem.add(new Button("Outro componente"));
janela.add(painelRolagem);
janela.setBounds(200, 150, 600, 400);
janela.setVisible(true);
}
}
Nota Importante: O ScrollPane utiliza o BorderLayout. Portanto, se múltiplos componentes forem adicionados diretamente a ele, apenas o último será visível na região central. Para exibir vários componentes, é necessário agrupá-los em um Panel interno.
- Gerenciadores de Layout (LayoutManager)
Definir manualmente as posições e tamanhos dos componentes torna a aplicação pouco portável, pois as dimensões ideais variam entre sistemas operacionais. Os gerenciadores de layout automatizam este processo, garantindo que a interface se adapte corretamente ao ambiente.
2.1 FlowLayout
Organiza os componentes em uma sequência, como um fluxo. Quando atinge a borda do container, os componentes são movidos para a próxima linha. A orientação padrão é da esquerda para a direita.
import java.awt.*;
public class LayoutFluxo {
public static void main(String[] args) {
Frame janela = new Frame("Layout FlowLayout");
janela.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 15));
for (int contador = 0; contador < 15; contador++) {
janela.add(new Button("Item " + (contador + 1)));
}
janela.pack();
janela.setVisible(true);
}
}
Dica: O método pack() ajusta o tamanho da janela para acomodar perfeitamente seus componentes filhos.
2.2 BorderLayout
Divide o container em cinco regiões fixas: Norte, Sul, Leste, Oeste e Centro. Se um componente não for designado a uma região, ele será colocado no Centro por padrão. A região Central se expande para preencher o espaço disponível.
import java.awt.*;
public class LayoutBorda {
public static void main(String[] args) {
Frame janela = new Frame("Layout BorderLayout");
janela.setLayout(new BorderLayout(10, 10));
janela.add(new Button("Norte"), BorderLayout.NORTH);
janela.add(new Button("Sul"), BorderLayout.SOUTH);
janela.add(new Button("Leste"), BorderLayout.EAST);
janela.add(new Button("Oeste"), BorderLayout.WEST);
janela.add(new Button("Centro"), BorderLayout.CENTER);
janela.pack();
janela.setVisible(true);
}
}
2.3 GridLayout
Cria uma grade de células de tamanho igual. Os componentes são adicionados da esquerda para a direita e de cima para baixo, expandindo-se para preencher completamente sua célula.
import java.awt.*;
public class LayoutGrade {
public static void main(String[] args) {
Frame janela = new Frame("Calculadora com GridLayout");
Panel painelSuperior = new Panel();
painelSuperior.add(new TextField(30));
janela.add(painelSuperior, BorderLayout.NORTH);
Panel painelBotoes = new Panel(new GridLayout(4, 4, 5, 5));
String[] rotulos = {"7","8","9","/","4","5","6","*","1","2","3","-","C","0",".","+"};
for (String rotulo : rotulos) {
painelBotoes.add(new Button(rotulo));
}
janela.add(painelBotoes, BorderLayout.CENTER);
janela.pack();
janela.setVisible(true);
}
}
2.4 GridBagLayout
O gerenciador de layout mais flexível e complexo. Permite que componentes ocupem múltiplas células da grade e controle preciso do redimensionamento. Requer o uso da classe auxiliar GridBagConstraints para definir as restrições de cada componente.
import java.awt.*;
public class LayoutGradeFlexivel {
public static void main(String[] args) {
Frame janela = new Frame("GridBagLayout Demo");
GridBagLayout layoutGrade = new GridBagLayout();
janela.setLayout(layoutGrade);
GridBagConstraints restricoes = new GridBagConstraints();
restricoes.fill = GridBagConstraints.BOTH;
restricoes.weightx = 1.0;
Button botao1 = new Button("Botão 1");
Button botao2 = new Button("Botão 2");
Button botao3 = new Button("Botão 3");
Button botao4 = new Button("Botão 4 (Ocupa 2 colunas)");
adicionarComponente(janela, botao1, layoutGrade, restricoes);
adicionarComponente(janela, botao2, layoutGrade, restricoes);
restricoes.gridwidth = GridBagConstraints.REMAINDER; // Termina a linha
adicionarComponente(janela, botao3, layoutGrade, restricoes);
restricoes.gridwidth = 2; // Ocupa 2 colunas
restricoes.weighty = 1.0;
adicionarComponente(janela, botao4, layoutGrade, restricoes);
janela.pack();
janela.setVisible(true);
}
private static void adicionarComponente(Container container, Component comp,
GridBagLayout layout, GridBagConstraints gbc) {
layout.setConstraints(comp, gbc);
container.add(comp);
}
}
2.5 CardLayout
Gerencia uma pilha de componentes, onde apenas um é visível por vez. Permite a navegação entre os "cards".
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LayoutCartas {
public static void main(String[] args) {
Frame janela = new Frame("CardLayout Demo");
CardLayout gerenciadorCartas = new CardLayout();
Panel painelCartas = new Panel(gerenciadorCartas);
String[] nomes = {"Painel A", "Painel B", "Painel C"};
Color[] cores = {Color.RED, Color.GREEN, Color.BLUE};
for (int i = 0; i < 3; i++) {
Panel card = new Panel();
card.setBackground(cores[i]);
card.add(new Label(nomes[i]));
painelCartas.add(card, nomes[i]);
}
Panel painelControle = new Panel();
ActionListener acao = e -> {
String cmd = e.getActionCommand();
if ("Proximo".equals(cmd)) {
gerenciadorCartas.next(painelCartas);
} else if ("Anterior".equals(cmd)) {
gerenciadorCartas.previous(painelCartas);
}
};
Button btnAnt = new Button("Anterior");
Button btnProx = new Button("Proximo");
btnAnt.addActionListener(acao);
btnProx.addActionListener(acao);
painelControle.add(btnAnt);
painelControle.add(btnProx);
janela.add(painelCartas, BorderLayout.CENTER);
janela.add(painelControle, BorderLayout.SOUTH);
janela.setSize(400, 300);
janela.setVisible(true);
}
}
2.6 BoxLayout
Organiza componentes em uma única linha (horizontal) ou coluna (vertical). É útil para criar interfaces lineares simples. Pode-se usar Box.createHorizontalBox() ou Box.createVerticalBox() para criar contêineres com este layout pré-configurado.
import java.awt.*;
import javax.swing.*;
public class LayoutCaixa {
public static void main(String[] args) {
Frame janela = new Frame("BoxLayout com Espaçamento");
Box caixaVertical = Box.createVerticalBox();
caixaVertical.add(new Button("Botão Superior"));
caixaVertical.add(Box.createVerticalStrut(20)); // Espaço fixo
caixaVertical.add(new Button("Botão do Meio"));
caixaVertical.add(Box.createVerticalGlue()); // Espaço elástico
caixaVertical.add(new Button("Botão Inferior"));
janela.add(caixaVertical);
janela.setSize(300, 300);
janela.setVisible(true);
}
}
- Componentes Comuns do AWT
Além dos containers, o AWT fornece uma variedade de componentes para entrada e saída de dados.
- Label: Exibe texto estático.
- Button: Botão clicável.
- TextField: Campo de entrada de texto de linha única.
- TextArea: Campo de entrada de texto multi-linha.
- Checkbox: Caixa de seleção (pode ser usada como rádio com
CheckboxGroup). - Choice: Lista suspensa (dropdown).
- List: Lista de itens com seleção simples ou múltipla.
- Canvas: Área bruta para desenho personaliazdo.
- Scrollbar: Barra de rolagem para valores numéricos.
- Tratamento de Eventos
A interação do usuário é tratada por um modelo de eventos. Os conceitos chave são:
- Fonte do Evento: O componente que gerou o evento (ex: um botão).
- Evento: Um objeto que encapsula a informação sobre o que aconteceu (ex: um clique).
- Ouvinte (Listener): Uma interface que define métodos para tratar um tipo específico de evento.
- Registro: O processo de vincular um ouvinte a uma fonte de evento.
Exemplo Básico de Evento
import java.awt.*;
import java.awt.event.*;
public class TratadorDeEventos {
public static void main(String[] args) {
Frame janela = new Frame("Eventos");
Button botaoAcao = new Button("Clique Aqui");
Label mensagem = new Label("Aguardando ação...");
botaoAcao.addActionListener(e -> {
mensagem.setText("Botão foi clicado!");
});
janela.add(mensagem, BorderLayout.NORTH);
janela.add(botaoAcao, BorderLayout.CENTER);
janela.pack();
janela.setVisible(true);
}
}
Evento de Janela
Para fechar a janela ao clicar no "X", é necessário tratar o evento de janela.
import java.awt.*;
import java.awt.event.*;
public class FecharJanela {
public static void main(String[] args) {
Frame janela = new Frame("Fechar Janela");
janela.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
janela.setSize(300, 200);
janela.setVisible(true);
}
}
- Componentes de Menu
Menus são construídos com MenuBar, Menu e MenuItem.
import java.awt.*;
public class MenuSimples {
public static void main(String[] args) {
Frame janela = new Frame("Exemplo de Menu");
MenuBar barraDeMenu = new MenuBar();
Menu menuArquivo = new Menu("Arquivo");
MenuItem itemNovo = new MenuItem("Novo");
MenuItem itemSair = new MenuItem("Sair");
itemSair.addActionListener(e -> System.exit(0));
menuArquivo.add(itemNovo);
menuArquivo.addSeparator(); // Linha divisória
menuArquivo.add(itemSair);
barraDeMenu.add(menuArquivo);
janela.setMenuBar(barraDeMenu);
janela.setSize(400, 300);
janela.setVisible(true);
}
}
- Desenho com Graphics
O desenho personalizado é realizado sobrescrevendo o método paint(Graphics g) de um componente (geralmente um Canvas ou Panel). A classe Graphics oferece métodos como drawRect, fillOval, drawLine, drawString e setColor.
Exemplo: Desenhando Formas
import java.awt.*;
public class AreaDeDesenho extends Canvas {
@Override
public void paint(Graphics pincel) {
// Configura a cor e desenha
pincel.setColor(Color.BLUE);
pincel.fillRect(50, 50, 100, 80);
pincel.setColor(Color.RED);
pincel.fillOval(200, 50, 80, 80);
pincel.setColor(Color.BLACK);
pincel.drawString("Exemplo de Desenho AWT", 100, 200);
}
public static void main(String[] args) {
Frame janela = new Frame("Desenho");
AreaDeDesenho canvas = new AreaDeDesenho();
canvas.setPreferredSize(new Dimension(400, 300));
janela.add(canvas);
janela.pack();
janela.setVisible(true);
}
}
BufferedImage e Pintura Suave
Para evitar cintilação (flickering) durante a repintura, pode-se desenhar primeiro em uma imagem buffer (BufferedImage) e depois transferir a imagem completa para o componente.
import java.awt.*;
import java.awt.image.BufferedImage;
public class DesenhoBufferizado extends Canvas {
private BufferedImage imagemBuffer;
public DesenhoBufferizado(int largura, int altura) {
imagemBuffer = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_ARGB);
}
public void redesenhar() {
Graphics2D g2d = imagemBuffer.createGraphics();
// Limpa a imagem buffer
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, imagemBuffer.getWidth(), imagemBuffer.getHeight());
// Desenha novos elementos na imagem buffer
g2d.setColor(Color.GREEN);
g2d.fillOval(50, 50, 100, 100);
g2d.dispose();
repaint(); // Solicita que o componente seja repintado
}
@Override
public void paint(Graphics g) {
// Apenas desenha a imagem buffer no componente
g.drawImage(imagemBuffer, 0, 0, null);
}
public static void main(String[] args) {
Frame janela = new Frame("Desenho Bufferizado");
DesenhoBufferizado canvas = new DesenhoBufferizado(400, 300);
canvas.setPreferredSize(new Dimension(400, 300));
janela.add(canvas);
janela.pack();
janela.setVisible(true);
// Exemplo: redesenhar a cada 100ms (simulação de animação)
// javax.swing.Timer timer = new javax.swing.Timer(100, e -> canvas.redesenhar());
// timer.start();
}
}