Programação Visual em Java
Programação Visual em Java
1
como Delphi e VisualBasic, que são voltadas exclusivamente para esse fim. Boa parte da
elaboração da interface da aplicação tem que ser feita manualmente, o que exige bastante
trabalho.
1.1 Frames
Na AWT, a janela de mais alto nível de uma aplicação (não está contida dentro de nenhuma
outra) é denominada Frame. No Swing, existe uma versão chamada JFrame, que é
derivada/estendida da classe Frame, possuindo alguns poucos métodos adicionais relacionados à
manipulação da disposição visual dos frames .Todos os outros métodos são derivados da classe
Frame. Um frame pode conter diversos outros componentes da GUI.
O frame criado não possui tamanho definido, nem título ou posicionamento. Para personalizar o
frame é necessário inserir um método construtor com as instruções necessárias. Exemplo:
import java.awt.*;
public class FrameDois extends Frame
{
public FrameDois() //construtor
{
setTitle("Frame Dois"); // título do Frame
setSize(300, 200); // largura: 300 pixels altura: 200 pixels
setResizable(false); // não permite o redimensionamento
2
setLocation(200, 100); // x: 200 pixels y: 100 pixels
}
public static void main (String[] args)
{
FrameDois fr = new FrameDois();
fr.setVisible(true);
}
}
A figura 1.2 mostra o resultado da execução, um frame com largura 300 x 200 pixels
(setSize()), com o título “Frame Dois” (setTitle()), que não permite redimensionamento
(setResizable()).
(0 ,0) x
(x, y)
Conforme já mencionado, o frame ainda não pode ser fechado. Para que isso aconteça é
necessário ter uma maneira de se ter a notificação de quando ele é fechado. A partir da
manipulação desse evento, mostrado no exemplo a seguir, é possível fechar o frame. É necessário
importar o pacote java.awt.event.* para manipular eventos do AWT. O modelo de eventos e
os demais eventos de janela serão vistos em seções posteriores.
import java.awt.*;
3
import java.awt.event.*;
public class FrameTres extends Frame
{
public FrameTres() //construtor
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setTitle("Frame Três"); // título do Frame
setSize(300, 200); // largura: 300 pixels altura: 200 pixels
setResizable(false); // não permite o redimensionamento
setLocation(200, 100); // x: 200 pixels y: 100 pixels
}
public static void main (String[] args)
{
FrameTres fr = new FrameTres();
fr.setVisible(true);
}
}
Ainda em relação ao posicionamento, dependendo da resolução da tela onde o frame será aberto,
pode se ter situações bem desagradáveis, como, por exemplo, o frame ser aberto e ficar com parte
fora da tela. É necessário então posicionar o frame em coordenadas que independam da resolução
utilizada. O exemplo a seguir abrirá um frame com a metade do tamanho da tela, posicionado no
centro, respeitando a resolução.
import java.awt.*;
import java.awt.event.*;
public class FrameQuatro extends Frame
{
public FrameQuatro() //construtor
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension d = tk.getScreenSize();
setSize(d.width / 2, d.height / 2);
setLocation(d.width / 4, d.height / 4);
Image img = tk.getImage("icone.gif");
setIconImage(img);
setTitle("Frame Quatro");
setResizable(false);
}
public static void main (String[] args)
{
FrameQuatro fr = new FrameQuatro();
fr.setVisible(true);
}
}
Para que seja possível essa tarefa de posicionamento conforme a resolução de vídeo, é necessário
obter informações do sistema operacional, e isso é feito através da classe Toolkit, método
getScreenSize(), cujos dados são jogados em um objeto da classe Dimension, que armazena a
altura e largura nos campos d.width e d.height. Por exemplo, se a resolução de vídeo for
800x600, o d.width fica com 800 e o d.height fica com 600. Tendo esses valores, é possível
utilizar em métodos como o setLocation() e o setSize(), como foi feito no exemplo. Além
disso, o exemplo também acrescenta um ícone ao frame, também utilizando a classe Toolkit,
4
método getImage(), para carregar a imagem (extensão .gif) e jogar em um objeto da classe
Image, para depois setar o ícone através do setIconImage().
O mesmo exemplo pode ser feito baseado na biblioteca Swing, classe JFrame, mudando apenas a
derivação e importando o pacote javax.swing.*, assim:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FrameQuatro extends JFrame
{
...
}
Os exemplos apresentados nas próximas seções criarão frames baseado na classe JFrame.
A partir disso, métodos como drawString() e drawLine() podem ser utilizados, como no
exemplo a seguir. O resultado é apresentado na figura 1.4.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MostrandoTextos extends JFrame
{
public MostrandoTextos()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension d = tk.getScreenSize();
int screenHeight = d.height;
int screenWidth = d.width;
setSize(d.width / 2, d.height / 2);
setLocation(d.width / 4, d.height / 4);
setTitle("Escrevendo Textos");
setResizable(false);
}
5
g.drawString("Estou escrevendo no frame", 40+i, 50+i);
g.drawLine(40+i, 60+i, 200+i, 60+i);
i+=30;
}
}
1.3 Cores
O método setColor() seleciona a cor que é utilizada para todas as operações de desenho dentro
do contexto gráfico ou componente. Um parâmetro Color define a cor a ser usada, sendo que as
treze cores padrão, apresentadas na tabela 1.1, estão definidas na classe java.awt.Color.
6
lightGray (cinza-claro)
Além das cores pré-definidas, pode-se criar novas cores baseadas no conteúdo RGB (red-
vermelho, green-verde, blue-azul), expressos por inteiros de 0 a 255. O exemplo a seguir
apresenta a criação de objetos coloridos em um frame. O resultado é apresentado na figura 1.5.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Cores extends JFrame
{
public Cores()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(400, 200);
setLocation(200, 100);
setTitle("Cores");
}
7
O método drawRect(int x, int y, int width, int height) desenha um retângulo com a
cor definida em setColor(), iniciando nas coordenadas x,y, tendo uma largura width e uma
altura height. O método fillRect(int x, int y, int width, int height) faz a mesma
coisa, mas preenche o retângulo.
1.4 Fontes
O método responsável por definir o tipo de fonte desejado é o setFont(), que precisa de um
objeto criado, baseado na classe Font, definindo assim o nome da fonte, o seu estilo e seu
tamanho. O nome pode ser qualquer fonte suportada pelo sistema operacional específico; o estilo
pode ser: PLAIN – regular, BOLD – negrito e ITALIC – itálico, sendo possível combinar os estilos
utilizando o operador +; o tamanho pode ser qualquer valor que represente o tamanho em pontos
da fonte. Exemplo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Fontes extends JFrame
{
public Fontes()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(400,130);
setTitle("Tipos de Fonte");
}
8
Figura 1.6. Frame Fontes
Em termos de portabilidade, deve-se tomar cuidado quanto a fontes que não existem em alguns
sistemas operacionais. O ideal é trabalhar com fontes comuns em sistemas operacionais
diferentes. O modelo do AWT define cinco fontes disponíveis em qualquer sistema operacional.
São elas: Serif, Monospaced, SansSerif, Dialog e DialogInput.
9
}
• drawOval(int x, int y, int width, int height): Desenha uma forma oval,
baseado nas coordenadas do retângulo que inicia em x,y, tendo uma largura width e uma
altura height.
• fillOval(int x, int y, int width, int height): Idem a drawOval, mas preenche
a forma oval.
10
• drawPolygon(int[] xPoints, int[] yPoints, int nPoints): Desenha um
polígono, baseado nas coordenadas dos arranjos x,y.
1.6 Imagens
A classe Image é a responsável pelo carregamento de imagens armazenadas em disco.
Novamente, é necessário utilizar um objeto do tipo Toolkit para obter uma imagem, através do
método getImage(), e depois jogar em um objeto do tipo Image. O exemplo a seguir mostra a
maneira de se preencher um frame com as imagens lado a lado. A figura 1.8 mostra o resultado.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
11
Figura 1.8. Frame Imagens
A primeira imagem, obtida pelo getImage() e jogada no objeto Image ima, é mostrada a partir
do drawImage(Image img, int x, int y, ImageObserver observer), que insere a imagem
img nas coordenadas x,y, para depois ser copiada lado a lado, através do método
copyArea(int x, int y, int width, int height, int dx, int dy), que copia o
conteúdo da área que começar nas coordenadas x,y com largura width e altura height, em um
local a uma distância dx,dy. Para realizar essa tarefa, foi necessário descobrir o tamanho da
imagem, através getWidth() e do getHeight().
1.7 Contêiners
Contêiners servem de repositório de outros componentes, como botões, por exemplo. Alguns
exemplos de contêiners: JFrame, JPanel e JApplet. Um JFrame é uma janela de mais alto nível;
um JPanel é um contêiner usado para agrupar componentes, normalmente dentro de um JFrame;
um JApplet permite a execução em navegadores da Web. Pode-se desenhar algo diretamente no
frame ou definir um contêiner, como um painel, por exemplo, e desenhar nele. Não é considerada
uma boa prática de programação desenhar diretamente no frame, pois ele foi projetado para ser
contêiner de componentes específicos, como barras de menu, por exemplo. Os painéis devem ser
utilizados para agrupar outros componentes. Exemplo de adição de um painel a um frame:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
12
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(400,130);
setTitle("Painel");
Container P = getContentPane();
P.add(new Painel());
}
O resultado pode ser conferido na figura 1.9. Para desenhar algo em um painel, deve-se criar uma
classe derivada de JPanel e sobrepor o método paintComponent(), que está definido na classe
JComponent, e recebe um parâmetro do tipo Graphics. Tal método é chamado automaticamente
toda vez que a janela é redesenhada, como na criação e no redimensionamento. Se, por algum
motivo, se desejar redesenhar o conteúdo no painel, o método a ser chamado é o repaint(), que
se encarrega de executar novamente o paintComponent(). O super.paintComponent(g) faz
com que o método da superclasse seja executado também. Isso normalmente é feito em
sobreposições de métodos, quando se deseja criar algo a mais que o método definido na
superclasse. A criação de uma classe derivada de JFrame é feita a seguir, e um objeto Container
é criado para depois adicionar (add) o painel. O método getContentPane() retorna a área de
conteúdo do frame para que possa ser adicionado o painel.
13
import java.awt.event.*;
import javax.swing.*;
Como o FlowLayout é o gerenciador padrão do JPanel, não seria necessário setar o layout
através do setLayout(new FlowLayout());. O alinhamento dos componentes fica centralizado
e, caso algum compontnte não caiba em uma linha, é jogado para a linha seguinte, como mostra a
figura 1.10. É possível alterar o alinhamento, passando-o como parâmetro na determinação do
layout (LEFT, RIGHT ou CENTER), assim:
setLayout(new FlowLayout(FlowLayout.RIGHT));
14
O GridLayout é um gerenciador que organiza os componentes em linhas e colunas espaçadas
regularmente. Exemplo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
setSize(200,150);
setLocation(150,150);
setTitle("GridLayout");
Container P = getContentPane();
P.add(new PainelGrid());
}
15
setLayout(). Os componentes são adicionados a partir da posição na parte superior esquerda da
grade, seguindo para a direita até preencher a linha e passar para baixo.
Também é possível espaçar os componentes horizontal e verticalmente. Nesse caso, na definição
do layout, deve-se passar esses valores também. O layout abaixo, por exemplo, define 5 pixels de
espaçameno horizontal e 8 pixels de espaçamento vertical:
setLayout(new GridLayout(3,2,5,8));
1.8.3 Gerenciador BorderLayout
setSize(300,150);
setLocation(150,150);
setTitle("BorderLayout");
Container P = getContentPane();
P.add(new PainelBorder());
}
16
Figura 1.12. Gerenciador de Layout GridLayout
Na figura 1.12 se observa o resultado da aplicação, com um botão em cada localização geográfica
dentro do painel. O BorderLayout é o gerenciador padrão para os contêiners JWindow e JFrame.
Não é necessário ter todas as localizações preenchidas. Se alguma das localizações (norte, sul,
leste ou oeste) não for ocupada, as demais ocupam o lugar da(s) omitida(s). Porém, se a
localização central não for ocupada, ela ficará vazia.
Na definição do layout é possível determinar o espaçamento horizontal e vertical entre as
localizações. O layout abaixo, por exemplo, define 5 pixels de espaçameno horizontal e 8 pixels
de espaçamento vertical:
setLayout(new BorderLayout(5,8));
1.8.4 Gerenciador BoxLayout
Os gerenciadores de layout foram criados ainda na versão 1.0 do Java. O Swing possui apenas
um gerenciador de layout de uso geral, chamado BoxLayout, sendo mais utilizado para criar
barras de ferramentas, podendo inserir componentes em apenas uma linha ou uma coluna. Ao
invés de utilizar o BoxLayout diretamente, pode-se usar um outro contêiner do Swing chamado
Box, como no exemplo a seguir.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
17
{
public GerenciadorBoxLayout()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(500,100);
setLocation(150,150);
setTitle("BoxLayout");
Container b = Box.createHorizontalBox();
getContentPane().add(b,BorderLayout.CENTER);
b.add(new PainelBox());
}
Observa-se, na figura 1.13, que os botões não ficaram distanciados uniformemente. Isso porque
dois métodos foram utilizados: o createHorizontalGlue(), que determina um espaçamento
variável, conforme o tamanho da janela e o createHorizontalStrut(), que determina um
espaçamento fixo, determinado pelo seu parâmetro.
Campo Descrição
int gridx, gridy Utilizado para controlar o posicionamento dos componentes
na grade do layout.
int weightx, weighty Utilizado para especificar um percentual de aumento do local
destinado aos componentes, que irão aumentar também se
estiverem expandidos.
int fill Utilizado para expandir o componente a fim de preencher o
espaço reservado a ele.
int gridheight, gridwidth Utilizado para indicar o número de linhas ou colunas que o
18
componente irá se espalhar.
int anchor Utilizado para controlar a posição do componente, caso ele
não esteja espalhado.
int ipadx, ipady Utilizado para controlar o aumento do tamanho mínimo dos
componente.
Insets insets Utilizado para controlar o afastamento entre componentes.
Tabela 1.1. Campos da classe GridBagConstraints
A utilização desses campos são demonstradas através de exemplos. O primeiro deles mostra um
GridBagLayout com cinco botões inseridos em posições determinadas pelo gridx e gridy.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public PainelGridBag()
{
setLayout(new GridBagLayout());
addGridBag(new JButton("Um"), 1, 0);
addGridBag(new JButton("Dois"), 0, 1);
addGridBag(new JButton("Três"), 1, 1);
addGridBag(new JButton("Quatro"), 2, 1);
addGridBag(new JButton("Cinco"), 1, 2);
}
setSize(270,130);
setLocation(150,150);
setTitle("GridBagLayout");
Container P = getContentPane();
P.add(new PainelGridBag());
}
19
}
}
O resultado, mostrado na figura 1.13, apresenta cinco botões inseridos em coordenadas que
indicam a presença de três linhas por três colunas (0, 1 e 2). O tamanho da grade é definido por
essas coordenadas, sendo possível, por isso, ter quantas colunas e linhas se desejar. O método
addGridBag() criado serve para auxiliar na definição dos valores que os campos de controle do
GridBagConstraints irão assumir.
Para que os botões preencham toda a área do painel é necessário definir, no construtor, a restrição
fill para BOTH e os campos weigthx e weigthy para 1, assim:
public PainelGridBag()
{
setLayout(new GridBagLayout());
restricoes.weightx = 1.0;
restricoes.weighty = 1.0;
restricoes.fill = GridBagConstraints.BOTH;
addGridBag(new JButton("Um"), 1, 0);
addGridBag(new JButton("Dois"), 0, 1);
addGridBag(new JButton("Três"), 1, 1);
addGridBag(new JButton("Quatro"), 2, 1);
addGridBag(new JButton("Cinco"), 1, 2);
}
O resultado é o preenchimento de todo painel, como mostra a figura 1.14. O fill ainda pode ser
definido como: HORIZONTAL, preenchendo o espaço horizontal disponível; VERTICAL,
preenchendo o espaço vertical disponível e; NONE, não preenchendo o espaço disponível. Os
campos weigthx e weigthy devem receber um valor diferente de zero, pois o preenchimento não
ocorre se esse valor for igual a zero, que é o valor default.
É possível realizar um espalhamento dos componentes em mais do que uma linha e/ou coluna.
Para isso, é necessário combinar os valores de gridx e gridy com a determinação da altura (em
20
número de linhas) e largura (em número de colunas) através dos campos gridwidth e
gridheight, assim:
public PainelGridBag()
{
setLayout(new GridBagLayout());
restricoes.weightx = 1.0;
restricoes.weighty = 1.0;
restricoes.fill = GridBagConstraints.BOTH;
restricoes.gridwidth = 3;
addGridBag(new JButton("Um"), 0, 0);
restricoes.gridwidth = 1;
addGridBag(new JButton("Dois"), 0, 1);
addGridBag(new JButton("Três"), 1, 1);
restricoes.gridheight = 2;
addGridBag(new JButton("Quatro"), 2, 1);
restricoes.gridheight = 1;
addGridBag(new JButton("Cinco"), 0, 2);
addGridBag(new JButton("Seis"), 1, 2);
}
Percebe-se, pelo resultado apresentado na figura 1.15, que o botão Um ocupou três colunas e uma
linha, enquanto o botão Quatro ocupou duas linhas e uma coluna. No momento que o número de
colunas/linhas é definido, todos os componentes utilizarão esse tamanho de espaço daí pra diante,
a não ser que este seja redefinido.
É possível também definir o tamanho dos componentes através do peso atribuído aos campos
weigthx e weigthy, como no exemplo:
public PainelGridBag()
{
setLayout(new GridBagLayout());
restricoes.weighty = 1.0;
restricoes.fill = GridBagConstraints.BOTH;
restricoes.weightx = 0.2;
addGridBag(new JButton("Um"), 0, 0);
restricoes.weightx = 0.6;
addGridBag(new JButton("Dois"), 1, 0);
restricoes.weightx = 1.5;
addGridBag(new JButton("Três"), 2, 0);
restricoes.weightx = 4.0;
addGridBag(new JButton("Quatro"), 3, 0);
}
21
Figura 1.16. Gerenciador de Layout GridBagLayout com determinação de pesos
Para que o exemplo fique igual ao apresentado na figura 1.16, é necessário mudar o setSize()
do frame para (400,60). Os botões ficam dispostos em uma única linha, com tamanhos
diferentes, determinados pela atribuição de seus respectivos pesos, sabendo-se que o valor
específico do peso não é o que importa, e sim as proporções relativas entre os botões e o tamanho
do painel.
O aumento do tamanho de alguns componentes pode ser feito pelos campos ipadx e ipady, que
especificam valores de aumento vertical e horizontal. Além disso, é possível fixar uma posição
do componente, dentro do espaço reservado a ele, desde que ele não esteja espalhado em mais
que uma coluna e/ou linha. Isso é feito através do anchor. Exemplo:
public PainelGridBag()
{
setLayout(new GridBagLayout());
addGridBag(new JButton("Um"), 1, 0);
restricoes.ipadx=10;
restricoes.ipady=10;
addGridBag(new JButton("Dois"), 0, 1);
restricoes.ipadx=0;
restricoes.ipady=0;
restricoes.anchor = GridBagConstraints.SOUTHEAST;
addGridBag(new JButton("Três"), 1, 1);
restricoes.ipadx=10;
restricoes.ipady=10;
restricoes.anchor = GridBagConstraints.CENTER;
addGridBag(new JButton("Quatro"), 2, 1);
restricoes.ipadx=0;
restricoes.ipady=0;
addGridBag(new JButton("Cinco"), 1, 2);
}
Novamente, para que o exemplo fique igual ao da figura 1.17, é necessário alterar o setSize()
do frame para (270,130). Percebe-se que o tamanho dos componentes Dois e Quatro foi
aumentado, sendo mantido o tamanho mínimo do botão Três. Para esse mesmo botão Três foi
especificado um posicionamento fixo no canto inferior direito, dentro de sua área definida. O
anchor só pode ser utilizado quando o tamanho do componente for menor que a área que lhe foi
22
concedida. O valor padrão é CENTER, e os outros valores possíveis são: NORTH, NORTHEAST, EAST,
SOUTHEAST, SOUTH, SOUTHWEST, WEST, e NORTHWEST.
Através do campo insets é possível indicar as distâncias entre os componentes do layout. Uma
classe Insets possui valores para as quatro direções: cima, baixo, direita e esquerda, dando
muita flexibilidade ao layout. O valor padrão é (0, 0, 0, 0). Exemplo:
public PainelGridBag()
{
setLayout(new GridBagLayout());
restricoes.weightx = 1.0;
restricoes.weighty = 1.0;
restricoes.fill = GridBagConstraints.BOTH;
restricoes.insets = new Insets(3,3,3,3);
addGridBag(new JButton("Um"), 1, 0);
addGridBag(new JButton("Dois"), 0, 1);
addGridBag(new JButton("Três"), 1, 1);
addGridBag(new JButton("Quatro"), 2, 1);
addGridBag(new JButton("Cinco"), 1, 2);
}
A figura 1.18 mostra que cada componente ganhou um espaço adicional de três pixels para cada
uma das direções: cima, baixo, direita e esquerda.
1.8.6 Layouts Compostos
Normalmente, ao querer criar um determinado layout, a utillização de um gerenciador apenas não
é suficiente. É necessário, então, combinar os diferentes layouts, como no exemplo a seguir.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
23
public PainelTipoFlow()
{
setLayout(new FlowLayout());
add(new JButton("Um"));
add(new JButton("Dois"));
add(new JButton("Três"));
add(new JButton("Quatro"));
add(new JButton("Cinco"));
}
}
setSize(400,120);
setLocation(150,150);
setTitle("Layouts Compostos");
Container P = getContentPane();
P.add(new PainelComposto());
}
A figura 1.17 mostra que o painel com layout FlowLayout foi inserido na localização sul do
painel com layout BorderLayout. Isso é uma prática bastante comum para se alcançar layouts
com disposição de componentes que satisfaçam aos objetivos da aplicação. A localização do
centro ficou vazia porque isso é uma característica do BorderLayout: não expandir as outras
localizações se a do centro estiver vazia.
24
seções descrevem o modelo de manipulação de eventos AWT a partir de alguns elementos GUI
simples.
25
private JButton BotaoBranco;
public PainelEventosBotao()
{
BotaoVerde = new JButton("Verde");
BotaoPreto = new JButton("Preto");
BotaoBranco = new JButton("Branco");
add(BotaoVerde);
add(BotaoPreto);
add(BotaoBranco);
BotaoVerde.addActionListener(this);
BotaoPreto.addActionListener(this);
BotaoBranco.addActionListener(this);
}
26
Figura 2.1. Eventos em objetos JButton
Na criação do painel, três botões foram adicionados a ele. Logo após, foi determinado que o
próprio painel (this) seria o ouvinte das ações dos três botões. O método actionPerformed() é
o único método da interface ActionListener, por isso apenas ele deve ser implementado. Esse
método recebe como parâmetro um objeto do tipo ActionEvent, que fornece informações sobre
o evento ocorrido, sendo o local para implementar as ações a serem realizadas. A classe
TesteEventosBotao adiciona o painel com os botões.
public PainelEventosCaixaTexto()
{
Codigo = new JTextField(3);
add(Codigo);
Nome = new JTextField("Digite seu nome");
add(Nome);
Senha = new JPasswordField(10);
add(Senha);
Codigo.addActionListener(this);
Nome.addActionListener(this);
Senha.addActionListener(this);
}
27
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(300,70);
setLocation(300,350);
setTitle("Eventos em Caixas de Texto");
Container P = getContentPane();
P.add(new PainelEventosCaixaTexto());
}
A figura 2.1 mostra o que acontece se for digitado algo em código e logo a seguir for pressionada
a tecla Enter. Novamente, o método actionPerformed() foi sobreposto e, no momento que for
pressionado o Enter, o getSource() pega o objeto onde está o foco naquele momento e mostra
em uma caixa de mensagens, criada a partir do método showMessageDialog(), pertencente à
classe JOptionPane.
28
import javax.swing.*;
public PainelAV()
{
BotaoMetal = new JButton("Metal");
BotaoWindows = new JButton("Windows");
BotaoMotif = new JButton("Motif");
BotaoGTK = new JButton("GTK");
BotaoMac = new JButton("Mac");
Texto = new JTextField("Digite seu texto aqui");
add(BotaoMetal);
add(BotaoWindows);
add(BotaoMotif);
add(BotaoGTK);
add(BotaoMac);
add(Texto);
BotaoMetal.addActionListener(this);
BotaoWindows.addActionListener(this);
BotaoMotif.addActionListener(this);
BotaoGTK.addActionListener(this);
BotaoMac.addActionListener(this);
}
29
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(370,100);
setTitle("Aspectos Visuais");
Container P = getContentPane();
P.add(new PainelAV());
}
A figura 2.3 mostra e resultado da execução após selecionar cada um dos aspectos visuais. É
importante salientar que o aspecto Windows só funciona no próprio Windows, pois a Sun não
disponibiliza esse aspecto para outras plataformas. Alguns Look And Feel’s podem gerar uma
exceção, por não existirem ou não serem suportados em determinadas plataformas, como o que
ocorreu como aspecto Mac. É importante salientar também que, a depender do layout utilizado
em uma determinada aplicação, podem ocorrer problemas de aparência, por que tamanhos de
botões, caixas de texto e outros componentes variam de plataforma para plataforma, e podem
fazer com que a aparência de uma aplicação fique desorganizada, como o que ocorreu com o
aspecto GTK. Muitos aspectos interessantes podem ser encontrados na Internet.
30
getAdjustmentType
getValue
ItemListener ItemStateChanged ItemEvent Checkbox
getItem CheckboxMenuItem
getItemSelectable Choice
getStateChange List
TextListener TextValueChanged TextEvent TextComponent
ComponentListenter componentMoved ComponentEvent Component
componentHidden getComponent
componentResized
componentShown
ContainerListener componentAdded ComponentEvent Container
componentRemoved getChild
getContainer
FocusListener focusGained FocusEvent Component
focusLost isTemporary
KeyListener keyPressed KeyEvent Component
keyReleased getKeyChar
keyTyped getKeyCode
getKeyModifiersText
getKeyText
isActionKey
MouseListener mousePressed MouseEvent Component
mouseReleased getClickCount
mouseEntered getX
mouseExited getY
mouseClicked getPoint
translatePoint
isPopupTrigger
MouseMotionListener mouseDragged MouseEvent Component
mouseMoved
WindowListener windowClosing WindowEvent Window
windowOpened getWindow
windowIconified
windowDeiconified
windowClosed
windowActivated
windowDeactivated
Figura 2.3. Interfaces existentes para manipular eventos
Boa parte dos componentes do Swing utilizam essas mesmas interfaces para manipular eventos,
mas existem outras. Os pacotes dessas interfaces são: java.awt.event e javax.swing.event.
31
As próximas seções se destinam a apresentação dos principais componentes do Swing, além dos
botões e caixas de texto, que foram vistos no capítulo anterior.
public PainelEventosBotaoELabel()
{
32
public class TesteEventosBotaoELabel extends JFrame
{
public TesteEventosBotaoELabel()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(600,130);
setTitle("Botões e Labels");
Container P = getContentPane();
P.add(new PainelEventosBotaoELabel());
}
A figura 3.1 mostra a situação após o clique nos dois botões. No código, percebe-se que existem
duas maneiras de saber qual botão foi clicado. A primeira é testando o próprio texto do botão, a
partir do getActionCommand().equals(). A segunda é através da definição de um objeto
origem, que, através do método getSource(), sabe qual botão gerou o evento. No clique do
BotaoUm é alterado o texto do LabelUm, setado um ícone para ele e realizado seu posicionamento
horizontal (setHorizontalTextPosition()) e vertical (setVerticalTextPosition()). O
clique do BotaoDois altera o texto do LabelUm, além de utilizar o método setToolTipText()
para especificar a dica de ferramenta, que é exibida quando o cursor do mouse passa sobre o
label.
33
class PainelBotoesDeEstado extends JPanel implements ActionListener
{
private JTextField Texto;
private JCheckBox CBItalico;
private JCheckBox CBNegrito;
private JRadioButton RBSansSerif;
private JRadioButton RBMonospaced;
private JRadioButton RBSerif;
private ButtonGroup Grupo;
public PainelBotoesDeEstado()
{
Texto = new JTextField("Texto para visualização",15);
CBItalico = new JCheckBox("Itálico");
CBNegrito = new JCheckBox("Negrito");
RBSansSerif = new JRadioButton("SansSerif",true);
RBMonospaced = new JRadioButton("Monospaced",false);
RBSerif = new JRadioButton("Serif",false);
add(Texto);
add(CBItalico);
add(CBNegrito);
add(RBSansSerif);
add(RBMonospaced);
add(RBSerif);
Grupo = new ButtonGroup();
Grupo.add(RBSansSerif);
Grupo.add(RBMonospaced);
Grupo.add(RBSerif);
CBItalico.addActionListener(this);
CBNegrito.addActionListener(this);
RBSansSerif.addActionListener(this);
RBMonospaced.addActionListener(this);
RBSerif.addActionListener(this);
}
34
}
}
A figura 3.2 apresenta o resultado da execução do exemplo, já com alguns itens selecionados. Ao
clicar em uma caixa de seleção, é acionado um evento de ação, capturado no método
actionPerformed(). O método isSelect() retorna o estado atual da caixa de seleção e,
conforme o estado, as variáveis Italico e Negrito são atualizadas, para depois servirem de
parâmetro para a alteração da fonte a partir do setFont(). Os botões de rádio são criados, já
tendo setado qual é o botão que ficará selecionado inicialmente. Cada um desses botões deve ser
adicionado a um grupo de botões (ButtonGroup), sendo ele responsável pala desativação do
botão anteriormente selecionado, quando um novo for clicado. No actionPerformed() é
verificado qual botão originou o evento, e a variável Fonte é atualizada com a fonte atual, para
também servir de parâmetro no setFont(). Isso é feito através da criação de um objeto f, do tipo
Font, incializado a partir do getFont() e passado para a variável Fonte através do getName().
3.3 Bordas
O Swing oferece várias opções de bordas para melhorar o aspecto visual da aplicação. O método
setBorder(), da classe JComponent, é a responsável pela definição das bordas, recebendo como
parâmetro um objeto de uma das classes de bordas existentes no pacote javax.swing.border.
Por isso, é necessário realizar um import desse pacote. O exemplo a seguir mostra as diversas
bordas existentes, permitindo a utilização de título ou não.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
35
import javax.swing.border.*;
public Bordas()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(700,250);
setTitle("Bordas");
JPanel PainelBaixo = new JPanel();
RBEtched = new JButton("Etched");
RBEmpty = new JButton("Empty");
RBLine = new JButton("Line");
RBMatte = new JButton("Matte");
RBLoweredBevel = new JButton("LoweredBevel");
RBRaisedBevel = new JButton("RaisedBevel");
RBCompound = new JButton("Compound");
CBTitled = new JCheckBox("Titled");
PainelBaixo.add(RBEtched);
PainelBaixo.add(RBEmpty);
PainelBaixo.add(RBLine);
PainelBaixo.add(RBMatte);
PainelBaixo.add(RBLoweredBevel);
PainelBaixo.add(RBRaisedBevel);
PainelBaixo.add(RBCompound);
PainelBaixo.add(CBTitled);
Border borda = BorderFactory.createEtchedBorder();
Border BordaBaixo =
BorderFactory.createTitledBorder(borda," Tipos de Borda ");
PainelBaixo.setBorder(BordaBaixo);
Container P = getContentPane();
P.setLayout(new BorderLayout());
P.add(PainelBaixo,"South");
RBEtched.addActionListener(this);
RBEmpty.addActionListener(this);
RBLine.addActionListener(this);
RBMatte.addActionListener(this);
RBLoweredBevel.addActionListener(this);
RBRaisedBevel.addActionListener(this);
RBCompound.addActionListener(this);
CBTitled.addActionListener(this);
}
36
JPanel PainelCentro = new JPanel();
if (origem == RBEtched)
BordaCentro = BorderFactory.createEtchedBorder();
else if (origem == RBEmpty)
BordaCentro = BorderFactory.createEmptyBorder();
else if (origem == RBLine)
BordaCentro = BorderFactory.createLineBorder(Color.red);
else if (origem == RBMatte)
BordaCentro =
BorderFactory.createMatteBorder(8, 8, 8, 8, Color.orange);
else if (origem == RBLoweredBevel)
BordaCentro = BorderFactory.createLoweredBevelBorder();
else if (origem == RBRaisedBevel)
BordaCentro = BorderFactory.createRaisedBevelBorder();
else if (origem == RBCompound)
BordaCentro = BorderFactory.createCompoundBorder
(BorderFactory.createEtchedBorder(),
BorderFactory.createMatteBorder(3, 3, 3, 3, Color.green));
if (CBTitled.isSelected())
{
Border BordaTitulo =
BorderFactory.createTitledBorder(BordaCentro," Exemplo de Título ");
PainelCentro.setBorder(BordaTitulo);
}
else
PainelCentro.setBorder(BordaCentro);
Container P = getContentPane();
P.add(PainelCentro,"Center");
validate();
}
37
A figura 3.3 mostra o resultado da execução, onde cada um dos botões realiza a mudança para a
borda especificada. O título na borda somente é mostrado se a caixa de seleção Titled estiver
marcada.
De forma geral, para criar uma borda é necessário criar um objeto Border e utilizar um dos
métodos da classe BorderFactory para criar a borda desejada. Os tipos de borda existentes, os
métodos para criação, o parâmetros necessários em cada tipo e as variações possíveis são:
38
JComboBox e o tratamento dos eventos também pode ser feito através da interface
ActionListener, como mostra o exemplo a seguir.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public CaixasDeCombinacao()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(300,160);
setTitle("Caixa de Combinação");
Container P = getContentPane();
P.setLayout(new BorderLayout());
PainelSul = new JPanel();
Cores = new JComboBox(Itens);
PainelSul.add(Cores);
Cores.addActionListener(this);
P.add(PainelSul,"South");
PainelCentro = new JPanel();
Borda = BorderFactory.createMatteBorder(8, 8, 8, 8, cor);
PainelCentro.setBorder(Borda);
Texto = new JLabel("Verde");
PainelCentro.add(Texto);
P.add(PainelCentro,"Center");
}
39
CaixasDeCombinacao fr = new CaixasDeCombinacao();
fr.setVisible(true);
}
}
Uma borda Borda do tipo MatteBorder foi criada no PainelCentro para que as cores sejam
alteradas a partir da seleção pela caixa de combinação Cores (figura 3.4), localizada no
PainelSul. O PainelCentro também contém um label Texto, que mostra a cor atual da borda.
Para manipular o evento de seleção da caixa de combinação, foi implementado o método
actionPerformed(), que define um objeto origem, do tipo JComboBox, e testa o item
selecionado a partir do getSelectedItem(). Conforme a seleção, um objeto cor, do tipo Color,
é atualizado, para depois ser utilizado na definição da nova cor da borda. Além disso, o label
Texto também é atualizado com a cor selecionada.
• void removeItemAt(Object Item, int posicao): remove o item da lista que está
posição indicada.
40
As caixas de listagem, criadas a partir de objetos do tipo JList, apresentam listas de valores para
seleções únicas ou múltiplas. Elas, por si só, não apresenta nenhuma barra de rolagem, sendo
necessário para isso, inseri-la em um contêiner JScrollPane, como no exemplo a seguir.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
public CaixasDeListagem()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(250,100);
setTitle("Caixa de Listagem");
Container P = getContentPane();
PainelLista = new JPanel();
FrutasLegumes = new JList(ItensLista);
FrutasLegumes.setVisibleRowCount(3);
FrutasLegumes.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
PainelLista.add(new JScrollPane(FrutasLegumes));
LabelImagem = new JLabel(Imagens[0]);
PainelLista.add(LabelImagem);
FrutasLegumes.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e)
{
LabelImagem.setIcon(Imagens[FrutasLegumes.getSelectedIndex()]);
}
});
P.add(PainelLista);
}
41
Figura 3.5. Caixa de Listagem de seleção única
A figura 3.5 apresenta o resultado da execução da aplicação, onde há uma caixa de listagem com
três linhas e uma barra de rolagem. Ao clicar em cada opção, aparece ao lado a imagem
solicitada. Para criar a lista foi declarado um objeto FrutasLegumes, do tipo JList, passando
como parâmetro um arranjo String ItensLista, com os itens desejados. A partir do método
setVisibleRowCount() foi definido o número de itens visíveis da lista. O
setSelectionMode() especifica o modo de seleção da lista, definido na classe
ListSelectionModel, que pode ser: SINGLE_SELECTION, que permite a seleção de um único
item; SINGLE_INTERVAL_SELECTION, que permite a seleção múltipla e contígua na lista, e;
MULTIPLE_INTERVAL_SELECTION, que permite a seleção múltipla, não interessando quais itens
serão selecionados.
Para que a lista pudesse ser apresentada com a barra de rolagem, o objeto FrutasLegumes foi
adicionado a um JScrollPane que, por sua vez, foi adicionado ao painel. Por fim, para ser
possível tratar o evento de seleção na lista, foi necessário implementar a interface
ListSelectionListener(), que está definida em javax.swing.event, sendo preciso importar
esse pacote, e que utiliza o método valueChanged() para efetuar as ações desejadas. Para alterar
a imagem do LabelImagem foi utilizado o setIcon(), relacionando o índice do arranjo Imagens
com o índice do item que foi selecionado na lista, buscado através do getSelectedIndex(). O
modo como o evento foi tratado poderia ter sido feito como nos exemplos vistos até agora, assim:
42
import javax.swing.event.*;
public ListaSelecaoMultipla()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(250,150);
setTitle("Seleção Múltipla");
Container P = getContentPane();
PainelListaSM = new JPanel();
Numeros = new JList(ItensLista);
Numeros.setVisibleRowCount(5);
Numeros.setFixedCellWidth(60);
Numeros.setFixedCellHeight(20);
Numeros.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
PainelListaSM.add(new JScrollPane(Numeros));
Selecionados = new JList();
Selecionados.setVisibleRowCount(5);
Selecionados.setFixedCellWidth(80);
Selecionados.setFixedCellHeight(20);
Selecionados.setSelectionMode
(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
PainelListaSM.add(new JScrollPane(Selecionados));
P.add(PainelListaSM);
Numeros.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e)
{
Selecionados.setListData(Numeros.getSelectedValues());
}
});
}
43
Figura 3.6. Caixas de Listagem de seleção múltipla
Na figura 3.6 é possível perceber os vários itens selecionados intercaladamente na primeira caixa
de listagem. A segunda caixa foi criada para mostrar os itens selecionados na primeira caixa.
Dois novos métodos foram utilizados para alterar a parte visual das caixas de listagem:
setFixedCellWidth(), que determina um tamanho fixo de largura da caixa de listagem e;
setFixedCellHeight(), que determina um tamanho fixo de algura da caixa. Percebe-se que a
primeira caixa de listagem permite uma seleção intercalada de valores, através da utilização da
tecla Ctrl (MULTIPLE_INTERVAL_SELECTION), enquanto a segunda caixa permite apenas a
seleção contígua, utilizando a tecla Shift (SINGLE_INTERVAL_SELECTION). A caixa de listagem
Numeros recebeu um ouvinte de eventos que, no momento que cada item é selecionado, realiza a
operação de atualização da caixa Selecionados. Isso é feito através do método setListData(),
que recebe como parâmetro o conjunto de valores selecionados a partir do método
getSelectedValues().
44
Figura 3.7. Labels com imagens compartilhando um painel dividido pelo JSplitPane
A barra que divide as imagens (figura 3.7) é redimensionável, permitindo aumentar ou diminuir o
espaço de cada um dos componentes. Depois de criados os labels Um e Dois, eles são colocados
em um JScrollPane, para que tenham barras de rolagem, e atribuídos a dois objetos Esquerda e
Direita, do tipo Component. Estes, por sua vez, são os componentes que vão compartilhar a
divisão horizontal (HORIZONTAL_SPLIT) feita pelo JSplitPane. A outra forma de divisão é a
VERTICAL_SPLIT, que divide o painel verticalmente. O método setDividerLocation() indica a
posição onde deve ficar o divisor redimensionável e o método setDividerSize() determina o
tamanho em pixels da barra divisória.
public ControleDeslizante()
45
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(570,230);
setTitle("Controle Deslizante");
Container P = getContentPane();
P.setLayout(new BorderLayout());
JPanel PainelCDNorte = new JPanel();
TextoSlider = new JLabel("JSlider tamanho 20");
TextoSlider.setFont(new Font("SansSerif",Font.PLAIN,20));
PainelCDNorte.add(TextoSlider);
P.add(PainelCDNorte,"North");
JPanel PainelCDCentro = new JPanel();
TextoScroll = new JLabel("JScrollBar tamanho 20");
TextoScroll.setFont(new Font("SansSerif",Font.PLAIN,20));
PainelCDCentro.add(TextoScroll);
P.add(PainelCDCentro,"Center");
JPanel PainelCDSul = new JPanel();
TamanhoTextoSlider = new JSlider(SwingConstants.HORIZONTAL,0,50,20);
TamanhoTextoSlider.setMajorTickSpacing(10);
TamanhoTextoSlider.setMinorTickSpacing(2);
TamanhoTextoSlider.setPaintTicks(true);
PainelCDSul.add(TamanhoTextoSlider);
TamanhoTextoScroll = new JScrollBar(JScrollBar.HORIZONTAL,20,0,0,50);
TamanhoTextoScroll.setPreferredSize(
new Dimension(200,TamanhoTextoScroll.getPreferredSize().height));
PainelCDSul.add(TamanhoTextoScroll);
P.add(PainelCDSul,"South");
TamanhoTextoSlider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e)
{
TextoSlider.setText("JSlider tamanho "+TamanhoTextoSlider.getValue());
TextoSlider.setFont(
new Font("SansSerif",Font.PLAIN,TamanhoTextoSlider.getValue()));
}
});
TamanhoTextoScroll.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e)
{
TextoScroll.setText(
"JScrollBar tamanho "+TamanhoTextoScroll.getValue());
TextoScroll.setFont(
new Font("SansSerif",Font.PLAIN,TamanhoTextoScroll.getValue()));
}
});
}
46
Figura 3.8. Utilização do JSlider e e JScrollBar para alterar tamanho de fonte
47
abas, cada uma com um tipo diferente de caixa de diálogo, provenientes de objetos das classes
JOptionPane, JFileChooser e JColorChooser. As caixas de diálogo são, por padrão, modais,
ou seja, não é possível interagir com outras janelas enquanto essa não for fechada. Elas são
utilizadas para exibir alguma mensagem ou obter algum tipo de informação do usuário, seja uma
confirmação, uma entrada de dados, ou uma seleção de algo.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
public AbasRotuladas()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(450,150);
setLocation(300,200);
setTitle("Caixas de Diálogo de...");
Container P = getContentPane();
Abas = new JTabbedPane();
JPanel PCxDlgMensagem = new JPanel();
CDMensagem1 = new JButton("Mensagem 1");
CDMensagem2 = new JButton("Mensagem 2");
CDMensagem3 = new JButton("Mensagem 3");
PCxDlgMensagem.add(CDMensagem1);
PCxDlgMensagem.add(CDMensagem2);
PCxDlgMensagem.add(CDMensagem3);
JPanel PCxDlgConfirmacao = new JPanel();
CDConfirmacao1 = new JButton("Confirmação 1");
CDConfirmacao2 = new JButton("Confirmação 2");
CDConfirmacao3 = new JButton("Confirmação 3");
CDConfirmacao4 = new JButton("Confirmação 4");
LabelConfirmacao = new JLabel("Retorno:");
48
PCxDlgConfirmacao.add(CDConfirmacao1);
PCxDlgConfirmacao.add(CDConfirmacao2);
PCxDlgConfirmacao.add(CDConfirmacao3);
PCxDlgConfirmacao.add(CDConfirmacao4);
PCxDlgConfirmacao.add(LabelConfirmacao);
JPanel PCxDlgOpcao = new JPanel();
CDOpcao1 = new JButton("Opção 1");
LabelOpcao = new JLabel("Retorno:");
PCxDlgOpcao.add(CDOpcao1);
PCxDlgOpcao.add(LabelOpcao);
JPanel PCxDlgEntrada = new JPanel();
CDEntrada1 = new JButton("Entrada 1");
CDEntrada2 = new JButton("Entrada 2");
CDEntrada3 = new JButton("Entrada 3");
LabelEntrada = new JLabel("Retorno:");
PCxDlgEntrada.add(CDEntrada1);
PCxDlgEntrada.add(CDEntrada2);
PCxDlgEntrada.add(CDEntrada3);
PCxDlgEntrada.add(LabelEntrada);
JPanel PCxDlgArquivo = new JPanel();
CDArquivo1 = new JButton("Arquivo 1");
LabelArquivo1 = new JLabel("Retorno:");
LabelArquivo2 = new JLabel("Seleção:");
PCxDlgArquivo.add(CDArquivo1);
PCxDlgArquivo.add(LabelArquivo1);
PCxDlgArquivo.add(LabelArquivo2);
JPanel PCxDlgCor = new JPanel();
CDCor1 = new JButton("Cor 1");
LabelCor = new JLabel("Retorno:");
PCxDlgCor.add(CDCor1);
PCxDlgCor.add(LabelCor);
Abas.addTab("Mensagem",PCxDlgMensagem);
Abas.addTab("Confirmação",PCxDlgConfirmacao);
Abas.addTab("Opção",PCxDlgOpcao);
Abas.addTab("Entrada",PCxDlgEntrada);
Abas.addTab("Arquivo",PCxDlgArquivo);
Abas.addTab("Cor",PCxDlgCor);
P.add(Abas);
CDMensagem1.addActionListener(this);
CDMensagem2.addActionListener(this);
CDMensagem3.addActionListener(this);
CDConfirmacao1.addActionListener(this);
CDConfirmacao2.addActionListener(this);
CDConfirmacao3.addActionListener(this);
CDConfirmacao4.addActionListener(this);
CDOpcao1.addActionListener(this);
CDEntrada1.addActionListener(this);
CDEntrada2.addActionListener(this);
CDEntrada3.addActionListener(this);
CDArquivo1.addActionListener(this);
CDCor1.addActionListener(this);
}
49
String valorRet = null;
Icon icone = new ImageIcon("LogoSun.gif");
if (origem == CDMensagem1)
JOptionPane.showMessageDialog(null,
"Esta é uma caixa de diálogo de Mensagem");
else if (origem == CDMensagem2)
JOptionPane.showMessageDialog(null,
"Esta é uma caixa de diálogo de Mensagem",
"Mensagem", JOptionPane.WARNING_MESSAGE);
else if (origem == CDMensagem3)
JOptionPane.showMessageDialog(null,
"Esta é uma caixa de diálogo de Mensagem",
"Mensagem", JOptionPane.WARNING_MESSAGE, icone);
else if (origem == CDConfirmacao1)
{
retorno = JOptionPane.showConfirmDialog(null,"Confirma Operação?");
LabelConfirmacao.setText("Retorno: " + retorno);
}
else if (origem == CDConfirmacao2)
{
retorno = JOptionPane.showConfirmDialog(null,"Confirma Operação?",
"Confirmação", JOptionPane.YES_NO_OPTION);
LabelConfirmacao.setText("Retorno: " + retorno);
}
else if (origem == CDConfirmacao3)
{
retorno = JOptionPane.showConfirmDialog(null,"Confirma Operação?",
"Confirmação", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
LabelConfirmacao.setText("Retorno: " + retorno);
}
else if (origem == CDConfirmacao4)
{
retorno = JOptionPane.showConfirmDialog(null,"Confirma Operação?",
"Confirmação", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, icone);
LabelConfirmacao.setText("Retorno: " + retorno);
}
else if (origem == CDOpcao1)
{
Object[] opcoes = { "OK", "Cancelar" };
retorno = JOptionPane.showOptionDialog(null,
"Esta é uma caixa de diálogo de Opção",
"Opção",JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE,
null, opcoes, opcoes[0]);
LabelOpcao.setText("Retorno: " + retorno);
}
else if (origem == CDEntrada1)
{
valorRet = JOptionPane.showInputDialog(null, "Digite um valor");
LabelEntrada.setText("Retorno: " + valorRet);
}
else if (origem == CDEntrada2)
{
valorRet = JOptionPane.showInputDialog(null, "Digite um valor",
"Entrada", JOptionPane.QUESTION_MESSAGE);
LabelEntrada.setText("Retorno: " + valorRet);
50
}
else if (origem == CDEntrada3)
{
Object[] valores= {"Opção Um","Opção Dois","Opção Três","Opção Quatro"};
Object valorSelec = JOptionPane.showInputDialog(null,
"Escolha uma opção",
"Entrada", JOptionPane.INFORMATION_MESSAGE,
null, valores, valores[0]);
LabelEntrada.setText("Retorno: " + valorSelec.toString());
}
else if (origem == CDArquivo1)
{
JFileChooser abreArquivo = new JFileChooser();
abreArquivo.setCurrentDirectory(new File("."));
abreArquivo.setSelectedFile(new File("AbasRotuladas.java"));
retorno = abreArquivo.showOpenDialog(this);
LabelArquivo1.setText("Retorno: " + retorno);
if (retorno == JFileChooser.APPROVE_OPTION)
{
File arquivoSelec = abreArquivo.getSelectedFile();
LabelArquivo2.setText("Seleção: " + arquivoSelec.getName());
}
else
LabelArquivo2.setText("Seleção: Nenhum arquivo");
}
else if (origem == CDCor1)
{
JColorChooser abreCor = new JColorChooser();
Color c = abreCor.showDialog(this, "Escolha uma cor", Color.black);
LabelCor.setForeground(c);
LabelCor.setText("Retorno: " + c.toString());
}
}
Figura 3.9. Abas rotuladas para demonstração das diversas caixas de diálogo
Na figura 3.9 é possível visualizar a situação do frame na execução da aplicação. Para que as abas
fossem criadas, foi definido um objeto Abas, do tipo JTabbedPane. Como são seis as abas, foram
criados seis painéis (PCxDlgMensagem, PCxDlgConfirmacao, PCxDlgOpcao, PCxDlgEntrada,
51
PCxDlgArquivo e PCxDlgCor), inseridos botões e labels em cada um deles, conforme a
necessidade, para depois, através do método addTab(), inseri-los no objeto Abas, permitindo a
inclusão de um título para cada aba.
52
• static int showConfirmDialog(Component componentePai, Object mensagem):
mostra uma caixa de confirmação com o título Select an Option e os botões Yes, No e
Cancel.
O terceiro tipo é a caixa de diálogo de opção, onde é possível determinar as opções possíveis para
os botões, na resposta de uma mensagem. O método para criação desse tipo de caixa de diálogo é
o showOptionDialog(), que possui como retorno um inteiro que indica o botão que foi
pressionado (começando por zero). Nesse tipo de caixa de diálogo não existem variações em
relação aos parâmetros, sendo necessário passar todos eles. Então, a única sintaxe aceita é:
O quarto tipo é a caixa de diálogo de entrada, que é um pouco diferente que as outras, pois
permite a inserção ou seleção de valores textuais. Se a caixa de diálogo permitir a inserção de um
valor, o retorno é do tipo String, já que o que vai ser digitado é um texto. No caso de ser
permitida a seleção de um dos valores em uma lista, o retorno é um objeto do tipo Object, onde,
através de um método toString() é possível obter o conteúdo textual do ítem selecionado. O
método para criação desse tipo de caixa de diálogo é o showInputDialog() e suas variações são:
53
com a possibilidade de inserir um título e selecionar o tipo da mensagem, que vai definir o
ícone a ser apresentado, que pode ser: ERROR_MESSAGE, INFORMATION_MESSAGE,
WARNING_MESSAGE, QUESTION_MESSAGE, ou PLAIN_MESSAGE.
A quinta aba apresenta um botão que, ao ser clicado, abre uma caixa de diálogo de arquivos,
como mostra a figura 3.11. A classe JFileChooser fornece métodos para apresentar essa caixa
de diálogo e configurá-la conforme as necessidades. Semelhante às outras caixas de diálogo, essa
também é apresentada na forma modal, tendo que fecha-la antes de continuar a utilização da
aplicação que a chamou.
54
Esse retorno pode ser testado utilizando o JFileChooser.APPROVE_OPTION, no caso de ter sido
clicado o botão Open e JFileChooser.CANCEL_OPTION, no caso de ter sido clicado o botão
Cancel. No exemplo, se for clicado no botão Open, é atribuído ao objeto arquivoSelec, do tipo
File, o retorno do método getSelectedFile(), que traz o arquivo que foi selecionado na caixa
de diálogo. Se existir a situação de múltipla seleção de arquivos, o método a ser utilizado é o
getSelectedFiles(), que retorna um arranjo de objetos do tipo File. Após, o nome desse
arquivo foi mostrado no label LabelArquivo2, através do método getName(). Caso tenha sido
clicado no botão Cancel, esse mesmo label apresenta uma mensagem que não foi selecionado
nenhum arquivo.
A sexta e última aba apresenta um botão que, ao ser clicado, abre uma caixa de diálogo de
seleção de cores, mostrado na figura 3.12. A classe JColorChooser é a responsável por essa
tarefa. No exemplo, foi criado um objeto abreCor a partir dessa classe e depois foi aberta a caixa
de diálogo a partir do método showDialog(), tendo que passar como parâmetro o seu título e a
sua cor inicial. O retorno desse método foi atribuído a um objeto c, do tipo Color, para depois ser
utilizado na determinação da cor do label, através do método setForeground().
55
serem clicados, podem abrir itens de menu, com ações diretas, ou submenus, que abrem outros
menus suspensos à direita, contendo itens de menu ou até mesmo outros submenus.
Os itens de menu podem ser mostrados de diversas formas: com uma imagem associada, com
teclas de atalho, com teclas aceleradoras, na forma de caixa de seleção ou botão de rádio. Ao
serem clicados, os itens de menu disparam eventos de ação, como um botão, por exemplo.
Referente às teclas de atalho, são utilizados mnemônicos para realizar essa função, que sublinham
um caracter para cada item de menu e são ativados utilizando a tecla Alt + caracter sublinhado.
Quanto às teclas aceleradoras, é possível relacionar uma combinação de teclas, ou uma tecla de
função, aos itens de menu, como Ctrl + C, Alt + R ou F3.
Para demonstar a utilização da maioria das funções possíveis em um menu, o exemplo a seguir
apresenta uma barra de menu com itens que manipulam uma área de texto. Uma área de texto é
semelhante aos objetos da classe JTextField, mas permite a entrada de mais que uma linha de
texto, podendo utilizar a tecla Enter para passar de uma linha para outra. A classe responsável por
esse componente é a JTextArea, permitindo especificar o número de linhas e colunas na criação
dos seus objetos.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public TesteDeMenu()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(400,180);
setLocation(200,150);
setTitle("Menus e Áreas de Texto");
JMenuBar BarraMenu = new JMenuBar();
setJMenuBar(BarraMenu);
// criação do menu Arquivo
JMenu menuArquivo = new JMenu("Arquivo");
menuArquivo.setMnemonic('A');
JMenuItem itemNovo = new JMenuItem("Novo...", new ImageIcon("novo.gif"));
itemNovo.setMnemonic('N');
JMenuItem itemAbrir= new JMenuItem("Abrir...",new ImageIcon("abrir.gif"));
itemAbrir.setMnemonic('b');
itemAbrir.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
InputEvent.CTRL_MASK));;
JMenuItem itemSalvar= new JMenuItem("Salvar",new ImageIcon("salvar.gif"));
itemSalvar.setMnemonic('S');
itemSalvar.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
InputEvent.CTRL_MASK));;
JMenuItem itemSair= new JMenuItem("Sair");
56
itemSair.setMnemonic('r');
itemSair.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
InputEvent.ALT_MASK));;
menuArquivo.add(itemNovo);
menuArquivo.add(itemAbrir);
menuArquivo.addSeparator();
menuArquivo.add(itemSalvar);
menuArquivo.addSeparator();
menuArquivo.add(itemSair);
BarraMenu.add(menuArquivo);
itemNovo.addActionListener(this);
itemAbrir.addActionListener(this);
itemSalvar.addActionListener(this);
itemSair.addActionListener(this);
// criação do menu Editar
JMenu menuEditar = new JMenu("Editar");
menuEditar.setMnemonic('E');
JMenuItem itemRecortar = new JMenuItem("Recortar...",
new ImageIcon("recortar.gif"));
itemRecortar.setMnemonic('t');
itemRecortar.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
InputEvent.CTRL_MASK));;
JMenuItem itemCopiar = new JMenuItem("Copiar...",
new ImageIcon("copiar.gif"));
itemCopiar.setMnemonic('b');
itemCopiar.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
InputEvent.CTRL_MASK));;
JMenuItem itemColar = new JMenuItem("Colar...",
new ImageIcon("colar.gif"));
itemColar.setMnemonic('S');
itemColar.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,
InputEvent.CTRL_MASK));;
menuEditar.add(itemRecortar);
menuEditar.add(itemCopiar);
menuEditar.add(itemColar);
BarraMenu.add(menuEditar);
itemRecortar.addActionListener(this);
itemCopiar.addActionListener(this);
itemColar.addActionListener(this);
// criação do menu Formatar
JMenu menuFormatar = new JMenu("Formatar");
menuFormatar.setMnemonic('F');
// criação do submenu Cor
String nomesCores[]= {"Preto", "Vermelho", "Azul", "Laranjado", "Verde"};
JMenu menuCor = new JMenu("Cor");
menuCor.setMnemonic('C');
RBCores = new JRadioButtonMenuItem[nomesCores.length];
grupoCores = new ButtonGroup();
for (int i = 0; i < nomesCores.length; i++)
{
RBCores[i] = new JRadioButtonMenuItem(nomesCores[i]);
menuCor.add(RBCores[i]);
grupoCores.add(RBCores[i]);
RBCores[i].addActionListener(this);
}
RBCores[0].setSelected(true);
menuFormatar.add(menuCor);
57
menuFormatar.addSeparator();
// criação do submenu Fonte
String nomesFontes[] = {"SansSerif", "Monospaced", "Serif"};
JMenu menuFonte = new JMenu("Fonte");
menuFonte.setMnemonic('n');
RBFontes = new JRadioButtonMenuItem[nomesFontes.length];
grupoFontes = new ButtonGroup();
for (int i = 0; i < RBFontes.length; i++)
{
RBFontes[i] = new JRadioButtonMenuItem(nomesFontes[i]);
menuFonte.add(RBFontes[i]);
grupoFontes.add(RBFontes[i]);
RBFontes[i].addActionListener(this);
}
RBFontes[0].setSelected(true);
menuFonte.addSeparator();
String CBItalicoNegrigoItens[] = {"Negrito", "Itálico"};
CBNegritoItalico = new JCheckBoxMenuItem[CBItalicoNegrigoItens.length];
for (int i = 0; i < CBItalicoNegrigoItens.length; i++)
{
CBNegritoItalico[i] = new JCheckBoxMenuItem(CBItalicoNegrigoItens[i]);
menuFonte.add(CBNegritoItalico[i]);
CBNegritoItalico[i].addActionListener(this);
}
menuFormatar.add(menuFonte);
BarraMenu.add(menuFormatar);
// criação do menu Ajuda
JMenu menuAjuda = new JMenu("Ajuda");
menuAjuda.setMnemonic('u');
JMenuItem itemSobre = new JMenuItem("Sobre a Aplicação...");
itemSobre.setMnemonic('S');
menuAjuda.add(itemSobre);
BarraMenu.add(menuAjuda);
itemSobre.addActionListener(this);
AreaTexto = new JTextArea(5, 40);
AreaTexto.setForeground(Color.black);
AreaTexto.setFont(new Font("SansSerif", Font.PLAIN, 14));
AreaTexto.setLineWrap(true);
Container P = getContentPane();
P.add(new JScrollPane(AreaTexto));
}
58
System.exit(0);
else if (item == "Recortar...")
AreaTexto.cut();
else if (item == "Copiar...")
AreaTexto.copy();
else if (item == "Colar...")
AreaTexto.paste();
else if (item == "Sobre a Aplicação...")
JOptionPane.showMessageDialog(this,
"Este é um exemplo de utilização de menus",
"Sobre", JOptionPane.PLAIN_MESSAGE);
else
{
int Tipo = Font.PLAIN;
if (CBNegritoItalico[0].isSelected())
Tipo += Font.BOLD;
if (CBNegritoItalico[1].isSelected() )
Tipo += Font.ITALIC;
AreaTexto.setFont(new Font(AreaTexto.getFont().getName(), Tipo, 14));
for (int i = 0; i < RBCores.length; i++)
if (evt.getSource() == RBCores[i])
{
AreaTexto.setForeground(cores[i]);
break;
}
for (int i = 0; i < RBFontes.length; i++ )
if (evt.getSource() == RBFontes[i])
{
AreaTexto.setFont(new Font(RBFontes[i].getText(), Tipo, 14));
break;
}
repaint();
}
}
}
59
A figura 3.13 mostra a execução da aplicação, notando que não foi inserido nenhum painel no
frame, tendo sido setada a barra de menu para o frame e inserida a área de texto diretamente em
um contêiner. Para criar uma área de texto é necessário, primeiramente, criar um objeto do tipo
JTextArea e passar os parâmetros para determinar o número de linhas e o número de colunas
desejado. Após, alguns métodos podem ser utilizados para configurar a área: o setForeground()
indica a cor do texto; o setFont() determina o tipo, tamanho e formato de fonte; o
setLineWrap() determina se o texto vai mudar de linha ao chegar no final da área definida. Para
que o texto possa ser mostrado com barras de rolagem, caso este seja maior que a área visível, é
necessário inserir o objeto área de texto em um objeto JScrollPane e após inseri-lo no contêiner.
Dois outros métodos são úteis: o setWrapStyleWord(), que faz a quebra da linha ao final da
palavra se o parâmetro for true, ou ignora o final da palavra para a quebra da linha, se o
parâmetro for falso, e; o setTabSize(), que determina, em seu parâmetro, o número de colunas
utilizados para a tabulação.
Para criar o menu mostrado na figura 3.14, foi necessário seguir vários passos. No exemplo, antes
de tudo, foi criado o objeto BarraMenu, do tipo JMenuBar, para depois ser passado como
parâmetro pelo método setJMenuBar(), que é responsável pela inserção do menu no frame.
Após foram inseridos os vários menus que compõem a barra de menu. Para a criação do menu
Arquivo foi criado um objeto menuArquivo, do tipo JMenu e setado um mnemônico, que irá
sublinhar o caracter desejado e servir de tecla de atalho, através do método setMnemonic().
Os itens de menu são adicionados a seguir, a partir da criação de objetos do tipo JMenuItem,
permitindo a definição de imagens a serem mostradas juntamente com os itens. Para cada item foi
setada uma tecla de atalho a partir do setMnemonic() e, para alguns deles, foram associadas
teclas aceleradoras através do método setAccelerator(), tendo que passar como parâmetro um
objeto do tipo KeyStroke, que identifica o caracter e a tecla de controle utilizados para fazer a
combinação. Tendo definidos todos itens de menu, suas teclas de atalho e aceleradoras, estes
foram adicionados ao menu menuArquivo, e este foi adiconado à barra de menu BarraMenu.
Percebe-se a existência de linhas separatórias entre os itens, criadas pelo método
addSeparator(). Como os itens de menu respondem a eventos de ação, foi setado um ouvinte
de eventos para cada um, a partir do addActionListener. Os mesmos passos foram seguidos
para criar os menus menuEditar e menuAjuda.
A criação do menuFormatar segue basicamente os mesmos passos, mas eles possuem, no lugar
de itens de menu comuns, itens que abrem submenus, que contém outros itens especiais (caixas
60
de seleção e botões de rádio). Assim, no menu Formatar foram inseridos dois submenus: Cor e
Fonte. Para a criação do menu Cor foi definido um objeto menuCor, do tipo JMenu, e foram
adicionados seis itens de menu a partir do arranjo RBCores, do tipo JRadioButtonMenuItem. Por
se tratar de botões de rádio, foi necessário adicioná-los também ao grupo grupoCores, do tipo
ButtonGroup. Antes de adicionar o menuCor ao menuFormatar, foi setado o botão de rádio que
inicia selecionado, pelo método setSelected().
Para a criação do menu Fonte foi definido um objeto menuFonte, também do tipo JMenu, e foram
adicionados: um grupo de botões de rádio, seguindo os mesmos passos já apresentados, uma
linha separatória, e dois itens do tipo caixa de seleção, feitos a partir do arranjo
CBNegritoItalico, do tipo JCheckBoxMenuItem. Ao final, o menuFonte foi adicionado ao
menuFormatar, e esse, por sua vez, foi adicionado à barra de menu. Da mesma forma que os
itens de menu normais, tembém foi setado um ouvinte de eventos para cada um, a partir do
addActionListener.
Como já comentado, para o tratamento dos eventos, foi utilizada a interface ActionListener e
implementado o método actionPerformed() que, a partir do getActionCommand(), permite a
comparação do que foi clicado com o texto do item de menu específico. Como as opções Novo,
Abrir e Salvar não possuem uma efetiva implementação, foi apresentada uma mensagem para
cada uma delas. O item Sair encerra a aplicação. Os itens do menu Editar simplesmente
executam os métodos cut(), copy() e paste(), do objeto AreaTexto. O item Sobre também
mostra apenas uma mensagem. Caso o item selecionado for algum dos constantes no menu
Formatar, então são utilizados métodos como o setFont() e o setForeground(), para realizar
as operações desejadas, sendo confirmadas a partir do repaint().
61
Como padrão, os componentes do Swing são percorridos, pela tecla Tab, da esquerda para a
direita e de cima para baixo, dentro do contêiner. Essa ordem é conhecida como “Ordem de
tabulação”, e o exemplo a seguir foi criado para realizar a verificação dessa ordem.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public TesteDeFoco()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(300,170);
setLocation(200,200);
setTitle("Teste de Foco");
Container P = getContentPane();
P.setLayout(new GridLayout(2,1));
JPanel PainelFocoCima = new JPanel();
TextoUm = new JTextField("Texto Um",10);
PainelFocoCima.add(TextoUm);
TextoDois = new JTextField("Texto Dois",10);
PainelFocoCima.add(TextoDois);
BotaoUm = new JButton("Botão Um");
PainelFocoCima.add(BotaoUm);
BotaoDois = new JButton("Botão Dois");
PainelFocoCima.add(BotaoDois);
Border bordaPainelCima = BorderFactory.createEtchedBorder();
PainelFocoCima.setBorder(bordaPainelCima);
P.add(PainelFocoCima);
JPanel PainelFocoBaixo = new JPanel();
TextoTres = new JTextField("Texto Três",10);
PainelFocoBaixo.add(TextoTres);
TextoQuatro = new JTextField("Texto Quatro",10);
PainelFocoBaixo.add(TextoQuatro);
BotaoTres = new JButton("Botão Três");
PainelFocoBaixo.add(BotaoTres);
BotaoQuatro = new JButton("Botão Quatro");
PainelFocoBaixo.add(BotaoQuatro);
Border bordaPainelBaixo = BorderFactory.createEtchedBorder();
PainelFocoBaixo.setBorder(bordaPainelBaixo);
P.add(PainelFocoBaixo);
}
62
JFrame fr = new TesteDeFoco();
fr.setVisible(true);
}
}
As legendas inseridas na figura 3.15 mostram o sentido natural seguido pelos componentes do
Swing. Se existir um contêiner dentro de outro, no momento que entrar no contêiner interno, irá
ser seguida a ordem padrão até o seu último componente, só então voltará a percorrer os
componentes do contêiner externo. É possível alterar essa ordem através do método
setNextFocusableComponent(). Por exemplo, para passar o foco do objeto TextoUm
diretamente para o TextoTres, basta implementar o código:
TextoUm.setNextFocusableComponent(TextoTres);
Nesse caso, após o TextoUm viria o TextoTres, e depois retornaria o sentido normal, ou seja:
TextoDois, BotaoUm, etc., a não ser que se altere novamente a ordem.
Como visto anteriormente, o requestFocus() permite alterar o foco, mas apenas em resposta a
algum evento. Isso é bastante útil se for necessário testar o conteúdo de uma caixa de texto e,
caso não esteja correto, emitir uma mensagem e não permitir a saída da caixa, como no exemplo
a seguir.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public FocoAlterado()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(300,70);
setLocation(200,200);
setTitle("Alterando o Foco");
Container P = getContentPane();
JPanel PainelFoco = new JPanel();
TextoUm = new JTextField("Texto Um",10);
PainelFoco.add(TextoUm);
63
TextoDois = new JTextField("Texto Dois",10);
PainelFoco.add(TextoDois);
P.add(PainelFoco);
TextoUm.addFocusListener(this);
}
A figura 3.16 mostra o que acontece se for feita a tentativa de sair da primeira caixa de texto sem
digitar nada nela. Para que isso seja possível, é necessário implementar os métodos da interface
FocusListener, focusLost() e focusGained(), que são invocados no momento que a origem
do evento ganhar ou perder o foco. O parâmetro FocusEvent é uma classe que apresenta alguns
métodos importantes, como o getComponent(), que informa quem recebeu ou perdeu o foco e o
isTemporary(), que informa se a mudança de foco foi permanente ou temporária, podendo ser,
por exemplo, na ativação de uma outra janela e posterior retorno à janela atual.
64
nenhuma ação no ganho de foco, o método focusGained() ficou vazio, lembrando a
obrigatoriedade de se implementar todos os métodos de uma interface.
Quando as janelas, incluindo o JFrame, gerarem algum evento, deve haver um ouvinte de eventos
baseado na interface WindowListener para seu tratamento, e alguns métodos podem ser
implementados, como é o caso do trecho de código a seguir, que tem sido colocado nos exemplos
vistos até aqui, com a função de fechar o frame. O método windowClosing() é executado no
momento que é clicado no botão específico para fechar a janela da plataforma corrente, sendo
necessário para isso encerrar a aplicação com o método System.exit(0).
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
Além do método windowClosing(), outros seis métodos podem ser implementados. São eles:
65
System.exit(0);
}
public void windowOpened(WindowEvent e)
{
setTitle("Aberto");
}
public void windowIconified(WindowEvent e)
{
setTitle("Minimizado");
}
public void windowDeiconified(WindowEvent e)
{
setTitle("Restaurado");
}
});
setSize(300,70);
setLocation(200,200);
}
Percebe-se que a estrutura adotada na maioria dos exemplos vistos até aqui foi seguida,
acrescentando-se apenas os métodos windowOpened(), na abertura do frame,
windowIconified(), no ato de minimizar o frame, e windowDeiconified(), no ato de restaurar
o frame. O resultado, apresentado na figura 3.17, mostra que foi feita uma alteração no título do
frame nesses métodos. O método windowClosing(), antes de finalizar a aplicação, mostra uma
mensagem alertando o usuário que isso irá acontecer. Nota-se que os demais métodos não foram
implementados, pois nesse tipo de implementação não é necessário.
A segunda maneira de realizar as mesmas tarefas é mostrada no exemplo a seguir.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
66
{
addWindowListener(this);
setSize(300,70);
setLocation(200,200);
}
67
objeto do tipo MouseEvent, que contém as informações necessárias para o tratamento, como as
coordenadas x e y de onde o evento ocorreu, por exemplo.
A interface MouseListener possui cinco métodos possíveis de serem implementados. São eles:
public EventosDeMouse()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
addMouseListener(this);
addMouseMotionListener(this);
setSize(400,100);
setLocation(200,200);
setTitle("Eventos de Mouse");
Container P = getContentPane();
P.setLayout(new BorderLayout());
JPanel PainelEMCentro = new JPanel();
68
BotaoOK = new JButton("OK");
PainelEMCentro.add(BotaoOK);
P.add(PainelEMCentro,"Center");
JPanel PainelEMSul = new JPanel();
Mensagem = new JLabel();
PainelEMSul.add(Mensagem);
P.add(PainelEMSul,"South");
BotaoOK.addMouseListener(this);
}
69
" y = " + e.getY());
}
Apenas uma das mensagens, das várias existentes, está sendo mostrada na figura 3.18. Antes de
tudo, as duas interfaces estão sendo utilizadas, através do implements MouseListener,
MouseMotionListener. Através do addMouseListener() e do addMouseMotionListener() foi
setado o frame como sendo ouvinte de eventos dele mesmo. Para que o botão BotaoOK também
pudesse responder aos eventos de clique, foi adicionado um ouvinte de eventos para ele. O
resultado é que, para cada um dos métodos implementados, uma mensagem é mostrada no label
Mensagem, que fica no painel situado na parte sul do frame. Em algumas situações, porém,
algumas mensagens não podem ser vistas porque a mensagem de outro evento a sobrepõe, como
é o caso de quando se entra no frame, onde a mensagem é sobreposta por aquela emitida pelo
método mouseMoved().
70
DEFAULT_CURSOR
HAND_CURSOR
WAIT_CURSOR
TEXT_CURSOR
CROSSHAIR_CURSOR
MOVE_CURSOR
Por fim, durante a movimentação sobre o frame, com ou sem o botão do mouse pressionado, uma
mensagem é mostrada, indicando o posicionamento. Os métodos responsáveis são o
mouseMoved() e o mouseDragged(). Percebe-se que esse tipo de mensagem não aparece quando
se passa em cima do botão. Isso ocorre porque não foi adicionado um ouvinte de eventos de
movimento (addMouseMotionListener()) ao botão.
3.10.4 Eventos de Teclado
Da mesma forma que o mouse, qualquer evento gerado pelo teclado pode ser tratado, mas isso só
é necessário em situações em que o evento ocorrido não esteja associado a um componente
específico. No mesmo exemplo utilizado para os eventos de mouse, um botão, para ser
presssionado, pode ser clicado o mouse sobre ele, ou pode ser pressionada a barra de espaços
quando o foco está sobre ele. Nesse caso, o evento a ser tratado não é algum específico de
teclado, e sim o evento específico para o botão. Nos casos específicos de tratamento de eventos
de teclado, a interface utilizada é a KeyListener, onde existem três métodos possíveis de serem
implementados, todos eles recebendo um objeto do tipo KeyEvent como parâmetro. São eles:
• keyTyped(): ocorre quando há o pressionamento de qualquer tecla que não seja uma tecla
de ação, como o Home, End, Caps Lock, Shift, Alt, etc.
71
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public EventosDeTeclado()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
addKeyListener(this);
setSize(250,100);
setLocation(300,250);
setTitle("Eventos de Teclado");
Container P = getContentPane();
Mensagem = new JLabel();
P.add(Mensagem);
}
}
if (tecla == KeyEvent.VK_A && e.isControlDown())
{
combinacao = true;
teclaPressed = "Control + A";
}
if (tecla == KeyEvent.VK_A && e.isAltDown())
{
combinacao = true;
teclaPressed = "Alt + A";
}
Mensagem.setText("Tecla " + tecla + " - " + teclaPressed +" PRESSIONADA");
72
}
Um label Mensagem inserido no frame (figura 3.19) indica qual tecla ou combinação foi
pressionada ou liberada. Para que isso seja possível, é necessário implementar os três métodos da
interface KeyListener. No exemplo, algumas variáveis foram declaradas a fim de utilizar nos
três métodos, já que, em algumas situações, a mensagem de um sobreporia aquela emitida por
outro método. No keyPressed() a variável tecla armazena o código inteiro da tecla
pressionada, a partir do getKeyCode(), e a variável teclaPressed armazena a descrição da tecla
pressionada, a partir do getKeyText(). No caso de se querer testar uma tecla específica, é
necessário testar o código para ver se ele é igual a alguma das constantes definidas na classe
KeyEvent, sempre iniciadas por VK_. No exemplo, foi feito isso simplesmente para colocar uma
descrição em português de algumas teclas na variável teclaPressed. Após, foi verificada a
ocorrência, e atualizada a variável teclaPressed, das combinações de teclas Shift+A,
Control+A e Alt+A, através dos métodos isShiftDown(), isControlDown() e isAltDown(),
respectivamente. A variável entrouPressed é setada para true sempre que for executado o
método keyPressed() e a variável combinacao é setada para true sempre que forem
73
pressionadas as combinações anteriormente citadas. Ao final, é mostrado no label o código e a
descrição da tecla ou combinação pressionada.
No método keyTyped() a variável teclaTyped obtém a tecla que foi pressionada, através do
getKeyChar(), lembrando que apenas teclas que não são de ação ativam esse método. A variável
entrouPressed é setada para false para indicar a entrada no keyTyped(). Ao final, é mostrada
a tecla que foi pressionada. Tudo isso somente é feito se não tiver sido pressionada uma
combinação de teclas anteriormente, controlada pela variável combinação.
Adicionalmente, existe ainda o método isActionKey(), que retorna true se a tecla pressionada
for uma tecla de ação e false caso contrário.
74
private JDesktopPane DPane;
private JPopupMenu Menu;
private JButton abreFrameUm;
private JButton abreFrameDois;
private JButton sair;
private JInternalFrame IFrameUm;
private JInternalFrame IFrameDois;
public AplicacaoMDI()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(500,400);
setLocation(100,50);
setTitle("Aplicação MDI com Barra de Ferramentas e Menu Flutuante");
//criação do menu
JMenuBar BarraMenu = new JMenuBar();
setJMenuBar(BarraMenu);
JMenu menuArquivo = new JMenu("Arquivo");
menuArquivo.setMnemonic('A');
JMenuItem itemAbrirUm = new JMenuItem("Abrir Frame Interno Um...",
new ImageIcon("EstrelaUm.gif"));
itemAbrirUm.setMnemonic('U');
JMenuItem itemAbrirDois= new JMenuItem("Abrir Frame Interno Dois...",
new ImageIcon("EstrelaDois.gif"));
itemAbrirDois.setMnemonic('D');
JMenuItem itemSair= new JMenuItem("Sair",
new ImageIcon("Sair.gif"));
itemSair.setMnemonic('r');
itemSair.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
InputEvent.ALT_MASK));;
menuArquivo.add(itemAbrirUm);
menuArquivo.add(itemAbrirDois);
menuArquivo.addSeparator();
menuArquivo.add(itemSair);
BarraMenu.add(menuArquivo);
itemAbrirUm.addActionListener(this);
itemAbrirDois.addActionListener(this);
itemSair.addActionListener(this);
//criação da barra de ferramentas
JToolBar barra = new JToolBar();
abreFrameUm = new JButton(new ImageIcon("EstrelaUm.gif"));
abreFrameUm.setToolTipText("Abre o Frame Interno Um");
abreFrameDois = new JButton(new ImageIcon("EstrelaDois.gif"));
abreFrameDois.setToolTipText("Abre o Frame Interno Dois");
sair = new JButton(new ImageIcon("Sair.gif"));
sair.setToolTipText("Encerra a aplicação");
barra.add(abreFrameUm);
barra.add(abreFrameDois);
barra.addSeparator();
barra.add(sair);
abreFrameUm.addActionListener(this);
abreFrameDois.addActionListener(this);
sair.addActionListener(this);
Container P = getContentPane();
P.setLayout(new BorderLayout());
P.add(barra,"North");
75
// criação da área para inserção de frames internos
DPane = new JDesktopPane();
DPane.putClientProperty("JDesktopPane.dragMode", "outline");
P.add(DPane,"Center");
}
76
Menu.show(e.getComponent(), e.getX(), e.getY());
}
});
Container C = IFrameUm.getContentPane();
C.setLayout(new BorderLayout());
C.add(BotaoFechar,"South");
DPane.add(IFrameUm);
try {
IFrameUm.setSelected(true);
}
catch (PropertyVetoException exc) { }
}
else if (item == "Abrir Frame Interno Dois..." || origem == abreFrameDois)
{
IFrameDois = new JInternalFrame("Frame Interno Dois",
false, true, false, false);
IFrameDois.setSize(250,150);
IFrameDois.setLocation(150,150);
IFrameDois.setFrameIcon(new ImageIcon("EstrelaDois.gif"));
IFrameDois.setVisible(true);
JButton BotaoFechar = new JButton("Fechar");
BotaoFechar.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
IFrameDois.setClosed(true);
}
catch (PropertyVetoException exc) { }
}
});
Container C = IFrameDois.getContentPane();
C.setLayout(new BorderLayout());
C.add(BotaoFechar,"South");
DPane.add(IFrameDois);
try {
IFrameDois.setSelected(true);
}
catch (PropertyVetoException exc) { }
}
else if (item == "Sair" || origem == sair)
System.exit(0);
}
77
Figura 3.20. Aplicação MDI – Barra de Menu
A primeira parte do exemplo mostra a criação da barra de menu do frame principal, já adiantando
que os frames internos também podem conter barras de menu individuais, o que não é o caso do
exemplo. A barra de menu BarraMenu, objeto da classe JMenuBar, é definida como barra de
menu do frame principal através do setJMenuBar(), e é criado um único menu nessa barra, o
menuArquivo, onde são adicionados os itens de menu apresentados na figura 3.20. O processo de
criação dos itens de menu segue o já visto em seções anteriores.
Após, a barra de ferramentas mostrada na figura 3.21 é criada, e isso é feito de maneira simples, a
partir do objeto barra, da classe JToolBar. Ao criar esse objeto, todas as características
referentes a uma barra de ferramentas são assimiladas, sendo necessário apenas inserir botões
com imagens através do método add(). O tamanho de cada botão é proporcional ao tamanho da
imagem e cada um dos botões vai ter um comportamento normal, sendo necessário adicionar um
ouvinte de eventos (addActionListener()) a eles para virem a executar ações posteriormente.
Na figura, também é possível verificar a existência de uma dica de ferramenta, que aparece
quando o cursor é posicionado sobre um componente, para o botão sair, inserido em cada botão
a partir do método setToolTipText(). É bom lembrar que qualquer componente que possui
como superclasse a classe JComponent pode possuir uma dica de ferramenta. O separador
existente entre os dois primeiros botões e o último foi adicionado pelo método addSeparator().
Ao final, o objeto barra é incluído na parte norte do frame.
78
Figura 3.22. Aplicação MDI – Mobilidade da Barra de Ferramentas
Entre as características particulares de uma barra de ferramentas, uma que se destaca é a que está
sendo mostrada na figura 3.22, caracterizada pela sua mobilidade. A barra de ferramentas pode
ser arrastada para qualquer uma das bordas do frame, ou ainda pode ser destacada do frame,
sendo criado um frame específico para ela. Nesse caso, se esse frame for fechado, a barra volta ao
seu lugar de origem.
79
Figura 3.23. Aplicação MDI – Frames Internos
Para que seja inserida a capacidade de receber frames internos, como mostra a figura 3.23,
criando assim uma aplicação MDI, é necessário adicionar ao contêiner um objeto da classe
JDesktopPane(). Foi isso que ocorreu na criação do objeto DPane, que, ao ser adicionado ao
contêiner, tornou possível a criação de frames internos.
80
Como todos os parâmetro foram passados como true, o frame incorporou todas as
funcionalidades permitidas a ele. Após, como qualquer outro frame, ele foi configurado através
de alguns métodos:
Para esse frame interno, e apenas esse, foi criado um menu flutuante a partir do objeto Menu, da
classe JPopupMenu (figura 3.24). Cada item de menu é criado e adicionado ao menu flutuante da
81
mesma maneira que ocorre em um menu normal. No exemplo, não foi criado nenhum menu
muito elaborado, tendo apenas dois itens: itemTitulo e itemFechar. O primeiro tem como ação
a alteração do título do frame pelo setTitle() a partir do retorno do que for digitado na caixa de
diálogo de entrada interna showInternalInputDialog(). Normalmente, quando se utilizam
frames internos, também são usadas caixas de diálogo internas. Elas são iguais às normais, mas,
além do nome, que recebe o termo Internal, permitem criar caixas de diálogo com as mesmas
características dos frames internos, não sendo frames modais e possuem atuação dentro da área
definida pelo frame principal.
No ato de fechar a caixa de diálogo, definindo o novo título, o frameUm não volta a ficar
selecionado. Para isso, foi utilizado o método setSelected(), necessitando também do
tratamento da exceção PropertyVetoException, pois pode ser que haja alguma rejeição nessa
ação.
Por fim, é criado um contêiner dentro do frame IFrameUm para receber o botão na parte inferior, o
frame é adicionado ao DPane, área destinada a receber os frames internos e é utilizado o
setSelected() para selecionar o frame.
Ainda no actionPerformed(), caso o item do menu selecionado for o Abrir Frame Interno
Dois... ou se for clicado o segundo botão da barra de ferramentas, será criado o segundo frame
interno (objeto IFrameDois). Os procedimentos de criação e configuração são os mesmos, mas
esse frame é mais simples, possuindo o botão fechar e não possuindo o menu flutuante. Também
foi setado para false as opções de redimensionar, minimizar e maximizar.
Por fim, se o item do menu selecionado for o Sair ou se for clicado o terceiro botão da barra de
ferramentas, a aplicação será finalizada, não interessando se existem frames internos abertos ou
não.
82
principal, como acontece com os frames internos. O exemplo a seguir ilustra essa situação, com a
criação de dois frames a partir de dois botões localizados no frame principal.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public VariosFrames()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(300,200);
setLocation(150,150);
setTitle("Criando Frames");
JPanel painelVF = new JPanel();
abreFrameUm = new JButton("Criar Frame Um");
abreFrameDois = new JButton("Criar Frame Dois");
painelVF.add(abreFrameUm);
painelVF.add(abreFrameDois);
abreFrameUm.addActionListener(this);
abreFrameDois.addActionListener(this);
Container P = getContentPane();
P.add(painelVF);
}
83
}
}
public FrameUm()
{
setSize(200,100);
setLocation(50,230);
setTitle("Frame Um");
JPanel painelFUm = new JPanel();
painelFUm.setLayout(new BorderLayout());
Fecha = new JButton("Fechar");
painelFUm.add(Fecha,"South");
Fecha.addActionListener(this);
Container P = getContentPane();
P.add(painelFUm);
}
Os dois frames criados tem o mesmo aspecto (figura 3.25), com posicionamento diferente, mas a
criação de cada um é diferente. Em primeiro lugar, no frame principal, foram inseridos dois
botões no painel painelVF: abreFrameUm e abreFrameDois. O tratamento do evento de clicar do
84
primeiro botão simplesmente cria uma instância da classe FrameUm, chamada frame, e mostra
através do show().
A classe FrameUm é um frame normal, que possui, em seu construtor, a definição do tamanho,
localização e título, inserção de um painel com um botão que, ao ser clicado, executa o método
dispose() para finalizar o frame.
3.13 Tabelas
Existem aplicações que necessitam apresentar dados na forma de tabelas, como é o caso de
aplicações com banco de dados. Em Java, a classe JTable é a responsável pela tarefa de
tratamento de dados em tabelas, permitindo a manipulação de linhas e colunas. As tabelas criadas
a partir dessa classe são extremamente poderosas, possuindo muitos recursos para seu manuseio.
Apesar da complexidade, é relativamente fácil criar uma tabela funcional, com um
comportamento pré-definido, como mostra o exemplo a seguir, que cria uma tabela simples.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public TabelaFormaUm()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize(500,200);
setLocation(100,50);
setTitle("Tabela - Forma Um");
Container P = getContentPane();
P.setLayout(new BorderLayout());
// criação da tabela
String[] colunas = new String []{"Referência", "Descrição", "Estoque"};
Object[][] linhas = new Object [][] {
{"01.015", "Televisor 15 polegadas", new Float(50)},
{"03.098", "Geladeira 300 litros", new Float(30)},
{"14.055", "Forno microondas", new Float(15)},
{"08.078", "DVD portátil", new Float(85)},
{"05.150", "Freezer vertical", new Float(25)},
{"10.004", "Aparelho de Som 300W", new Float(60)}};
JTable tabela = new JTable(linhas, colunas);
JScrollPane rolagemTabela = new JScrollPane(tabela);
85
P.add(rolagemTabela,"Center");
// criação do painel de baixo
JPanel pBaixo = new JPanel();
BSair = new JButton("Sair");
pBaixo.add(BSair);
P.add(pBaixo,"South");
BSair.addActionListener(this);
}
A execução do exemplo apresenta a tabela da figura 3.26. A criação dela foi baseada em um
arranjo bidimensional, e não em um modelo de tabela, como é o usual e mais indicado, visto no
exemplo posterior. Os nomes das colunas foram definidos em um arranjo String chamado
colunas. Os dados da tabela são armazenados em um arranjo bidimensional do tipo Object
chamado linhas. O arranjo é do tipo Object pelo fato de que é possível ter muitos tipos de
objeto em uma coluna, como um JComboBox, por exemplo.
Após definir os arranjos, base da construção da tabela, esta é criada com a passagem dos
parâmetros linhas e colunas, sendo depois inserida em um JScrollPane, para perimitir a
existência de barras de rolagem, e este, por fim, sendo inserido no contêiner.
No painel de baixo é inserido o botão BSair no painel pBaixo, que possui a tarefa de finalizar a
aplicação.
86
Na execução, algumas características são pré-definidas, como:
• permissão para digitação dos dados, sendo que, se o valor não couber na célula,
reticências (...) são apresentadas, indicando essa situação.
• troca de colunas, onde uma coluna pode ser trocada com outra através do ato de arrastar-
soltar, com o mouse posicionado no cabeçalho da coluna desejada.
public TabelaFormaDois()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setTitle("Tabela - Forma Dois");
setSize(430,250);
setLocation(100,50);
Container P = getContentPane();
P.setLayout(new BorderLayout());
87
String[] tipos = {"Sim","Não"};
JComboBox cbAtivo = new JComboBox(tipos);
tabela = new JTable();
tabela.setModel(new DefaultTableModel(
new Object [][] { },
new String [] {
"ID", "Nome", "Sobrenome", "Limite", "Ativo"
}
));
tabela.getColumnModel().getColumn(0).setPreferredWidth(20);
tabela.getColumnModel().getColumn(0).setResizable(false);
tabela.getColumnModel().getColumn(1).setPreferredWidth(150);
tabela.getColumnModel().getColumn(1).setResizable(true);
tabela.getColumnModel().getColumn(2).setPreferredWidth(150);
tabela.getColumnModel().getColumn(2).setResizable(true);
tabela.getColumnModel().getColumn(3).setPreferredWidth(60);
tabela.getColumnModel().getColumn(3).setResizable(true);
tabela.getColumn(tabela.getColumnName(4)).setCellEditor
(new DefaultCellEditor(cbAtivo));
tabela.getColumnModel().getColumn(4).setPreferredWidth(50);
tabela.getColumnModel().getColumn(4).setResizable(true);
tabela.getTableHeader().setReorderingAllowed(false);
tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane rolagemTabela = new JScrollPane(tabela);
P.add(rolagemTabela,"Center");
// criação do Painel de baixo
JPanel PTabSul = new JPanel();
btnIncluir = new JButton("Incluir");
PTabSul.add(btnIncluir);
btnExcluir = new JButton("Excluir");
PTabSul.add(btnExcluir);
btnMostrar = new JButton("Mostrar");
PTabSul.add(btnMostrar);
texto = new JTextField("Nome Selecionado");
PTabSul.add(texto);
P.add(PTabSul, "South");
btnExcluir.addActionListener(this);
btnIncluir.addActionListener(this);
btnMostrar.addActionListener(this);
}
88
int linhas[] = tabela.getSelectedRows();
DefaultTableModel dtm = (DefaultTableModel)tabela.getModel();
for(int i = (linhas.length - 1); i >= 0; i--)
dtm.removeRow(linhas[i]);
}
if (origem == btnMostrar)
{
if (tabela.getSelectedRow()>=0)
texto.setText(tabela.getValueAt
(tabela.getSelectedRow(),1).toString());
}
}
A figura 3.26 apresenta o resultado da execução após clicar em alguns botões. A tabela foi criada
normalmente, baseada no JTable. Após isso, foi setado o modelo pelo método setModel(), cujo
parâmetro é a criação de um objeto DefaultTableModel, iniciando com um arranjo
bidimensional vazio e um arranjo String com os nomes das colunas. Nenhum dado é
apresentado inicialmente porque isso é uma tarefa do botão Incluir.
Para cada coluna foi configurado o seu tamanho, a partir do método setPreferredWidth() e se
é redimensinável ou não, a partir do método setResizable(). A coluna Ativo é diferente das
demais, pois apresenta um caixa de seleção. Para que isso seja possível, foi definido um objeto
cbAtivo, do tipo JComboBox, que, posteriormente, foi inserido na tabela a partir do método
setCellEditor().
89
• AUTO_RESIZE_NEXT_COLUMN: redimensiona apenas a próxima coluna.
O painel de baixo contém três botões e uma caixa de texto. O primeiro botão, Incluir, ao ser
clicado, utiliza o método getModel() para criar o objeto dtm, do tipo DefaultTableModel. Tal
objeto possui o método addRow(), que é usado para inserir uma linha na tabela, sempre com os
mesmos campos, apenas mudando a numeração, controlada pela variável inteira incCod. O
segundo botão, Excluir, também cria um objeto dtm, além de utilizar o getSelectedRows()
para alimentar o arranjo int linhas com as linhas selecionadas. Um for percorrendo as linhas
selecionadas foi feito para excluí-las a partir do método removeRow(). Por fim, o terceiro botão,
Mostrar, mostra na caixa de texto o conteúdo da célula 1 (Nome) da linha selecionada
(getSelectedRow()). Isso é capturado a partir do método getValueAt().
3.13.2 Modelo AbstractTableModel
A classe DefaultTableModel é uma classe com métodos básicos para trabalhar com os dados da
JTable. Uma opção mais avançada é criar uma classe própria, estendendo a classe
AbstractTableModel, que fornece diversos métodos prontos, exceto:
• public Object getValueAt(int row, int col): retorna o objeto contido na célula
determinado por row e col.
90
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public TabelaFormaTres()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setTitle("Tabela - Forma Três");
setSize(600,250);
setLocation(100,50);
Container P = getContentPane();
P.setLayout(new BorderLayout());
// criação de um arranjo sem tamanho definido para inserção
// dinâmica de objetos
ArrayList dados = new ArrayList();
// criação de um arranjo para os títulos no cabeçalho
String[] colunas = new String[] { "ID", "Nome", "Sobrenome",
"Limite", "Ativo" };
// criação de um arranjo para identificar se a célula é editável ou não
boolean[] edicao = {false, true, true, false, true};
// Inserção da primeira linha da tabela
dados.add(new Object[]{
new Integer(++incCod),
"Cliente " + incCod,
"Endereço " + incCod,
new Double(999.99),
new Boolean(true)
});
// criação da tabela baseada no modelo ModeloTabela
modelo = new ModeloTabela(dados, colunas, edicao);
tabela = new JTable(modelo);
tabela.getColumnModel().getColumn(0).setPreferredWidth(50);
tabela.getColumnModel().getColumn(0).setResizable(false);
tabela.getColumnModel().getColumn(1).setPreferredWidth(200);
tabela.getColumnModel().getColumn(1).setResizable(true);
tabela.getColumnModel().getColumn(2).setPreferredWidth(200);
tabela.getColumnModel().getColumn(2).setResizable(true);
tabela.getColumnModel().getColumn(3).setPreferredWidth(80);
tabela.getColumnModel().getColumn(3).setResizable(true);
tabela.getColumnModel().getColumn(4).setPreferredWidth(55);
tabela.getColumnModel().getColumn(4).setResizable(true);
tabela.getTableHeader().setReorderingAllowed(false);
tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tabela.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
91
JScrollPane rolagemTabela = new JScrollPane(tabela);
P.add(rolagemTabela,"Center");
// criação do Painel de baixo
JPanel PTabSul = new JPanel();
btnIncluir = new JButton("Incluir");
PTabSul.add(btnIncluir);
btnExcluir = new JButton("Excluir");
PTabSul.add(btnExcluir);
btnMostrar = new JButton("Mostrar");
PTabSul.add(btnMostrar);
btnAlterar = new JButton("Alterar");
PTabSul.add(btnAlterar);
btnMostrarClasse = new JButton("Classe");
PTabSul.add(btnMostrarClasse);
texto = new JTextField(15);
PTabSul.add(texto);
P.add(PTabSul, "South");
btnExcluir.addActionListener(this);
btnIncluir.addActionListener(this);
btnMostrar.addActionListener(this);
btnAlterar.addActionListener(this);
btnMostrarClasse.addActionListener(this);
}
92
tabela.getSelectedColumn()).toString());
}
}
93
}
94
Figura 3.28. Uma tabela baseada no modelo criado a partir do AbstractTableModel
Dois outros arranjos são criados: colunas, do tipo String, que armazena o nome das colunas, a
ser mostrado no cabeçalho da tabela e; colEditavel, do tipo boolean, que armazena true ou
false, conforme a coluna possa ser editável ou não.
Os primeiros quatro métodos realizam o tratamento dos dados dos arranjos linhas e colunas. São
eles:
O contrutor da classe recebe três parâmetros: um ArrayList, para iniciar a tabela com as linhas
desejadas; um arranjo String, que são os nomes das colunas, e; um arranjo boolean, com a
indicação da possibilidade de edição de cada uma das colunas. No momento da instanciação em
alguma aplicação, esses dados devem ser passados para que a tabela tenha uma situação inicial.
Como explicado anteriormente, os nomes das colunas não seriam atribuídos se não fosse
sobreposto o método getColumnName(), que retorna exatamente o conteúdo atribuído ao arranjo
colunas. Além disso, os dois métodos obrigatórios getRowCount()e getColumnCount() são
implementados, retornando o número de linhas e colunas do modelo.
Os demais métodos implementados são:
95
• public boolean isCellEditable(int numCol): retorna true se a coluna numCol for
editável, e false, caso contrário.
A criação da tabela baseada nesse modelo, que resulta na aplicação mostrada na figura 3.28, é
feita na classe TabelaFormaTres. O ArrayList dados é criado e é adicionado a ele apenas uma
única linha, que é um arranjo de vários objetos de tipos diferentes. Além de dados, o arranjo
colunas é criado e alimentado com os nomes das colunas da tabela; e o arranjo edicao é criado
com a indicação se cada coluna é editável ou não.
Tais arranjos são passados como parâmetro na criação do objeto da classe ModeloTabela,
explicado anteriormente, chamado modelo, e este serve como parâmetro na criação da JTable.
Após, como no exemplo anterior, são definidos os tamanhos de cada coluna
(setPreferredWidth()), e se elas são redimensionáveis ou não (setResizable()). Também
igualmente ao exemplo anterior, as colunas deixam de ser reorganizáveis, a partir do método
setReorderingAllowed(), setado para false, e é configurado o modo de redimensionamento
automático das colunas da tabela, a partir do método setAutoResizeMode().
• Incluir: utiliza o método addRow() do modelo para incluir uma nova linha no final da
tabela.
96
• Excluir: utiliza o método removeRow() do modelo para excluir a linha que está
selecionada, capturada a partir do método getSelectedRow().
• Mostrar: mostra o conteúdo da célula no campo texto, caso haja uma linha selecionada.
Isso é feito pelo método getValueAt(), passando como parâmetro o número da linha
(getSelectedRow()) e coluna (getSelectedColumn()) referente à célula selecionada.
public CriaTabelas()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setTitle("Wizard para criação de tabelas de BD");
setSize(500,320);
setLocation(100,100);
Container P = getContentPane();
P.setLayout(new BorderLayout());
campos = new Vector();
97
// criação do primeiro painel
JPanel PNorte = new JPanel();
PNorte.setLayout(new BorderLayout());
JPanel PNorteNorte = new JPanel();
PNorteNorte.add(new JLabel("Fonte de Dados"));
fonteDados = new JTextField(13);
PNorteNorte.add(fonteDados);
PNorteNorte.add(new JLabel("Usuário"));
usuario = new JTextField(7);
PNorteNorte.add(usuario);
PNorteNorte.add(new JLabel("Senha"));
senha = new JPasswordField(5);
PNorteNorte.add(senha);
PNorte.add(PNorteNorte,"North");
JPanel PNorteCentro = new JPanel();
btnConectar = new JButton("Conectar Banco");
btnConectar.addActionListener(this);
PNorteCentro.add(btnConectar);
lblCon = new JLabel("Não Conectado");
PNorteCentro.add(lblCon);
btnDesconectar = new JButton("Desconectar Banco");
btnDesconectar.addActionListener(this);
PNorteCentro.add(btnDesconectar);
PNorte.add(PNorteCentro,"Center");
P.add(PNorte, "North");
// criação do segundo painel
JPanel PCentro = new JPanel();
PCentro.add(new JLabel("Nome da Tabela"));
nomeTabela = new JTextField(10);
PCentro.add(nomeTabela);
lista = new JList();
lista.setVisibleRowCount(8);
lista.setFixedCellWidth(200);
lista.setFixedCellHeight(15);
lista.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
PCentro.add(new JScrollPane(lista));
btnCriar = new JButton("Criar Tabela");
btnCriar.addActionListener(this);
PCentro.add(btnCriar);
btnLimpar = new JButton("Limpar lista");
btnLimpar.addActionListener(this);
PCentro.add(btnLimpar);
Border borda = BorderFactory.createEtchedBorder();
PCentro.setBorder(borda);
P.add(PCentro, "Center");
// criação do terceiro painel
JPanel PSul = new JPanel();
PSul.add(new JLabel("Nome"));
nomeCampo = new JTextField(10);
PSul.add(nomeCampo);
PSul.add(new JLabel("Tipo"));
tipoCampo = new JTextField(10);
PSul.add(tipoCampo);
btnIncluir = new JButton("Incluir");
PSul.add(btnIncluir);
btnExcluir = new JButton("Excluir");
PSul.add(btnExcluir);
98
P.add(PSul, "South");
btnExcluir.addActionListener(this);
btnIncluir.addActionListener(this);
}
99
"Mensagem", JOptionPane.WARNING_MESSAGE);
chavePrimaria = nomeCampo.getText();
}
campos.addElement(item);
lista.setListData(campos);
}
if (origem == btnExcluir)
{
if (lista.getSelectedIndex()>= 0)
{
campos.removeElementAt(lista.getSelectedIndex());
lista.setListData(campos);
}
}
if (origem == btnLimpar)
{
campos.removeAllElements();
lista.setListData(campos);
}
if (origem == btnCriar)
{
String itens = campos.toString();
itens = itens.substring(1,itens.length()-1);
String sentencaSQL = "CREATE TABLE " +
nomeTabela.getText().trim() + " (" + itens +
", PRIMARY KEY (" + chavePrimaria + "))" ;
try{
Statement st = con.createStatement();
st.executeUpdate(sentencaSQL);
JOptionPane.showMessageDialog(this,
"Tabela criada com sucesso!",
"Mensagem", JOptionPane.WARNING_MESSAGE);
}catch (SQLException eSQL) {
eSQL.printStackTrace();
JOptionPane.showMessageDialog(this,
"Não foi possível criar a tabela!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
}
}
100
A
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.*;
import javax.swing.table.*;
public Consulta()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setTitle("Consulta a Banco de Dados");
setSize(500,320);
setLocation(100,100);
Container P = getContentPane();
P.setLayout(new BorderLayout());
// conecta o banco
con = conectaBanco("jdbc:odbc:ODBCBancoExemplo", null, null);
// criação do primeiro painel
JPanel PNorte = new JPanel();
101
PNorte.setLayout(new BorderLayout());
JPanel PNorteNorte = new JPanel();
PNorteNorte.add(new JLabel("Digite nome"));
nome = new JTextField(13);
PNorteNorte.add(nome);
btnPesqNome = new JButton("Pesquisar por nome");
PNorteNorte.add(btnPesqNome);
btnPesqNome.addActionListener(this);
PNorte.add(PNorteNorte,"North");
JPanel PNorteCentro = new JPanel();
PNorteCentro.add(new JLabel("Digite código"));
codigo = new JTextField(7);
PNorteCentro.add(codigo);
btnPesqCod = new JButton("Pesquisar por código");
PNorteCentro.add(btnPesqCod);
PNorte.add(PNorteCentro,"Center");
btnPesqCod.addActionListener(this);
P.add(PNorte, "North");
// criação da tabela
// criação de um array para inserção dinâmica de objetos
ArrayList dados = new ArrayList();
// criação de um array para os títulos no cabeçalho
String[] colunas = new String[] { "Código", "Nome", "Endereço"};
// criação de um array para identificar se a célula é editável ou não
boolean[] edicao = {false, false, false};
// seleciona todos os registros da tabela Clientes e joga no ArrayList
try {
String sentencaSQL = "SELECT * FROM Clientes ORDER BY Codigo";
sentenca = con.createStatement();
registros = sentenca.executeQuery(sentencaSQL);
boolean proximoRegistro = registros.next();
if (!proximoRegistro)
{
JOptionPane.showMessageDialog(this,
"Nenhum registro foi encontrado!",
"Mensagem", JOptionPane.WARNING_MESSAGE);
}
else
do {
dados.add(new Object[]{
new Integer(Integer.parseInt(registros.getString("Codigo"))),
registros.getString("Nome"),
registros.getString("Endereco")
});
} while (registros.next());
sentenca.close();
}catch (SQLException eSQL) {
eSQL.printStackTrace();
JOptionPane.showMessageDialog(this,
"Não foi possível carregar os dados!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
// criação da tabela baseada no modelo ModeloTabelaBD
modelo = new ModeloTabelaBD(dados, colunas, edicao);
tabela = new JTable(modelo);
tabela.getColumnModel().getColumn(0).setPreferredWidth(50);
102
tabela.getColumnModel().getColumn(0).setResizable(false);
tabela.getColumnModel().getColumn(1).setPreferredWidth(200);
tabela.getColumnModel().getColumn(1).setResizable(true);
tabela.getColumnModel().getColumn(2).setPreferredWidth(240);
tabela.getColumnModel().getColumn(2).setResizable(true);
tabela.getTableHeader().setReorderingAllowed(false);
tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tabela.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane rolagemTabela = new JScrollPane(tabela);
P.add(rolagemTabela, "Center");
// criação do terceiro painel
JPanel PSul = new JPanel();
btnSair = new JButton("Sair");
PSul.add(btnSair);
P.add(PSul, "South");
btnSair.addActionListener(this);
}
103
{
JOptionPane.showMessageDialog(this,
"Nenhum registro foi encontrado!",
"Mensagem", JOptionPane.WARNING_MESSAGE);
}
else
do {
modelo.addRow(new Object[]{
new Integer(Integer.parseInt(registros.getString("Codigo"))),
registros.getString("Nome"),
registros.getString("Endereco")
});
} while (registros.next());
sentenca.close();
}catch (SQLException eSQL) {
eSQL.printStackTrace();
JOptionPane.showMessageDialog(this,
"Não foi possível carregar os dados!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
}
104
private String[] colunas = null;
private boolean[] colEditavel;
105
{
if (isCellEditable(numCol))
{
Object[] linha = (Object[])getLinhas().get(numLin);
linha[numCol] = dado;
fireTableDataChanged();
}
}
import javax.swing.*;
import java.awt.*;
106
import java.awt.event.*;
import java.sql.*;
import java.util.*;
import javax.swing.table.*;
public Cadastro()
{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setTitle("Consulta a Banco de Dados");
setSize(500,320);
setLocation(100,100);
Container P = getContentPane();
P.setLayout(new BorderLayout());
// conecta o banco
con = conectaBanco("jdbc:odbc:ODBCBancoExemplo", null, null);
// criação do primeiro painel
JPanel PNorte = new JPanel();
PNorte.setLayout(new FlowLayout());
PNorte.add(new JLabel("Digite nome"));
nome = new JTextField(13);
PNorte.add(nome);
btnPesqNome = new JButton("Pesquisar");
PNorte.add(btnPesqNome);
btnPesqNome.addActionListener(this);
P.add(PNorte, "North");
// criação da tabela
// criação de um array para inserção dinâmica de objetos
ArrayList dados = new ArrayList();
// criação de um array para os títulos no cabeçalho
String[] colunas = new String[] { "Código", "Nome", "Endereço"};
// criação de um array para identificar se a célula é editável ou não
boolean[] edicao = {false, false, false};
// criação da tabela baseada no modelo ModeloTabelaBD
modelo = new ModeloTabelaBD(dados, colunas, edicao);
tabela = new JTable(modelo);
tabela.getColumnModel().getColumn(0).setPreferredWidth(50);
tabela.getColumnModel().getColumn(0).setResizable(false);
tabela.getColumnModel().getColumn(1).setPreferredWidth(200);
tabela.getColumnModel().getColumn(1).setResizable(true);
tabela.getColumnModel().getColumn(2).setPreferredWidth(240);
tabela.getColumnModel().getColumn(2).setResizable(true);
tabela.getTableHeader().setReorderingAllowed(false);
107
tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tabela.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane rolagemTabela = new JScrollPane(tabela);
P.add(rolagemTabela, "Center");
// criação do terceiro painel
JPanel PSul = new JPanel();
btnIncluir = new JButton("Incluir");
btnAlterar = new JButton("Alterar");
btnExcluir = new JButton("Excluir");
btnSair = new JButton("Sair");
PSul.add(btnIncluir);
PSul.add(btnAlterar);
PSul.add(btnExcluir);
PSul.add(btnSair);
P.add(PSul, "South");
btnIncluir.addActionListener(this);
btnAlterar.addActionListener(this);
btnExcluir.addActionListener(this);
btnSair.addActionListener(this);
}
108
String sentencaSQL ="DELETE FROM Clientes WHERE Codigo= " +
modelo.getValueAt(tabela.getSelectedRow(),0).toString();
sentenca.executeUpdate(sentencaSQL);
sentenca.close();
Selecao("SELECT * FROM Clientes WHERE NOME LIKE '%" +
nome.getText() + "%' ORDER BY NOME");
}
}catch (SQLException eSQL) {
eSQL.printStackTrace();
JOptionPane.showMessageDialog(this,
"Não foi possível realizar a operação!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
}
if (origem == btnSair)
{
try {
con.close();
System.exit(0);
}catch (SQLException eSQL) {
// exceções de SQL
eSQL.printStackTrace();
JOptionPane.showMessageDialog(this,
"Não foi possível desconectar o banco!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
}
}
109
JOptionPane.showMessageDialog(this,
"Não foi possível carregar os dados!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
}
110
painelFC.setLayout(new FlowLayout());
painelFC.add(new JLabel("Código"));
txtCodigo = new JTextField(15);
txtCodigo.setText(Cod);
if (Tipo == 'A')
{
txtCodigo.setEditable(false);
setTitle("Alteração");
}
else
setTitle("Inclusão");
painelFC.add(txtCodigo);
painelFC.add(new JLabel("Nome"));
txtNome = new JTextField(15);
txtNome.setText(Nome);
painelFC.add(txtNome);
painelFC.add(new JLabel("Endereço"));
txtEndereco = new JTextField(15);
txtEndereco.setText(Endereco);
painelFC.add(txtEndereco);
OK = new JButton("OK");
Cancelar = new JButton("Cancelar");
painelFC.add(OK);
painelFC.add(Cancelar);
OK.addActionListener(this);
Cancelar.addActionListener(this);
P.add(painelFC,"Center");
}
111
sentenca.executeUpdate(sentencaSQL);
sentenca.close();
dispose();
}catch (SQLException eSQL) {
eSQL.printStackTrace();
JOptionPane.showMessageDialog(this,
"Não foi possível realizar a operação!\n" +
"Mensagem: " + eSQL.getMessage(),
"Erro", JOptionPane.ERROR_MESSAGE);
}
}
}
if (evt.getSource() == Cancelar)
{
dispose();
}
}
}
D
D
D
d
3. AWT Avançado
Imagens e desenhos mais complexos não podem ser feitos a partir da classe Graphics. É
necessário utilizar pacotes existentes na API Java 2D, que permite produzir desenhos de mais alta
qualidade.
112
3.14 Java 2D
O Java 2D apresenta pacotes de classes com métodos para desenhos gráficos com um nível maior
de complexidade. Alguns desses pacotes: java.awt.image, java.awt.geom, java.awt.print,
java.awt.Graphics2D. Com o Java 2D é possível produzir uma variedade maior de figuras
geométricas, com padrões diferentes de preenchimento, além de ter controle sobre os desenhos
criados, podendo move-los, gira-los ou alonga-los.
3.15 Imagens
A classe Image é a responsável pelo carregamento de imagens armazenadas em disco. Novam
d
113
Bibliografia
Sites de Interesse
www.java.sun.com - Site ofical do Java.
www.javafree.com.br - Comunidade de desenvolvedores Java.
www.portaljava.com.br - Comunidade de desenvolvedores Java.
114