114
1 Programação JAVA 1. Programação Visual Básica A Interface Gráfica com o Usuário, também conhecido como GUI - Graphical User Interface, em Java, é feita através de bibliotecas de classes, sendo que a primeira a surgir foi a AWT (Abstract Window Toolkit). A AWT surgiu já na versão 1.0, mas se tornou confiável a partir da versão 1.1. A maneira como as classes dessa biblioteca trabalham garante a criação dos elementos da interface de usuário seguindo o comportamento destinado às ferramentas GUI nativas de cada plataforma (Windows, Mac, Solaris, ...). Alguns exemplos destes elementos são: botões, listas, menus, componentes de textos, containers (janelas e barras de menus), caixas de diálogo para abrir ou salvar arquivos, além de elementos para manipulação de imagens, fontes e cores. A portabilidade de plataforma funcionava bem em aplicações simples, mas aplicações que envolviam elementos mais complexos, como menus e barras de rolagem, por exemplo, apresentavam diferenças de comportamento conforme a plataforma. O que aconteceu foi que as aplicações visuais feitas em Java não se pareciam, e nem tinham as mesmas funcionalidades, com as aplicações convencionais de cada plataforma. A partir da versão 2 do Java, a JFC (Java Foundation Classes) apresentou novos recursos para a construção da GUI das aplicações, o que melhorou muito os problemas de portabilidade. São eles: Java 2D: novas funções para desenhos e gráficos. Drag & Drop: clicar, arrastar, copiar e colar. Swing: biblioteca de classes extensão da AWT, onde são apresentados novos componentes de interface e o que é conhecido por look and feel, que é uma adaptação perfeita da GUI ao sistema operacional específico de desenvolvimento. É bom salientar que o Swing não substitui o AWT, mas é o kit de ferramentas GUI mais utilizado para desenvolvimento de aplicações visuais. O AWT continua existindo, mantendo a mesma arquitetura criada para o Java versão 1.1. O Swing possui muito mais recursos, além de garantir maior portabilidade e, em boa parte dos casos, é mais fácil de usar. Isso não significa que ou se utiliza AWT ou se utiliza Swing, normalmente o que acontece é que elementos das duas bibliotecas são utilizados conjuntamente nas aplicações. Referente a criação das aplicações, exitem muitas ferramentas que auxiliam na produção de interfaces de usuário gráficas, mas não se comparam a ferramentas para plataformas específicas,

Programação Visual em Java

Embed Size (px)

DESCRIPTION

Uma apostila bem interessante sobre programação visual com Java.

Citation preview

Page 1: Programação Visual em Java

1

Programação JAVA

1. Programação Visual Básica

A Interface Gráfica com o Usuário, também conhecido como GUI - Graphical User Interface, em Java, é feita através de bibliotecas de classes, sendo que a primeira a surgir foi a AWT (Abstract Window Toolkit). A AWT surgiu já na versão 1.0, mas se tornou confiável a partir da versão 1.1. A maneira como as classes dessa biblioteca trabalham garante a criação dos elementos da interface de usuário seguindo o comportamento destinado às ferramentas GUI nativas de cada plataforma (Windows, Mac, Solaris, ...).

Alguns exemplos destes elementos são: botões, listas, menus, componentes de textos, containers (janelas e barras de menus), caixas de diálogo para abrir ou salvar arquivos, além de elementos para manipulação de imagens, fontes e cores.

A portabilidade de plataforma funcionava bem em aplicações simples, mas aplicações que envolviam elementos mais complexos, como menus e barras de rolagem, por exemplo, apresentavam diferenças de comportamento conforme a plataforma. O que aconteceu foi que as aplicações visuais feitas em Java não se pareciam, e nem tinham as mesmas funcionalidades, com as aplicações convencionais de cada plataforma.

A partir da versão 2 do Java, a JFC (Java Foundation Classes) apresentou novos recursos para a construção da GUI das aplicações, o que melhorou muito os problemas de portabilidade. São eles:

• Java 2D: novas funções para desenhos e gráficos.

• Drag & Drop: clicar, arrastar, copiar e colar.

• Swing: biblioteca de classes extensão da AWT, onde são apresentados novos componentes de interface e o que é conhecido por look and feel, que é uma adaptação perfeita da GUI ao sistema operacional específico de desenvolvimento.

É bom salientar que o Swing não substitui o AWT, mas é o kit de ferramentas GUI mais utilizado para desenvolvimento de aplicações visuais. O AWT continua existindo, mantendo a mesma arquitetura criada para o Java versão 1.1.

O Swing possui muito mais recursos, além de garantir maior portabilidade e, em boa parte dos casos, é mais fácil de usar. Isso não significa que ou se utiliza AWT ou se utiliza Swing, normalmente o que acontece é que elementos das duas bibliotecas são utilizados conjuntamente nas aplicações.

Referente a criação das aplicações, exitem muitas ferramentas que auxiliam na produção de interfaces de usuário gráficas, mas não se comparam a ferramentas para plataformas específicas,

Page 2: Programação Visual em Java

2

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.

Para se definir um frame básico baseado em AWT, deve-se:

• Importar o pacote java.awt.* .

• Estender a classe Frame .

• Ter um método main() para criar o objeto a partir do operador new.

• Torná-lo visível.

Assim, o código a seguir resulta no frame apresentado na figura 1.1. import java.awt.*; public class FrameUm extends Frame { public static void main (String[] args) { FrameUm fr = new FrameUm(); fr.setVisible(true); } }

Para torná-lo visível, é possível utilizar fr.show(); no lugar de fr.setVisible(true); . Percebe-se que não é possível fechá-lo utilizando o botão fechar. Por enquanto, ela deve ser encerrada forçando a finalização do processo (ex.: finalizar tarefa no Windows, ou terminar processo na ferramenta específica de desenvolvimento).

Figura 1.1. Frame FrameUm

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 alt ura: 200 pixels setResizable(false); // não permite o redimensi onamento

Page 3: Programação Visual em Java

3

setLocation(200, 100); // x: 200 pixels y: 1 00 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() ).

Figura 1.2. Frame FrameDois

Além disso, o setLocation() realiza o posicionamento em tela do frame, seguindo o sistema de coordenadas do Java (figura 1.3), medidas em pixels, conforme a resolução atual da tela. No exemplo, o frame fica posicionado em 200 pixels para x e 100 pixels para y.

(0 ,0) x

y

(x, y)

Figura 1.3. Sistema de coordenadas do Java

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.*;

Page 4: Programação Visual em Java

4

import java.awt.event.*; public class FrameTres extends Frame { public FrameTres() //construtor { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Sys tem.exit(0);}}); setTitle("Frame Três"); // título do Frame setSize(300, 200); // largura: 300 pixels alt ura: 200 pixels setResizable(false); // não permite o redimensi onamento setLocation(200, 100); // x: 200 pixels y: 1 00 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){Sys tem.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 ,

Page 5: Programação Visual em Java

5

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 .

1.2 Mostrando Textos e Linhas no Frame

Para que seja possível mostrar textos em um frame é necessário criar um objeto baseado na classe Graphics , que será responsável pelo gerenciamento da área gráfica a ser desenhada, controlando cores, tipos de fontes, etc. A classe Component possui um método paint() que aceita um objeto Graphics como parâmetro. Esse método, na classe de origem, não faz nada, por isso ele deve ser sobrescrito com a chamada de métodos que realizam operações de escrita, pintura, desenho, etc. Para efetuar a sobreposição do método paint() deve-se ter o cabeçalho:

public void paint(Graphics g)

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){Syst em.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); } public void paint (Graphics g) { g.drawString("Estou escrevendo no frame", 40, 5 0); g.drawLine(40, 60, 200, 60); int i = 30; while (i < 150) {

Page 6: Programação Visual em Java

6

g.drawString("Estou escrevendo no frame", 40+ i, 50+i); g.drawLine(40+i, 60+i, 200+i, 60+i); i+=30; } } public static void main (String[] args) { MostrandoTextos fr = new MostrandoTextos(); fr.setVisible(true); } }

Figura 1.4. Frame MostrandoTextos

O método drawString(String s, int x, int y) realiza a mostragem de um texto em uma posição definida por x e y. O método drawLine(int x1, int y1, int x2, int y2) desenha uma linha que inicia nas coordenadas x1,y1 e termina nas coordenadas x2,y2 .

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 .

black (preto) magenta (magenta)

blue (azulo) orange (laranja)

cyan (ciano) pink (rosa)

darkGray (cinza-escuro) red (vermelho)

gray (cinza) white (branco)

green (verde) yellow (amarelo)

Page 7: Programação Visual em Java

7

lightGray (cinza-claro)

Tabela 1.1. Cores definidas em java.awt.Color

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){Syst em.exit(0);}}); setSize(400, 200); setLocation(200, 100); setTitle("Cores"); } public void paint (Graphics g) { g.setColor(Color.blue); g.drawString("Cor Azul", 50, 50); g.setColor(Color.green); g.drawLine(50, 60, 220, 60); g.setColor(Color.red); g.drawRect(50,70,100,30); g.setColor(new Color(0,128,128)); g.fillRect(50,110,100,30); } public static void main (String[] args) { Cores fr = new Cores(); fr.setVisible(true); } }

Figura 1.5. Frame Cores

Page 8: Programação Visual em Java

8

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){Syst em.exit(0);}}); setSize(400,130); setTitle("Tipos de Fonte"); } public void paint (Graphics g) { g.setColor(Color.blue); Font f = new Font("SansSerif", Font.ITALIC, 16) ; g.setFont(f); g.drawString("Fonte SansSerif itálico tamanho 1 6", 20, 50); g.setFont(new Font("Monospaced", Font.BOLD + Fo nt.ITALIC, 14)); g.drawString("Fonte Monospaced negrito e itálic o tamanho 14", 20, 80); g.setFont(f); g.drawString("Novamente Fonte SansSerif itálico tamanho 16", 20, 110); } public static void main (String[] args) { Fontes fr = new Fontes(); fr.setVisible(true); } }

A figura 1.6 mostra o resultado. Percebe-se que não é necessário criar explicitamente um objeto do tipo Font (objeto f ), podendo ser possível criá-lo no próprio argumento do setFont() . Se a fonte for utilizada várias vezes no decorrer da aplicação, torna-se útil a criação do objeto explicitamente.

Page 9: Programação Visual em Java

9

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 .

1.5 Outras Formas Geométricas

Além das formas já apresentadas, existem várias outras possíveis, a maioria com a opção de preenchimento ou não, a partir da precedência de draw ou fill . O exemplo a seguir tem como resultado o frame apresentado na figura 1.7. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class FormasGeometricas extends JFrame { public FormasGeometricas() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(460,140); setTitle("Formas Geométricas"); } public void paint (Graphics g) { g.setColor(Color.red); g.drawRoundRect(10,30,80,40,30,30); g.fillRoundRect(10,80,80,40,30,30); g.setColor(Color.yellow); g.draw3DRect(100,30,80,40,true); g.fill3DRect(100,80,80,40,false); g.setColor(Color.blue); g.drawOval(190,30,80,40); g.fillOval(190,80,80,40); g.setColor(Color.darkGray); g.drawArc(280,30,80,40,90,270); g.fillArc(280,80,80,40,90,270); g.setColor(Color.magenta); int ValoresX[] = {370,450,410,370}; int ValoresY[] = {30,30,70,30}; g.drawPolygon(ValoresX,ValoresY,3); int ValoresX2[] = {370,450,410,370}; int ValoresY2[] = {80,80,120,80}; g.fillPolygon(ValoresX2,ValoresY2,3);

Page 10: Programação Visual em Java

10

} public static void main (String[] args) { FormasGeometricas fr = new FormasGeometricas(); fr.setVisible(true); } }

Figura 1.7. Frame Fontes

Várias formas geométricas foram desenhadas no frame. Funcionamento de cada método:

• drawRoundRect(int x, int y, int width, int height, int arcWidth, int

arcHeight) : Desenha um retângulo com cantos arredondados, iniciando nas coordenadas x,y , tendo uma largura width e uma altura height , e cantos definidos por arcWidth e

arcHeight .

• fillRoundRect(int x, int y, int width, int height, int arcWidth, int

arcHeight) : Idem a drawRoundRect , mas preenche o retângulo.

• draw3DRect(int x, int y, int width, int height, boo lean raised) : Desenha um retângulo 3D, iniciando nas coordenadas x,y , tendo uma largura width e uma altura height , e um valor lógico para indicar a aparência do 3D.

• fill3DRect(int x, int y, int width, int height, boo lean raised) : Idem a draw3DRect , mas preenche o retângulo.

• 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.

• drawArc(int x, int y, int width, int height, int st artAngle, int

arcAngle) : Desenha um arco, baseado nas coordenadas do retângulo que inicia em x,y , tendo uma largura width e uma altura height , mostrando apenas a linha que vai do ângulo startAngle até o ângulo arcAngle .

• fillArc(int x, int y, int width, int height, int st artAngle, int

arcAngle) : Idem a drawArc , mas preenche o arco.

Page 11: Programação Visual em Java

11

• drawPolygon(int[] xPoints, int[] yPoints, int nPoin ts) : Desenha um polígono, baseado nas coordenadas dos arranjos x,y .

• fillPolygon(int[] xPoints, int[] yPoints, int nPoin ts) : Idem a drawPolygon , mas preenche o arco.

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.*; public class Imagens extends JFrame { public Imagens() //construtora { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(400,200); setTitle("Imagens"); } public void paint (Graphics g) { Image ima = Toolkit.getDefaultToolkit().getImag e("LogoJava.gif"); int larguraTela = 400; int alturaTela = 200; int larguraImagem = ima.getWidth(this); int alturaImagem = ima.getHeight(this); g.drawImage(ima,4,23,null); for (int i = 0; i <= larguraTela / larguraImage m; i++) for (int j = 0; j <= alturaTela / alturaImage m; j++) if (i + j > 0) g.copyArea(4,23,larguraImagem, alturaImag em, i * larguraImagem, j * alturaImag em); } public static void main (String[] args) { Imagens fr = new Imagens(); fr.setVisible(true); } }

Page 12: Programação Visual em Java

12

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 ob server) , 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 d x, 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.*; class Painel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); g.drawString("Estou escrevendo em um painel", 1 00, 50); } } public class EscrevendoEmPainel extends JFrame { public EscrevendoEmPainel() { addWindowListener(new WindowAdapter()

Page 13: Programação Visual em Java

13

{public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(400,130); setTitle("Painel"); Container P = getContentPane(); P.add(new Painel()); } public static void main (String[] args) { EscrevendoEmPainel fr = new EscrevendoEmPainel( ); fr.setVisible(true); } }

Figura 1.9. Contêiner do tipo 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.

1.8 Gerenciadores de Layout

Os gerenciadores de layout controlam o dimensionamento e posicionamento dos componentes dentro de contêiners, sendo que cada contêiner possui um gerenciador padrão, mas pode ser alterado através da chamada ao método setLayout() do contêiner específico. Por exemplo, o gerenciador padrão do JPanel é o FlowLayout , que coloca os componentes em um tamanho pré-definido da esquerda para a direita e de cima para baixo no contêiner. Outros gerenciadores de layout existentes: GridLayout , BorderLayout , BoxLayout e GridBagLayout .

1.8.1 Gerenciador FlowLayout

Para que seja possível verificar a diferença entre alguns deles, exemplos são demonstrados nas próximas seções, começando exatamente pelo gerenciador FlowLayout , padrão do JPanel . Nos exemplos, são definidos objetos botão a partir da classe JButton . import java.awt.*;

Page 14: Programação Visual em Java

14

import java.awt.event.*; import javax.swing.*; class PainelFlow extends JPanel { public PainelFlow() { setLayout(new FlowLayout()); add(new JButton("Um")); add(new JButton("Dois")); add(new JButton("Três")); add(new JButton("Quatro")); add(new JButton("Cinco")); } } public class GerenciadorFlowLayout extends JFrame { public GerenciadorFlowLayout() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(200,90); setLocation(150,150); setTitle("FlowLayout"); Container P = getContentPane(); P.add(new PainelFlow()); } public static void main (String[] args) { GerenciadorFlowLayout fr = new GerenciadorFlowL ayout(); fr.setVisible(true); } }

Figura 1.10. Gerenciador de Layout FlowLayout

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));

1.8.2 Gerenciador GridLayout

Page 15: Programação Visual em Java

15

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.*; class PainelGrid extends JPanel { public PainelGrid() { setLayout(new GridLayout(3,2)); add(new JButton("Um")); add(new JButton("Dois")); add(new JButton("Três")); add(new JButton("Quatro")); add(new JButton("Cinco")); } } public class GerenciadorGridLayout extends JFrame { public GerenciadorGridLayout() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(200,150); setLocation(150,150); setTitle("GridLayout"); Container P = getContentPane(); P.add(new PainelGrid()); } public static void main (String[] args) { GerenciadorGridLayout fr = new GerenciadorGridL ayout(); fr.setVisible(true); } }

Figura 1.11. Gerenciador de Layout GridLayout

O tamanho de cada componente é redimensionado automaticamente, como mostra a figura 1.11, podendo ficar espaços vazios. É necessário definir o número de linhas e colunas no

Page 16: Programação Visual em Java

16

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

Existem gerenciadores mais interessantes, como o BorderLayout , que organiza os objetos em locais determinados por NORTH, SOUTH, EAST, WEST e CENTER. Exemplo: import java.awt.*; import java.awt.event.*; import javax.swing.*; class PainelBorder extends JPanel { public PainelBorder() { setLayout(new BorderLayout()); add(new JButton("Um"),BorderLayout.NORTH); add(new JButton("Dois"),BorderLayout.SOUTH); add(new JButton("Três"),BorderLayout.EAST); add(new JButton("Quatro"),BorderLayout.WEST); add(new JButton("Cinco"),BorderLayout.CENTER); } } public class GerenciadorBorderLayout extends JFrame { public GerenciadorBorderLayout() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(300,150); setLocation(150,150); setTitle("BorderLayout"); Container P = getContentPane(); P.add(new PainelBorder()); } public static void main (String[] args) { GerenciadorBorderLayout fr = new GerenciadorBor derLayout(); fr.setVisible(true); } }

Page 17: Programação Visual em Java

17

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.*; class PainelBox extends JPanel { public PainelBox() { add(Box.createHorizontalGlue()); add(new JButton("Um")); add(Box.createHorizontalGlue()); add(new JButton("Dois")); add(Box.createHorizontalStrut(10)); add(new JButton("Três")); add(Box.createHorizontalStrut(30)); add(new JButton("Quatro")); add(Box.createHorizontalGlue()); add(new JButton("Cinco")); add(Box.createHorizontalGlue()); } } public class GerenciadorBoxLayout extends JFrame

Page 18: Programação Visual em Java

18

{ public GerenciadorBoxLayout() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(500,100); setLocation(150,150); setTitle("BoxLayout"); Container b = Box.createHorizontalBox(); getContentPane().add(b,BorderLayout.CENTER); b.add(new PainelBox()); } public static void main (String[] args) { GerenciadorBoxLayout fr = new GerenciadorBoxLay out(); fr.setVisible(true); } }

Figura 1.13. Gerenciador de Layout BoxLayout

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.

1.8.5 Gerenciador GridBagLayout

O gerenciador GridBagLayout é bastante flexível, permitindo posicionamento dos componentes em relação aos outros. Assim, é possível criar praticamente qualquer tipo de layout. Por ser mais flexível, é também mais difícil de ser utilizado. O construtor não possui argumentos e a aparência do layout é controlada pela classe GridBagConstraints . Os componentes gerenciados devem estar associados a um objeto GridBagConstraints , que possui campos, mostrados na tabela 1.1, para controle dos componentes.

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

Page 19: Programação Visual em Java

19

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.*; class PainelGridBag extends JPanel { GridBagConstraints restricoes = new GridBagConstr aints(); 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); } void addGridBag(Component objeto, int x, int y) { restricoes.gridx = x; restricoes.gridy = y; add(objeto, restricoes); } } public class GerenciadorGridBagLayout extends JFram e { public GerenciadorGridBagLayout() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(270,130); setLocation(150,150); setTitle("GridBagLayout"); Container P = getContentPane(); P.add(new PainelGridBag()); } public static void main (String[] args) { GerenciadorGridBagLayout fr = new GerenciadorGr idBagLayout(); fr.setVisible(true);

Page 20: Programação Visual em Java

20

} }

Figura 1.13. Gerenciador de Layout GridBagLayout co m cinco botões

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); }

Figura 1.14. Gerenciador de Layout GridBagLayout oc upando todo espaço disponível

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

Page 21: Programação Visual em Java

21

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); }

Figura 1.15. Gerenciador de Layout GridBagLayout ut ilizando espalhamento

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); }

Page 22: Programação Visual em Java

22

Figura 1.16. Gerenciador de Layout GridBagLayout co m 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); }

Figura 1.17. Gerenciador de Layout GridBagLayout co m aumento do tamanho e

posicionamento de componentes

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

Page 23: Programação Visual em Java

23

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); }

Figura 1.18. Gerenciador de Layout GridBagLayout ut ilizando Insets

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.*; class PainelComposto extends JPanel { public PainelComposto() { setLayout(new BorderLayout()); add(new JTextField("Digite seu texto aqui"),Bor derLayout.NORTH); add(new PainelTipoFlow(),BorderLayout.SOUTH); } } class PainelTipoFlow extends JPanel {

Page 24: Programação Visual em Java

24

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")); } } public class LayoutsCompostos extends JFrame { public LayoutsCompostos() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(400,120); setLocation(150,150); setTitle("Layouts Compostos"); Container P = getContentPane(); P.add(new PainelComposto()); } public static void main (String[] args) { LayoutsCompostos fr = new LayoutsCompostos(); fr.setVisible(true); } }

Figura 1.17. Layouts Compostos – BorderLayout e Flo wLayout

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.

2. Interface Gráfica com o Usuário e a Manipulação de Eventos

Os componentes de uma Interface Gráfica com o Usuário (GUI) são baseados em eventos, os quais são gerados na interação do usuário com a interface. Alguns exemplos de eventos possíveis: mover/clicar o mouse, clicar em um botão, fechar o frame, digitar um texto em um campo de edição, etc. É necessário, então, realizar uma manipulação dos eventos gerados. As próximas

Page 25: Programação Visual em Java

25

seções descrevem o modelo de manipulação de eventos AWT a partir de alguns elementos GUI simples.

2.1 O Modelo de Manipulação de Eventos AWT

É muito comum encontrar, em linguagens de programação visuais, o tratamento dos eventos que são gerados por seus componentes visuais. Com Java não é diferente, tanto na biblioteca AWT, quanto na biblioteca Swing, existem classes para manipulação de eventos. A maneira como essa manipulação acontece não é tão simples como nas linguagens Delphi e Visual Basic, exigindo que haja a designação de pelo menos um (pode ter mais que um) objeto ouvinte de eventos, que deve ser um objeto de uma classe que implemente a interface ouvinte (listener interface ). O objeto deve efetuar convenientemente a resposta desejada ao evento. É necessário lembrar que as interfaces possuem métodos abstract para serem redefinidos pelas classes que as implementarem. Além disso, “todos” os métodos abstract devem ser redefinidos. O registro desses ouvintes é feito em objetos conhecidos como origem do evento, como um botão, por exemplo. A origem envia objetos eventos para o(s) ouvinte(s) na ocorrência de um evento, e esse(s) usa(m) essa informação para determinar o que será feito em reação ao evento.

Um exemplo de registro de um objeto ouvinte painel em um objeto de origem botão :

MeuPainel painel = new MeuPainel(); Jbutton botao = new Jbutton(“OK”); botao.addActionListener(painel);

seguindo a sintaxe:

ObjetoOrigem.addEventListener(ObjetoOuvinte);

Assim, o objeto painel é notificado sempre que um evento ocorrer em botao , como o clique, por exemplo. No exemplo, a classe onde o objeto ouvinte painel é registrado deve implementar a interface ActionListener e definir o método actionPerformed() , que recebe um objeto ActionEvent como parâmetro. Assim: public class MeuPainel extends Jpanel implements Ac tionListener { ... public void actionPerformed(ActionEvent evt) { //código para a reação ao evento } }

2.2 Eventos em Botões

O exemplo a seguir apresenta um painel com três botões, sendo que o próprio painel é definido como ouvinte para monitorar os eventos que podem acontecer nos botões. import java.awt.*; import java.awt.event.*; import javax.swing.*; class PainelEventosBotao extends JPanel implements ActionListener { private JButton BotaoVerde; private JButton BotaoPreto;

Page 26: Programação Visual em Java

26

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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); Color cor = getBackground(); if (origem == BotaoVerde) cor = Color.green; else if (origem == BotaoPreto) cor = Color.black; else if (origem == BotaoBranco) cor = Color.white; setBackground(cor); repaint(); } } public class TesteEventosBotao extends JFrame { public TesteEventosBotao() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(400,130); setTitle("Eventos em Botões"); Container P = getContentPane(); P.add(new PainelEventosBotao()); } public static void main(String[] args) { JFrame fr = new TesteEventosBotao(); fr.setVisible(true); } }

Page 27: Programação Visual em Java

27

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.

2.3 Eventos em Caixas de Texto

O exemplo a seguir apresenta um painel com duas caixas de texto do tipo JTextField e uma do tipo JPasswordField . O objeto ouvinte definido foi o próprio painel e, quando for dado um Enter em qualquer uma das caixas, o conteúdo digitado irá aparecer em uma caixa de mensagens. import java.awt.*; import java.awt.event.*; import javax.swing.*; class PainelEventosCaixaTexto extends JPanel implem ents ActionListener { private JTextField Codigo; private JTextField Nome; private JPasswordField Senha; 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == Codigo) JOptionPane.showMessageDialog(null,"Código = "+ evt.getActionCommand()); else if (origem == Nome) JOptionPane.showMessageDialog(null,"Nome = "+ evt.getActionCommand()); else if (origem == Senha) JOptionPane.showMessageDialog(null,"Senha = " + evt.getActionCommand()); } } public class TesteEventosCaixaTexto extends JFrame { public TesteEventosCaixaTexto() { addWindowListener(new WindowAdapter()

Page 28: Programação Visual em Java

28

{public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(300,70); setLocation(300,350); setTitle("Eventos em Caixas de Texto"); Container P = getContentPane(); P.add(new PainelEventosCaixaTexto()); } public static void main(String[] args) { JFrame fr = new TesteEventosCaixaTexto(); fr.setVisible(true); } }

Figura 2.2. Eventos em objetos JTextField e JPasswo rdField

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 .

2.4 Utilizando Eventos para Alterar o Aspecto Visual da Aplicação

O Look and Feel é a aparência que sua aplicação irá tomar, definindo a forma como seus componentes serão mostrados na tela. Ao utilizar componentes da biblioteca Swing, o aspecto visual é determinado pelo estilo Metal, mas existem outros, e a alteração é feita através do método UIManager.setLookAndFeel() , passando como parâmetro o aspecto visual desejado, localizados em pacotes diferentes:

• Aspecto Metal: javax.swing.plaf.metal.MetalLookAndFeel

• Aspecto Windows: com.sun.java.swing.plaf.windows.WindowsLookAndFeel

• Aspecto Motif: com.sun.java.swing.plaf.motif.MotifLookAndFeel

• Aspecto GTK: com.sun.java.swing.plaf.gtk.GTKLookAndFeel

• Aspecto Mac: javax.swing.plaf.mac.MacLookAndFeel

Logo após, é necessário chamar o método SwingUtilities.updateComponentTreeUI para atualizar todo o conjunto de componentes. import java.awt.*; import java.awt.event.*;

Page 29: Programação Visual em Java

29

import javax.swing.*; class PainelAV extends JPanel implements ActionList ener { private JButton BotaoMetal; private JButton BotaoWindows; private JButton BotaoMotif; private JButton BotaoGTK; private JButton BotaoMac; private JTextField Texto; 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); String modelo = ""; if (origem == BotaoMetal) modelo = "javax.swing.plaf.metal.MetalLookAnd Feel"; else if (origem == BotaoWindows) modelo = "com.sun.java.swing.plaf.windows.Win dowsLookAndFeel"; else if (origem == BotaoMotif) modelo = "com.sun.java.swing.plaf.motif.Motif LookAndFeel"; else if (origem == BotaoGTK) modelo = "com.sun.java.swing.plaf.gtk.GTKLook AndFeel"; else if (origem == BotaoMac) modelo = "javax.swing.plaf.mac.MacLookAndFeel "; try { UIManager.setLookAndFeel(modelo); SwingUtilities.updateComponentTreeUI(this); } catch (Exception e) {} } } public class AspectosVisuais extends JFrame { public AspectosVisuais()

Page 30: Programação Visual em Java

30

{ addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(370,100); setTitle("Aspectos Visuais"); Container P = getContentPane(); P.add(new PainelAV()); } public static void main(String[] args) { JFrame fr = new AspectosVisuais(); fr.setVisible(true); } }

Figura 2.3. Aspectos Visuais Metal, Windows, Motif, GTK e Mac

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.

2.5 Resumo de Eventos no AWT

A tabela 2.1 mostra todas as interfaces da AWT existentes para serem implementadas em classes com objetos ouvintes, os métodos que devem ser sobrepostos, os parâmetros e os objetos origens dos eventos.

Interface Métodos Parâmetros Origens ActionListener actionPerformed ActionEvent

getActionCommand getModifiers

Button List MenuItem TextField

AdjustmentListener AdjustementValueChanged AdjustmentEvent getAdjustable

Scrollbar

Page 31: Programação Visual em Java

31

getAdjustmentType getValue

ItemListener ItemStateChanged ItemEvent getItem getItemSelectable getStateChange

Checkbox CheckboxMenuItem Choice List

TextListener TextValueChanged TextEvent TextComponent ComponentListenter componentMoved

componentHidden componentResized componentShown

ComponentEvent getComponent

Component

ContainerListener componentAdded componentRemoved

ComponentEvent getChild getContainer

Container

FocusListener focusGained focusLost

FocusEvent isTemporary

Component

KeyListener keyPressed keyReleased keyTyped

KeyEvent getKeyChar getKeyCode getKeyModifiersText getKeyText isActionKey

Component

MouseListener mousePressed mouseReleased mouseEntered mouseExited mouseClicked

MouseEvent getClickCount getX getY getPoint translatePoint isPopupTrigger

Component

MouseMotionListener mouseDragged mouseMoved

MouseEvent Component

WindowListener windowClosing windowOpened windowIconified windowDeiconified windowClosed windowActivated windowDeactivated

WindowEvent getWindow

Window

Figura 2.3. Interfaces existentes para manipular ev entos

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 .

3. Utilizando a Biblioteca Swing para a Interface com o Usuário

A partir do conhecimento do funcionamento do modelo de eventos é possível utiliza-lo nos muitos componentes de interface com o usuário existentes na biblioteca Swing, como listas, menus e caixas de diálogo, por exemplo. É bom lembrar que boa parte desses componentes possui um correspondente no AWT. A diferença é que, ao contrário do AWT, os componentes do Swing são implementados no próprio Java, garantindo que, indiferente da plataforma utilizada, a aparência não fique prejudicada.

Page 32: Programação Visual em Java

32

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.

3.1 Labels e Botões – Classes JLabel e JButton

Os labels e botões são componentes muito utilizados e de fácil manipulação. Como já visto, para tratar eventos em botões é necessário implementar o método actionPerformed() da interface ActionListenter . O exemplo a seguir mostra as principais ações que podem ser realizadas em labels, acionadas a partir do clique de botões. import java.awt.*; import java.awt.event.*; import javax.swing.*; class PainelEventosBotaoELabel extends JPanel imple ments ActionListener { private JButton BotaoUm; private JButton BotaoDois; private JLabel LabelUm; private JLabel LabelDois; public PainelEventosBotaoELabel() { BotaoUm = new JButton("Um"); BotaoDois = new JButton("Dois"); LabelUm = new JLabel("Label para o botão um"); LabelDois = new JLabel("Label para o botão dois "); add(BotaoUm); add(LabelUm); add(BotaoDois); add(LabelDois); BotaoUm.addActionListener(this); BotaoDois.addActionListener(this); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); Icon icone = new ImageIcon("LogoJava.gif"); if (evt.getActionCommand().equals("Um")) // pri meira maneira de verificar { LabelUm.setText("O botão " + BotaoUm.getText( ) + " foi clicado"); LabelUm.setIcon(icone); LabelUm.setVerticalTextPosition(SwingConstant s.BOTTOM); LabelUm.setHorizontalTextPosition(SwingConsta nts.RIGHT); } if (origem == BotaoDois) // segunda maneira de verificar { LabelDois.setText("O botão " + BotaoDois.getT ext() + " foi clicado"); LabelDois.setToolTipText("Esse é o label do b otão dois"); } } }

Page 33: Programação Visual em Java

33

public class TesteEventosBotaoELabel extends JFrame { public TesteEventosBotaoELabel() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(600,130); setTitle("Botões e Labels"); Container P = getContentPane(); P.add(new PainelEventosBotaoELabel()); } public static void main(String[] args) { JFrame fr = new TesteEventosBotaoELabel(); fr.setVisible(true); } }

Figura 3.1. Manipulação de Botões e Labels

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.

3.2 Botões de Estado – Classes JRadioButton e JCheckBox

Os botões de estado permitem ativar ou desativar opções. Dois tipos são comumente usados: as caixas de seleção e os botões de rádio. Uma caixa de seleção possui um rótulo (label) que a identifica e, ao clicar nela, a opção vai ficar ativada ou não, conforme o estado atual. Botões de rádio ficam agrupados a partir da classe ButtonGroup , sendo que apenas uma opção pode ficar selecionada. Para tratamento dos eventos, a interface utilizada é a ActionListener , como nos botões e caixas de texto. Exemplo:

import java.awt.*; import java.awt.event.*; import javax.swing.*;

Page 34: Programação Visual em Java

34

class PainelBotoesDeEstado extends JPanel implement s 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",fa lse); 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); Font f = Texto.getFont(); String Fonte = f.getName(); int Negrito = Font.PLAIN; int Italico = Font.PLAIN; if (CBItalico.isSelected()) Italico = Font.ITALIC; else Italico = Font.PLAIN; if (CBNegrito.isSelected()) Negrito = Font.BOLD; else Negrito = Font.PLAIN; if (origem == RBSansSerif) Fonte = "SansSerif"; else if (origem == RBMonospaced) Fonte = "Monospaced"; else if (origem == RBSerif) Fonte = "Serif"; Texto.setFont(new Font(Fonte, Negrito + Italico , 12));

Page 35: Programação Visual em Java

35

} } public class BotoesDeEstado extends JFrame { public BotoesDeEstado() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(350,100); setTitle("Botões de Estado"); Container P = getContentPane(); P.add(new PainelBotoesDeEstado()); } public static void main(String[] args) { JFrame fr = new BotoesDeEstado(); fr.setVisible(true); } }

Figura 3.2. Botões de Estado

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.*;

Page 36: Programação Visual em Java

36

import javax.swing.border.*; public class Bordas extends JFrame implements Actio nListener { private JButton RBEtched; private JButton RBEmpty; private JButton RBLine; private JButton RBMatte; private JButton RBLoweredBevel; private JButton RBRaisedBevel; private JButton RBCompound; private JCheckBox CBTitled; private Border BordaCentro = null; public Bordas() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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," Tip os 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource();

Page 37: Programação Visual em Java

37

JPanel PainelCentro = new JPanel(); if (origem == RBEtched) BordaCentro = BorderFactory.createEtchedBord er(); 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.createLoweredBe velBorder(); else if (origem == RBRaisedBevel) BordaCentro = BorderFactory.createRaisedBevelBorde r(); else if (origem == RBCompound) BordaCentro = BorderFactory.createCompoundBorder (BorderFactory.createEtchedBorder(), BorderFactory.createMatteBorder(3, 3, 3, 3, Color.green)); if (CBTitled.isSelected()) { Border BordaTitulo = BorderFactory.createTitledBorder(BordaCen tro," Exemplo de Título "); PainelCentro.setBorder(BordaTitulo); } else PainelCentro.setBorder(BordaCentro); Container P = getContentPane(); P.add(PainelCentro,"Center"); validate(); } public static void main(String[] args) { JFrame fr = new Bordas(); fr.setVisible(true); } }

Figura 3.3. Tipos de Bordas no Swing

Page 38: Programação Visual em Java

38

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:

• EtchedBorder: cria uma borda de linha com efeito 3D. createEtchedBorder() createEtchedBorder(Color destaque, Color Sombra)

• EmptyBorder : cria uma borda vazia, mas ocupa espaço e permite inserção de título. createEmptyBorder() createEmptyBorder(int topo, int esquerda, int base, int direita)

• LineBorder : cria uma borda de linha simples. createLineBorder(Color cor) createLineBorder(Color cor, int espessura)

• MatteBorder : cria uma borda larga que pode ser preenchida com uma cor sólida ou um ícone. createMatteBorder(int topo, int esquerda, int base, int direita, Color cor) createMatteBorder(int topo, int esquerda, int base, int direita, Icon icone)

• BevelBorder: cria uma borda com efeito de relevo (para cima ou para baixo). createLoweredBorder() createRaisedBorder()

• CompoundBorder: cria uma borda unindo duas outras bordas. createCompundBorder(Border BordaExterna, Border Bor daInterna)

• TitledBorder : cria uma borda com um título. Normalmente é utilizado para inserir títulos em outras bordas. createTitledBorder(String titulo) createTitledBorder(Border borda, String titulo) createTitledBorder(Border borda, String titulo, int alinhamento, int posicao) createTitledBorder(Border borda, String titulo, int alinhamento, int posição, Font fonte, Color cor)

O alinhamento do TitledBorder pode ser uma das constantes: TitledBorder.LEFT , TitledBorder.RIGHT ou TitledBorder.CENTER . A posição pode ser uma das constantes de TitledBorder : ABOVE_TOP, TOP, BELOW_TOP, ABOVE_BOTTOM, BOTTOM, BELOW_BOTTOM.

3.4 Caixas de Combinação

Uma caixa de combinação é uma lista do tipo “abre/fecha” que apresenta múltiplos valores, sendo que apenas um pode ser selecionado. A classe que implementa esse componente é a

Page 39: Programação Visual em Java

39

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 class CaixasDeCombinacao extends JFrame impl ements ActionListener { private JComboBox Cores; private Color cor = Color.green; private String Itens[] = {"Verde","Amarelo","Azul ","Branco"}; private JPanel PainelSul; private JPanel PainelCentro; private Border Borda; private JLabel Texto; public CaixasDeCombinacao() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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"); } public void actionPerformed(ActionEvent evt) { JComboBox origem = (JComboBox)evt.getSource(); if ((String)origem.getSelectedItem() == "Verde" ) cor = Color.green; else if ((String)origem.getSelectedItem() == "A marelo") cor = Color.yellow; else if ((String)origem.getSelectedItem() == "A zul") cor = Color.blue; else if ((String)origem.getSelectedItem() == "B ranco") cor = Color.white; Borda = BorderFactory.createMatteBorder(8, 8, 8 , 8, cor); PainelCentro.setBorder(Borda); Texto.setText((String)origem.getSelectedItem()) ; } public static void main (String[] args) {

Page 40: Programação Visual em Java

40

CaixasDeCombinacao fr = new CaixasDeCombinacao( ); fr.setVisible(true); } }

Figura 3.4. Manipulação de Bordas através de uma Ca ixa de Combinação

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.

Alguns outros métodos são importantes:

• void setEditable(Boolean editavel) : se o parâmetro for true, o item selecionado pode sofrer alterações, caso contrário não.

• void addItem(Object Item) : adiciona um item à lista.

• void insertItemAt(Object Item, int posicao) : adiciona um item à lista na posição indicada.

• void removeItem(Object Item) : remove um item da lista.

• void removeItemAt(Object Item, int posicao) : remove o item da lista que está posição indicada.

3.5 Contêiner JScrollPane e Caixas de Listagem

Sempre que se deseja incluir barras de rolagem em um componente qualquer, é necessário inseri-lo em um contêiner JScrollPane . Caso o componente inserido seja maior que o contêiner, automaticamente são mostradas barras de rolagem para poder visualizar a parte do componente que não ficou visível, tanto vertical, quanto horizontalmente. Não é possível atribuir um layout ao JScrollPane , pois ele tem seu próprio layout, não podendo ser alterado. Tal layout aceita apenas um componente, permitindo a inserção de um outro contêiner, como um painel, por exemplo.

Page 41: Programação Visual em Java

41

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 class CaixasDeListagem extends JFrame { private JList FrutasLegumes; private String NomesImagens[] = {"","Abobora.gif","Alcachofra.gif","Berin jela.gif","Maca.gif"}; private Icon Imagens[] = {new ImageIcon(NomesImag ens[0]), new ImageIcon(NomesImag ens[1]), new ImageIcon(NomesImag ens[2]), new ImageIcon(NomesImag ens[3]), new ImageIcon(NomesImag ens[4])}; private String ItensLista[] = {"Nenhum","Abóbora","Alcachofra","Berinje la","Maçã"}; private JPanel PainelLista; private JLabel LabelImagem; public CaixasDeListagem() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(250,100); setTitle("Caixa de Listagem"); Container P = getContentPane(); PainelLista = new JPanel(); FrutasLegumes = new JList(ItensLista); FrutasLegumes.setVisibleRowCount(3); FrutasLegumes.setSelectionMode(ListSelectionMod el.SINGLE_SELECTION); PainelLista.add(new JScrollPane(FrutasLegumes)) ; LabelImagem = new JLabel(Imagens[0]); PainelLista.add(LabelImagem); FrutasLegumes.addListSelectionListener(new List SelectionListener() { public void valueChanged(ListSelectionEvent e) { LabelImagem.setIcon(Imagens[FrutasLegumes.ge tSelectedIndex()]); } }); P.add(PainelLista); } public static void main (String[] args) { CaixasDeListagem fr = new CaixasDeListagem(); fr.setVisible(true); } }

Page 42: Programação Visual em Java

42

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:

Antes de tudo, inserir o implements ListSelectionListener na criação da classe: public class CaixasDeListagem extends JFrame implem ents ListSelectionListener

Depois, indicar o próprio frame como objeto ouvinte: FrutasLegumes.addListSelectionListener(this);

Por fim, implementar o método valueChanged() : public void valueChanged(ListSelectionEvent evt) { LabelImagem.setIcon(Imagens[FrutasLegumes.getSele ctedIndex()]); }

Para que se possa efetuar a seleção múltipla dos itens de uma caixa de listagem, é necessário determinar se a seleção é SINGLE_INTERVAL_SELECTION, permitindo selecionar um intervalo contíguo, clicando com o mouse em um primeiro item e, com a tecla Shift pressionada, clicando no último item desejado; ou MULTIPLE_INTERVAL_SELECTION, permitindo selecionar itens não contíguos, através da utilização da tecla Ctrl , clicando com o mouse nos itens desejados. Exemplo: import java.awt.*; import java.awt.event.*; import javax.swing.*;

Page 43: Programação Visual em Java

43

import javax.swing.event.*; public class ListaSelecaoMultipla extends JFrame { private JList Numeros; private JList Selecionados; private String ItensLista[] = {"Zero","Um","Dois","Três","Quatro","Cinc o","Seis","Sete"}; private JPanel PainelListaSM; public ListaSelecaoMultipla() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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.MUL TIPLE_INTERVAL_SELECTION); PainelListaSM.add(new JScrollPane(Numeros)); Selecionados = new JList(); Selecionados.setVisibleRowCount(5); Selecionados.setFixedCellWidth(80); Selecionados.setFixedCellHeight(20); Selecionados.setSelectionMode (ListSelectionModel.SINGL E_INTERVAL_SELECTION); PainelListaSM.add(new JScrollPane(Selecionados) ); P.add(PainelListaSM); Numeros.addListSelectionListener(new ListSelect ionListener() { public void valueChanged(ListSelectionEvent e) { Selecionados.setListData(Numeros.getSelectedVal ues()); } }); } public static void main (String[] args) { ListaSelecaoMultipla fr = new ListaSelecaoMulti pla(); fr.setVisible(true); } }

Page 44: Programação Visual em Java

44

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() .

3.6 Dividindo Painéis

A classe JSplitPane é a responsável pela divisão de áreas. Na verdade, ele é um contêiner especial que permite o compartilhamento do espaço para dois outros componentes, separando-os por uma barra divisora ajustável. O exemplo a seguir mostra dois labels com imagens compartilhando a área definida pelo JSplitPane . import java.awt.*; import java.awt.event.*; import javax.swing.*; public class PainelDividido extends JFrame { public PainelDividido() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); setSize(615,300); setTitle("Painel Dividido"); JLabel Um = new JLabel(new ImageIcon("Um.jpg")) ; JLabel Dois = new JLabel(new ImageIcon("Dois.jp g")); Component Esquerda = new JScrollPane(Um); Component Direita = new JScrollPane(Dois); JSplitPane Divisao = new JSplitPane(JSplitPane.HORIZONTAL _SPLIT, Esquerda, Direita); Divisao.setDividerLocation(300); Divisao.setDividerSize(10); Container P = getContentPane(); P.add(Divisao); } public static void main (String[] args) { PainelDividido fr = new PainelDividido(); fr.setVisible(true); } }

Page 45: Programação Visual em Java

45

Figura 3.7. Labels com imagens compartilhando um pa inel 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.

3.8 Barra de Controle Deslizante

A partir de um objeto do tipo JSlider é possível selecionar um valor inteiro entre um intervalo definido em uma barra de controle com um marcador de medidas. Tal componente possui diversas configurações possíveis, como: o posicionamento horizontal ou vertical, a exibição de marcas de medida principais e secundárias e a mostragem de rótulos para essas marcas. O exemplo a seguir mostra uma barra de controle deslizante (JSlider ) e uma barra de rolagem normal (JScrollBar ). import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class ControleDeslizante extends JFrame { private JSlider TamanhoTextoSlider; private JScrollBar TamanhoTextoScroll; private JLabel TextoSlider; private JLabel TextoScroll; public ControleDeslizante()

Page 46: Programação Visual em Java

46

{ addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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.P LAIN,20)); PainelCDNorte.add(TextoSlider); P.add(PainelCDNorte,"North"); JPanel PainelCDCentro = new JPanel(); TextoScroll = new JLabel("JScrollBar tamanho 20 "); TextoScroll.setFont(new Font("SansSerif",Font.P LAIN,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.get PreferredSize().height)); PainelCDSul.add(TamanhoTextoScroll); P.add(PainelCDSul,"South"); TamanhoTextoSlider.addChangeListener(new Change Listener() { public void stateChanged(ChangeEvent e) { TextoSlider.setText("JSlider tamanho "+Tamanho TextoSlider.getValue()); TextoSlider.setFont( new Font("SansSerif",Font.PLAIN,Tamanh oTextoSlider.getValue())); } }); TamanhoTextoScroll.addAdjustmentListener(new Ad justmentListener() { public void adjustmentValueChanged(Adjustment Event e) { TextoScroll.setText( "JScrollBar tamanho "+TamanhoTextoScr oll.getValue()); TextoScroll.setFont( new Font("SansSerif",Font.PLAIN,Taman hoTextoScroll.getValue())); } }); } public static void main (String[] args) { ControleDeslizante fr = new ControleDeslizante( ); fr.setVisible(true); } }

Page 47: Programação Visual em Java

47

Figura 3.8. Utilização do JSlider e e JScrollBar pa ra alterar tamanho de fonte

Dois labels de tamanho 20 foram inseridos em dois painéis (PainelCDNorte e PainelCDCentro ) para mostrar a funcionalidade dos componentes (figura 3.8). No PainelCDSul foi inserido um componente TamanhoTextoSlider , do tipo JSlider , para controlar o tamanho do primeiro label, e um outro componente TamanhoTextoScroll , para controlar o tamanho do segundo label. Para criar o objeto JSlider foi identificada a orientação como sendo horizontal (SwingConstants.HORIZONTAL ), o valor mínimo como sendo 0, o valor máximo como sendo 50, e a posição de início como sendo 20. Após, foram setados os marcadores principal e secundário como sendo 10 e 2, através do setMajorTickSpacing() e do setMinorTickSpacing() , para depois serem mostrados através do setPaintTicks() . Para criar o objeto JScrollBar também foi identificada a orientação como sendo horizontal (JScrollBar.HORIZONTAL ), a posição de início como sendo 20, a área visível da barra de rolagem como sendo 0 pois, nesse tipo de utilização do JScrollBar , é necessária a utilização total da barra, o valor mínimo como sendo 0 e o valor máximo como sendo 50. O seu tamanho foi definido pelo método setPreferredSize() , que necessita de um objeto Dimension como parâmetro, sendo passado os valores de largura 200 e sendo mantida a altura original da barra de rolagem, através do getPreferredSize().height .

Para o tratamento dos eventos do objeto TamanhoTextoSlider foi feita a implementação do método stateChanged() , a partir da interface ChangeListener , onde, a cada modificação no controle deslizante, o texto é alterado pelo setText() e a fonte é alterada pelo setFont() , passando como parâmetro a posição atual do controle deslizante, a partir do getValue() . A mesma coisa ocorre no tratamento dos eventos do objeto TamanhoTextoScroll , utilizando uma interface diferente, a AdjustmentListener , com a implementação do método adjustmentValueChanged() .

3.8 Abas Rotuladas e Caixas de Diálogo

Na construção de aplicações, freqüentemente ocorre o problema de falta de espaço para inserir todos os componentes necessários. Uma opção muito utilizada nesses casos é a criação de abas rotuladas conforme o tipo de objetos que serão inseridos. A classe que realiza essa tarefa é a JTabbedPane , que nada mais é que um contêiner que permite a inserção de diversos painéis, um em cada aba. Para exemplificar a utilização das abas rotuladas, o exemplo a seguir possui seis

Page 48: Programação Visual em Java

48

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 class AbasRotuladas extends JFrame implement s ActionListener { private JTabbedPane Abas; private JButton CDMensagem1; private JButton CDMensagem2; private JButton CDMensagem3; private JButton CDConfirmacao1; private JButton CDConfirmacao2; private JButton CDConfirmacao3; private JButton CDConfirmacao4; private JLabel LabelConfirmacao; private JButton CDOpcao1; private JLabel LabelOpcao; private JButton CDEntrada1; private JButton CDEntrada2; private JButton CDEntrada3; private JLabel LabelEntrada; private JButton CDArquivo1; private JLabel LabelArquivo1; private JLabel LabelArquivo2; private JButton CDCor1; private JLabel LabelCor; public AbasRotuladas() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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:");

Page 49: Programação Visual em Java

49

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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); int retorno = 0;

Page 50: Programação Visual em Java

50

String valorRet = null; Icon icone = new ImageIcon("LogoSun.gif"); if (origem == CDMensagem1) JOptionPane.showMessageDialog(null, "Esta é uma caixa de diálogo de Me nsagem"); else if (origem == CDMensagem2) JOptionPane.showMessageDialog(null, "Esta é uma caixa de diálogo de Me nsagem", "Mensagem", JOptionPane.WARNING_MESSAGE); else if (origem == CDMensagem3) JOptionPane.showMessageDialog(null, "Esta é uma caixa de diálogo de M ensagem", "Mensagem", JOptionPane.WARNING_MESSAG E, icone); else if (origem == CDConfirmacao1) { retorno = JOptionPane.showConfirmDialog(null, "Confirma Operação?"); LabelConfirmacao.setText("Retorno: " + retorn o); } else if (origem == CDConfirmacao2) { retorno = JOptionPane.showConfirmDialog(null, "Confirma Operação?", "Confirmação", JOptionPane.YES_NO_OPTION); LabelConfirmacao.setText("Retorno: " + retorn o); } else if (origem == CDConfirmacao3) { retorno = JOptionPane.showConfirmDialog(null, "Confirma Operação?", "Confirmação", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); LabelConfirmacao.setText("Retorno: " + retorn o); } else if (origem == CDConfirmacao4) { retorno = JOptionPane.showConfirmDialog(null, "Confirma Operação?", "Confirmação", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, icone ); LabelConfirmacao.setText("Retorno: " + retorn o); } 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_ME SSAGE); LabelEntrada.setText("Retorno: " + valorRet);

Page 51: Programação Visual em Java

51

} else if (origem == CDEntrada3) { Object[] valores= {"Opção Um","Opção Dois","O pção Três","Opção Quatro"}; Object valorSelec = JOptionPane.showInputDial og(null, "Escolha uma opção", "Entrada", JOptionPane.INFORMATION_MES SAGE, 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("AbasRot uladas.java")); retorno = abreArquivo.showOpenDialog(this); LabelArquivo1.setText("Retorno: " + retorno); if (retorno == JFileChooser.APPROVE_OPTION) { File arquivoSelec = abreArquivo.getSelected File(); 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 u ma cor", Color.black); LabelCor.setForeground(c); LabelCor.setText("Retorno: " + c.toString()); } } public static void main (String[] args) { AbasRotuladas fr = new AbasRotuladas(); fr.setVisible(true); } }

Figura 3.9. Abas rotuladas para demonstração das di versas 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 ,

Page 52: Programação Visual em Java

52

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.

Figura 3.10. Caixas de diálogo de mensagem, confirm ação, opção e entrada

As primeiras quatro abas correspondem às caixas de diálogo existentes na classe JOptionPane , dividas em quatro tipos, mostrados nos exemplos da figura 3.10. O primeiro tipo é a caixa de diálogo de mensagem, onde uma mensagem é mostrada, acompanhada de um botão OK. O método para criação desse tipo de caixa de diálogo é o showMessageDialog() e existem variações em relação aos parâmetros que são passados, que são:

• static void showMessageDialog(Component componenteP ai, Object mensagem) : mostra uma caixa de mensagem com o título Message e um botão OK.

• static void showMessageDialog(Component componenteP ai, Object mensagem,

String titulo, int tipoDaMensagem) : mostra uma caixa de mensagem com o título definido por titulo , um botão OK e o tipo da mensagem, que identifica o ícone apresentado, podendo ser ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE, ou PLAIN_MESSAGE.

• static void showMessageDialog(Component componenteP ai, Object mensagem,

String titulo, int tipoDaMensagem, Icon icone) : idêntico ao anterior, com a possibilidade de mostrar um ícone específico.

O segundo tipo é a caixa de diálogo de confirmação, onde uma mensagem é mostrada, normalmente uma pergunta, acompanhada de botões de confirmação. O método para criação desse tipo de caixa de diálogo é o showConfirmDialog() , que possui como retorno um inteiro que indica o botão que foi pressionado (começando por zero). No exemplo, tal retorno é armazenado em uma variável retorno e mostrado no label LabelConfirmacao . Também existem variações em relação aos parâmetros que são passados:

Page 53: Programação Visual em Java

53

• static int showConfirmDialog(Component componentePa i, Object mensagem) : mostra uma caixa de confirmação com o título Select an Option e os botões Yes, No e Cancel .

• static int showConfirmDialog(Component componentePa i, Object message,

String titulo, int tipoDaOpcao) : mostra uma caixa de confirmação com o título definido por titulo , e o o conjunto de botões definido por tipoDaOpcao , que pode ser YES_NO_OPTION, ou YES_NO_CANCEL_OPTION.

• static int showConfirmDialog(Component componentePa i, Object message,

String titulo, int tipoDaOpcao, int tipoDaMensagem) : idêntico ao anterior, com a possibilidade de identificar o tipo da mensagem e o ícone, podendo ser ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE, ou PLAIN_MESSAGE.

• static int showConfirmDialog(Component componentePa i, Object message,

String titulo, int tipoDaOpcao, int tipoDaMensagem, Icon icone) : idêntico ao anterior, permitindo mostrar um ícone.

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 é:

• static int showOptionDialog(Component componentePai , Object mensagem, String titulo, int tipoDaOpcao, int tipoDaMensagem, Icon icone, Object[]

opcoes, Object valorInicial) : mostra uma caixa de opção com o título definido por titulo , uma mensagem, a escolha do conjunto de botões utilizado, definido por tipoDaOpcao , que pode ser YES_NO_OPTION, ou YES_NO_CANCEL_OPTION, o tipo da mensagem, que identifica o ícone apresentado, podendo ser ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE, ou PLAIN_MESSAGE, um ícone, o nome dos botões, definido por um objeto opcoes , do tipo Object , e o botão que será o inicialmente selecionado, definido por valorInicial .

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:

• static String showInputDialog(Component componenteP ai, Object mensagem) : mostra uma caixa de entrada com com o título Input , uma caixa de texto para a entrada de dados e os botões OK e Cancel .

• static String showInputDialog(Component componenteP ai, Object mensagem,

String titulo, int tipoDaMensagem) : mostra uma caixa de entrada como a anterior,

Page 54: Programação Visual em Java

54

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.

• static Object showInputDialog(Component componenteP ai, Object mensagem, String titulo, int tipoDaMensagem, Icon icone, Obje ct[] valoresSelec,

Object valorSelecInicial) : tem as mesmas opções que o anterior, porém, permite inserir um ícone e, através da criação de um objeto do tipo Object , apresenta os valores em uma lista, podendo ainda ter o valor inicial setado por valorSelecInicial .

Figura 3.11. Caixa de diálogo de seleção de arquivo s

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.

No exemplo apresentado é criado um objeto abreArquivo , do tipo JFileChooser , em primeiro lugar. Após é setado o diretório a ser mostrado inicialmente, através do método setCurrentDirectory() , passando como parâmetro um objeto do tipo File . Além do diretório, foi setado o nome do arquivo inicial da busca, através do método setSelectedFile() , que também precisa de um objeto do tipo File como parâmetro. Não foi utilizado no exemplo, mas, se for necessário permitir a seleção múltipla de arquivos, é possível utilizar o método setMultiSelectionEnabled(true) . Para abrir a caixa de diálogo, basta chamar o método showOpenDialog() , tendo como valor de retorno um inteiro que representa o botão que foi pressionado (0 para Open e 1 para Cancel ). Da mesma forma, se for desejável abrir uma caixa de diálogo para Salvar arquivo, ao invés de Abrir , basta utilizar o showSaveDialog() . No exemplo, foi utilizada a variável retorno para ser posteriormente mostrada no label LabelArquivo1 .

Page 55: Programação Visual em Java

55

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.

Figura 3.12. Caixa de diálogo de seleção de cores

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() .

3.9 Menus e Áreas de Texto

O Swing apresenta suporte a menus a partir das classes JMenuBar , JMenu, JMenuItem , JCheckBoxMenuItem e JRadioButtonMenuItem . Para criar um menu não é necessário ter um gerenciador de layout específico, sendo normalmente inserido no próprio frame. A barra de menu é apresentada, normalmente, no topo do frame, com os nomes para cada menu suspenso que, ao

Page 56: Programação Visual em Java

56

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 class TesteDeMenu extends JFrame implements ActionListener { private JRadioButtonMenuItem RBFontes[],RBCores[] ; private JCheckBoxMenuItem CBNegritoItalico[]; private Color cores[]= {Color.black, Color.red, Color.blue, Color.orange, Color.gre en}; private JTextArea AreaTexto; private ButtonGroup grupoFontes, grupoCores; public TesteDeMenu() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Sys tem.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...", n ew ImageIcon("novo.gif")); itemNovo.setMnemonic('N'); JMenuItem itemAbrir= new JMenuItem("Abrir...",n ew ImageIcon("abrir.gif")); itemAbrir.setMnemonic('b'); itemAbrir.setAccelerator(KeyStroke.getKeyStroke (KeyEvent.VK_O, InputEvent.CTRL_MASK));; JMenuItem itemSalvar= new JMenuItem("Salvar",ne w ImageIcon("salvar.gif")); itemSalvar.setMnemonic('S'); itemSalvar.setAccelerator(KeyStroke.getKeyStrok e(KeyEvent.VK_S, InputEvent.CTRL_MASK));; JMenuItem itemSair= new JMenuItem("Sair");

Page 57: Programação Visual em Java

57

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("Recorta r...", new ImageIcon("recortar.gif")); itemRecortar.setMnemonic('t'); itemRecortar.setAccelerator(KeyStroke.getKeyStr oke(KeyEvent.VK_X, InputEvent.CTRL_MASK));; JMenuItem itemCopiar = new JMenuItem("Copiar... ", new ImageIcon("copiar.gif")); itemCopiar.setMnemonic('b'); itemCopiar.setAccelerator(KeyStroke.getKeyStrok e(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", "Azu l", "Laranjado", "Verde"}; JMenu menuCor = new JMenu("Cor"); menuCor.setMnemonic('C'); RBCores = new JRadioButtonMenuItem[nomesCores.l ength]; grupoCores = new ButtonGroup(); for (int i = 0; i < nomesCores.length; i++) { RBCores[i] = new JRadioButtonMenuItem(nomesCo res[i]); menuCor.add(RBCores[i]); grupoCores.add(RBCores[i]); RBCores[i].addActionListener(this); } RBCores[0].setSelected(true); menuFormatar.add(menuCor);

Page 58: Programação Visual em Java

58

menuFormatar.addSeparator(); // criação do submenu Fonte String nomesFontes[] = {"SansSerif", "Monospace d", "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(nomesF ontes[i]); menuFonte.add(RBFontes[i]); grupoFontes.add(RBFontes[i]); RBFontes[i].addActionListener(this); } RBFontes[0].setSelected(true); menuFonte.addSeparator(); String CBItalicoNegrigoItens[] = {"Negrito", "I tálico"}; CBNegritoItalico = new JCheckBoxMenuItem[CBItal icoNegrigoItens.length]; for (int i = 0; i < CBItalicoNegrigoItens.lengt h; i++) { CBNegritoItalico[i] = new JCheckBoxMenuItem(C BItalicoNegrigoItens[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 Ap licaçã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.PL AIN, 14)); AreaTexto.setLineWrap(true); Container P = getContentPane(); P.add(new JScrollPane(AreaTexto)); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() instanceof JMenuItem) { String item = evt.getActionCommand(); if (item == "Novo...") JOptionPane.showMessageDialog(this, "Opçao Novo não disponível!", "Alerta", JOptionPane.WARNING_M ESSAGE); else if (item == "Abrir...") JOptionPane.showMessageDialog(this, "Opçao Abrir não disponível!", "Alerta", JOptionPane.WARNING_M ESSAGE); else if (item == "Salvar") JOptionPane.showMessageDialog(this, "Opçao Salvar não disponível!", "Alerta", JOptionPane.WARNING_M ESSAGE); else if (item == "Sair")

Page 59: Programação Visual em Java

59

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_MESS AGE); else { int Tipo = Font.PLAIN; if (CBNegritoItalico[0].isSelected()) Tipo += Font.BOLD; if (CBNegritoItalico[1].isSelected() ) Tipo += Font.ITALIC; AreaTexto.setFont(new Font(AreaTexto.getFon t().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(); } } } public static void main(String args[]) { TesteDeMenu fr = new TesteDeMenu(); fr.setVisible(true); } }

Figura 3.13. Manipulação de uma área de texto a par tir de menus

Page 60: Programação Visual em Java

60

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.

Figura 3.14. As opções existentes no menu

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

Page 61: Programação Visual em Java

61

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() .

3.10 Tratamento de Eventos Especiais

Além dos eventos gerados por componentes de interface com o usuário, vistos até aqui, existem eventos especiais que podem ser ativados a qualquer hora, e não precisam estar associados a algum componente específico. As próximas seções explicitam três desses tipos de eventos: de foco, de janela, de mouse e de teclado.

3.10.1 Eventos de Foco

Existem componentes que podem receber foco e outros não. Receber foco significa possuir prioridade sobre os outros componentes na digitação de teclas. Por exemplo, se um botão possuir o foco, no momento que for pressionada a barra de espaços, este será o escolhido. Da mesma forma, se uma caixa de texto possuir o foco, quando forem digitados caracteres, é nela que eles serão mostrados. Portanto, se o componente puder realizar algum tipo de ação advindo do pressionamento de teclas, então, ele pode obter foco, caso contrário, não. Logicamente, em um frame pode haver apenas um componente com foco, mas ele pode perder o foco se for pressionada a tecla Tab ou se um outro componente que pode receber foco for clicado com o mouse. Isso se existitem, no frame, outros componentes que podem receber foco.

O componente que possui o foco mostra visualmente essa situação, como: um botão apresenta um retângulo pontilhado e uma caixa de texto apresenta o cursor piscando na área destinada à digitação. É possível mudar o foco via programação a qualquer momento, através do método requestFocus() , mas só irá funcionar em resposta a um evento qualquer.

Page 62: Programação Visual em Java

62

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 class TesteDeFoco extends JFrame { private JTextField TextoUm; private JTextField TextoDois; private JTextField TextoTres; private JTextField TextoQuatro; private JButton BotaoUm; private JButton BotaoDois; private JButton BotaoTres; private JButton BotaoQuatro; public TesteDeFoco() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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.createEt chedBorder(); 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.createE tchedBorder(); PainelFocoBaixo.setBorder(bordaPainelBaixo); P.add(PainelFocoBaixo); } public static void main(String[] args) {

Page 63: Programação Visual em Java

63

JFrame fr = new TesteDeFoco(); fr.setVisible(true); } }

Figura 3.15. Sentido da Ordem de Tabulação

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 class FocoAlterado extends JFrame implements FocusListener { private JTextField TextoUm; private JTextField TextoDois; public FocoAlterado() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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);

Page 64: Programação Visual em Java

64

TextoDois = new JTextField("Texto Dois",10); PainelFoco.add(TextoDois); P.add(PainelFoco); TextoUm.addFocusListener(this); } public void focusLost(FocusEvent evt) { Component origem = evt.getComponent(); if (origem == TextoUm && !evt.isTemporary()) if (TextoUm.getText().equals("")) { JOptionPane.showMessageDialog(this, "O valo r deve ser digitado!", "Atenção", JOptionPane.ERROR_ME SSAGE); TextoUm.requestFocus(); } } public void focusGained(FocusEvent evt) { } public static void main(String[] args) { JFrame fr = new FocoAlterado(); fr.setVisible(true); } }

Figura 3.16. Teste de entrada de dados em uma caixa de texto

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.

No exemplo, para o objeto TextoUm , foi adicionado o ouvinte de eventos a partir do addFocusListener() . No método focusLost() foi feito o teste se a origem do evento foi o TextoUm e se não foi uma perda de foco temporária. Caso seja verdadeiro e o conteúdo da caixa de texto esteja vazio, é mostrada uma mensagem e é devolvido o foco ao próprio TextoUm , não permitindo, dessa forma, sair da caixa de texto sem a digitação de algo. Como não foi realizada

Page 65: Programação Visual em Java

65

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.

3.10.2 Eventos de Janela

Da mesma forma que os componentes, as janelas também possuem eventos possíveis de acontecer. A classe JFrame é o tipo de janela mais utilizado em Java, possuindo uma barra de título e uma borda que se adaptam a plataforma onde o aplicativo está sendo executado. Isso significa que são incorporados recursos da GUI daquela plataforma específica.

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){Syst em.exit(0);}});

Além do método windowClosing() , outros seis métodos podem ser implementados. São eles:

• windowActivated() : ocorre quando a janela se torna ativa.

• windowDeactivated() : ocorre quando a janela se torna inativa, provavelmente na ativação de outra janela.

• windowOpened() : ocorre quando a janela é aberta.

• windowClosed() : ocorre quando a janela é fechada. A diferença desse método para o windowClosing() é que esse último pode evitar que a janela seja fechada, enquanto o windowClosed() é executado após o fechamento da janela.

• windowIconified() : ocorre quando a janela é minimizada.

• windowDeiconified() : ocorre quando a janela é restaurada.

O exemplo a seguir mostra a primeira maneira de implementação de alguns métodos da interface WindowListener . import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EventosEmJanelas extends JFrame { public EventosEmJanelas() { addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { JOptionPane.showMessageDialog(null, "O frame será fechado...");

Page 66: Programação Visual em Java

66

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); } public static void main(String[] args) { JFrame fr = new EventosEmJanelas(); fr.setVisible(true); } }

Figura 3.17. Manipulação de eventos em janelas

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.*; public class EventosEmJanelasSegundaForma extends J Frame implements WindowListener { public EventosEmJanelasSegundaForma()

Page 67: Programação Visual em Java

67

{ addWindowListener(this); setSize(300,70); setLocation(200,200); } public void windowClosing(WindowEvent e) { JOptionPane.showMessageDialog(null, "O frame ser á fechado..."); System.exit(0); } public void windowOpened(WindowEvent e) { setTitle("Aberto"); } public void windowIconified(WindowEvent e) { setTitle("Minimizado"); } public void windowDeiconified(WindowEvent e) { setTitle("Restaurado"); } public void windowClosed(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e){ } public static void main(String[] args) { JFrame fr = new EventosEmJanelasSegundaForma() ; fr.setVisible(true); } }

A execução é a mesma, mas a forma escolhida para a programação é diferente. Observe que, em primeiro lugar, utilizou-se o implements WindowListener , e após foi realizada a implementação dos métodos, tornando-se obrigatória, dessa forma, que todos os métodos estejam presentes, inclusive aqueles que não tem nenhum código interno.

3.10.3 Eventos de Mouse

Qualquer ação do mouse pode ser capturada como sendo um evento específico, porém, na maioria das vezes, essas ações já são tratadas pelos componentes que estão sendo manipulados. Por exemplo, se for clicado em um botão, o método a ser implementado é o actionPerformed() , da interface ActionListener , não sendo necessário tratar exclusivamente o clique do mouse. Porém, existem situações que necessitam da implementação de linhas de código que respondam a eventos de mouse, e quando isso acontece, os métodos da interface MouseListener e MouseMotionListener devem ser implementados, tendo como parâmetro um

Page 68: Programação Visual em Java

68

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:

• mouseClicked() : ocorre quando há o pressionamento do mouse, com qualquer botão, e sua liberação sem o movimento do cursor.

• mousePressed() : ocorre quando há o pressionamento de algum botão do mouse.

• mouseReleased() : ocorre quando há a liberação de algum botão do mouse após ter havido o pressionamento deste.

• mouseEntered() : ocorre quando o cursor do mouse entra na área definida por um componente específico.

• mouseExited() : ocorre quando o cursor do mouse sai da área definida por um componente específico.

Já a interface MouseMotionListener se preocupa mais com os eventos de movimento do mouse. Os dois métodos exitentes são:

• mouseMoved() : ocorre quando há o movimento do cursor do mouse em um componente específico.

• mouseDragged() : ocorre quando há o pressionamento (mousePressed() ) de um botão do mouse e posterior movimentação.

A fim de demonstrar o funcionamento do tratamento de eventos de mouse, o exemplo a seguir traz uma implementação para todos os métodos de cada uma das duas interfaces.

import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EventosDeMouse extends JFrame implements MouseListener, MouseMotionL istener { private JLabel Mensagem; private JButton BotaoOK; public EventosDeMouse() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.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();

Page 69: Programação Visual em Java

69

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); } public void mouseClicked(MouseEvent e) { String botaoPressionado =e.getButton() == 1 ? " esquerdo" : (e.getButton() == 2 ? "do m eio" : "direito"); Mensagem.setText("Botão " + botaoPressionado + " CLICADO nas cordenadas x = " + e.getX() + " y = " + e.getY()); } public void mousePressed(MouseEvent e) { String botaoPressionado =e.getButton() == 1 ? " esquerdo" : (e.getButton() == 2 ? " do meio" : "direito"); Mensagem.setText("Botão " + botaoPressionado + " PRESSIONADO nas cordenadas x = " + e.get X() + " y = " + e.getY()); } public void mouseReleased(MouseEvent e) { String botaoPressionado =e.getButton() == 1 ? " esquerdo" : (e.getButton() == 2 ? " do meio" : "direito"); Mensagem.setText("Botão " + botaoPressionado + " LIBERADO nas cordenadas x = " + e.getX() + " y = " + e.getY()); } public void mouseEntered(MouseEvent e) { Mensagem.setText("Mouse ENTROU no FRAME"); if (e.getSource() == BotaoOK) { Mensagem.setText("Mouse ENTROU no BOTÃO"); setCursor(Cursor.getPredefinedCursor(Cursor.H AND_CURSOR)); } } public void mouseExited(MouseEvent e) { Mensagem.setText("Mouse SAIU do FRAME"); if (e.getSource() == BotaoOK) { Mensagem.setText("Mouse SAIU no BOTÃO"); // mensagem não perceptível setCursor(Cursor.getDefaultCursor()); } } public void mouseMoved(MouseEvent e) { Mensagem.setText("Cursor MOVIDO para x = " + e. getX() +

Page 70: Programação Visual em Java

70

" y = " + e.getY()); } public void mouseDragged(MouseEvent e) { Mensagem.setText("Cursor ARRASTADO para x = " + e.getX() + " y = " +e.getY()); } public static void main(String[] args) { JFrame fr = new EventosDeMouse(); fr.setVisible(true); } }

Figura 3.18. Manipulação de eventos de mouse

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() .

Os métodos mouseClicked() , mousePressed() e mouseReleased() simplesmente atualizam o label com: a mensagem de qual botão foi pressionado, informação adquirida pelo método getButton() , que retorna um inteiro (1- botão esquerdo, 2- botão do meio e 3- botão direito); a ação realizada, se o botão foi clicado, pressionado ou liberado; e as coordenadas x e y, adquiridas pelos métodos getX() e getY() . Como o botão também possui um ouvinte de eventos, a mensagem também é atualizada quando o evento ocorre sobre ele. Percebe-se que as coordenadas x e y são específicas do botão.

Nos métodos mouseEntered() e mouseExited() há um tratamento especial para a ocorrência do evento no botão. Quando o evento de entrada ou saída ocorre no frame, apenas uma mensagem adequada é mostrada, porém, quando esse tipo de evento ocorre no botão, além da mensagem, é alterado o cursor para HAND_CURSOR na entrada e para o cursor padrão na saída. Isso é feito a partir do método setCursor() , que tem como parâmetro um objeto do tipo Cursor , onde, através do getPredefinedCursor() , é possível setar um dos cursores pré-definidos. Alguns desses tipos de cursor são mostrados na tabela 3.1.

Page 71: Programação Visual em Java

71

DEFAULT_CURSOR

HAND_CURSOR

WAIT_CURSOR

TEXT_CURSOR

CROSSHAIR_CURSOR

MOVE_CURSOR

N_RESIZE_CURSOR (norte) ou S_RESIZE_CURSOR (sul)

SW_RESIZE_CURSOR (sul- leste) ou NE_RESIZE_CURSOR (norte-leste)

SE_RESIZE_CURSOR (sul-leste) ou NW_RESIZE_CURSOR (norte-leste)

E_RESIZE_CURSOR (leste) ou W_RESIZE_CURSOR (oeste)

Tabela 3.1. Exemplos de cursor existentes na plataf orma Windows

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:

• keyPressed() : ocorre quando há o pressionamento de qualquer tecla.

• keyReleased() : ocorre quando há a liberação de qualquer tecla, ocorrida após o seu pressionamento.

• 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.

O funcionamento dos eventos de teclado possíveis é demonstrado no exemplo a seguir, que simplesmente mostra a tecla, ou combinação de teclas que foi pressionada ou liberada.

Page 72: Programação Visual em Java

72

import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EventosDeTeclado extends JFrame implem ents KeyListener { private JLabel Mensagem; private int tecla = 0; private String teclaPressed = null; private char teclaTyped; private boolean entrouPressed; private boolean combinacao; public EventosDeTeclado() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Syst em.exit(0);}}); addKeyListener(this); setSize(250,100); setLocation(300,250); setTitle("Eventos de Teclado"); Container P = getContentPane(); Mensagem = new JLabel(); P.add(Mensagem); } public void keyPressed(KeyEvent e) { tecla = e.getKeyCode(); teclaPressed = e.getKeyText(tecla); entrouPressed = true; switch (tecla){ case KeyEvent.VK_SHIFT: teclaPressed = "Shift "; break; case KeyEvent.VK_CONTROL: teclaPressed = "Con trol"; break; case KeyEvent.VK_ALT: teclaPressed = "Alt"; b reak; case KeyEvent.VK_RIGHT: teclaPressed = "Direi ta"; break; case KeyEvent.VK_LEFT: teclaPressed = "Esquer da"; break; case KeyEvent.VK_UP: teclaPressed = "Cima"; b reak; case KeyEvent.VK_DOWN: teclaPressed = "Baixo" ; break; } if (tecla == KeyEvent.VK_A && e.isShiftDown()) { combinacao = true; teclaPressed = "Shift + A"; } 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 + " - " + tec laPressed +" PRESSIONADA");

Page 73: Programação Visual em Java

73

} public void keyReleased(KeyEvent e) { if (entrouPressed) { Mensagem.setText("Tecla " + tecla + " - " + t eclaPressed + " LIBERADA"); combinacao = false; } else Mensagem.setText("Tecla " + teclaTyped + " L IBERADA"); } public void keyTyped(KeyEvent e) { if (!combinacao) { teclaTyped = e.getKeyChar(); entrouPressed = false; Mensagem.setText("Tecla " + teclaTyped + " PRESSIONADA"); } } public static void main(String[] args) { JFrame fr = new EventosDeTeclado(); fr.setVisible(true); } }

Figura 3.19. Manipulação de eventos de teclado

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

Page 74: Programação Visual em Java

74

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.

O método keyReleased() é executado após o keyPressed() ou o keyTyped() tiver sido executado. Por isso a existência da variável entrouPressed , para dar mensagens diferentes na liberação das teclas.

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.

3.11 Aplicações MDI, Menus Flutuantes e Barra de Ferramentas

Em Java, uma aplicação MDI (Mutilple Document Interface – Interface de Múltiplos Documentos) é caracterizada pela existência de um frame principal, ou frame pai, que pode conter várias outros frames internos, ou frames filhos. As operações de manipulação do frame principal acarretam em efeitos nos frames internos. A ação de fechar, por exemplo, faz com que os frames internos que estão abertos também sejam finalizados.

A área de ação de um frame interno é o próprio frame principal, não podendo ultrapassar os seus limites. Isso significa que, se um frame interno for maximizado, ele vai ocupar o espaço delimitado pelo frame principal, esteja ele ocupando o espaço que for da tela. Da mesma forma, ao minimizar um frame interno, este vai ficar localizado no rodapé do frame principal.

Para que se possa criar uma área apta à manipulação de frames internos, deve-se trabalhar com um objeto da classe JDesktopPane e inserir um objeto da classe JInternalFrame para cada frame interno que se deseja criar.

A aplicação mostrada a seguir apresenta, além do exemplo da aplicação MDI, a utilização de uma barra de ferramentas e de menus flutuantes. Uma barra de ferramentas é criada a partir da classe JToolBar , e nada mais é do que um conjunto de botões que realizam ações, normalmente utilizada para criar acessos rápidos às principais tarefas da aplicação. Os menus flutuantes, criados a partir da classe JPopupMenu e comumente chamados de pop-up , são menus suspensos ativados normalmente pelo clique do botão direito do mouse, e podem aparecer em qualquer parte da área que lhe foi destinada. Os itens de menu de um menu flutuante podem ter as mesmas características de um menu normal: ser apresentados na forma de caixa de seleção ou botão de rádio, com imagem associada, com teclas de atalho e teclas aceleradoras.

import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.beans.*; public class AplicacaoMDI extends JFrame implements ActionListener {

Page 75: Programação Visual em Java

75

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){Sys tem.exit(0);}}); setSize(500,400); setLocation(100,50); setTitle("Aplicação MDI com Barra de Ferramenta s 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 Fr ame Interno Um...", new ImageIcon("EstrelaUm.gif")); itemAbrirUm.setMnemonic('U'); JMenuItem itemAbrirDois= new JMenuItem("Abrir F rame 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("Estrel aUm.gif")); abreFrameUm.setToolTipText("Abre o Frame Intern o Um"); abreFrameDois = new JButton(new ImageIcon("Estr elaDois.gif")); abreFrameDois.setToolTipText("Abre o Frame Inte rno 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");

Page 76: Programação Visual em Java

76

// criação da área para inserção de frames inte rnos DPane = new JDesktopPane(); DPane.putClientProperty("JDesktopPane.dragMode" , "outline"); P.add(DPane,"Center"); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); String item = evt.getActionCommand(); if (item == "Abrir Frame Interno Um..." || orig em == abreFrameUm) { IFrameUm = new JInternalFrame("Frame Interno Um", true, true, true, true); IFrameUm.setSize(250,150); IFrameUm.setLocation(50,50); IFrameUm.setFrameIcon(new ImageIcon("EstrelaU m.gif")); IFrameUm.setVisible(true); JButton BotaoFechar = new JButton("Fechar"); BotaoFechar.addActionListener(new ActionListe ner() { public void actionPerformed(ActionEvent e) { try { IFrameUm.setClosed(true); } catch (PropertyVetoException exc) { } } }); Menu = new JPopupMenu(); JMenuItem itemTitulo = new JMenuItem("Alterar Título"); Menu.add(itemTitulo); itemTitulo.addActionListener(new ActionListen er() { public void actionPerformed(ActionEvent e) { String retorno = JOptionPane.showInternal InputDialog(IFrameUm, "Digite novo título", "Entrada" , JOptionPane.QUESTION_MESSAGE); if (retorno != null) IFrameUm.setTitle(retorno); try { IFrameUm.setSelected(true); } catch (PropertyVetoException exc) { } } }); Menu.addSeparator(); JMenuItem itemFechar = new JMenuItem("Fechar" ); Menu.add(itemFechar); itemFechar.addActionListener(new ActionListen er() { public void actionPerformed(ActionEvent e) { try { IFrameUm.setClosed(true); } catch (PropertyVetoException exc) { } } }); IFrameUm.addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger())

Page 77: Programação Visual em Java

77

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 Intern o Dois", false, true, false, false); IFrameDois.setSize(250,150); IFrameDois.setLocation(150,150); IFrameDois.setFrameIcon(new ImageIcon("Estrel aDois.gif")); IFrameDois.setVisible(true); JButton BotaoFechar = new JButton("Fechar"); BotaoFechar.addActionListener(new ActionListe ner() { 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); } public static void main(String args[]) { AplicacaoMDI fr = new AplicacaoMDI(); fr.setVisible(true); } }

Page 78: Programação Visual em Java

78

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.

Figura 3.21. Aplicação MDI – Barra de Ferramentas

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.

Page 79: Programação Visual em Java

79

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.

Page 80: Programação Visual em Java

80

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.

O método putClientProperty() utilizado em seguida é referente ao arrastar dos frames internos. Como padrão, toda vez que se tentar movimentar um frame interno, este é redesenhado a todo momento, enquanto estiver sendo arrastado. Isso pode causar desagrado a usuários que não tenham um bom equipamento, principalmente no que diz respeito ao vídeo, pois o desempenho pode não ser satisfatório. Para evitar isso, o método chamado faz com que, no ato de arrastar, apenas o contorno apareça e o frame só seja redesenhado na posição final desejada. O Windows, por exemplo, tem esse procedimento como padrão no arrastar de janelas.

No exemplo, os frames internos somente serão criados se um evento ocorrer, seja pela chamada do item de menu específico, ou através da barra de ferramentas. Então, no método actionPerformed() , se for selecionado o item do menu Abrir Frame Interno Um... , ou se for clicado o primeiro botão da barra de ferramentas, será mostrrado o primeiro frame interno. Para isso, foi criado um objeto IFrameUm a partir da classe JInternalFrame , passando cinco parâmetros, seguindo a sintaxe: JInternalFrame(String titulo, boolean redimensionar, boolean fechar, boolean maximizar, boolean minimizar)

Page 81: Programação Visual em Java

81

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:

• setSize() : determina o tamanho do frame interno.

• setLocation() : determina a localização do frame interno dentro do frame principal.

• setFrameIcon() : insere um ícone no frame interno.

• setVisible() : torna o frame interno visível.

O botão BotaoFechar foi criado, já adicionando um ouvinte de eventos e implementando o código para fechar o frame interno. O método setClosed() é responsável por fechar o frame interno, mas é necessário tratar a exceção PropertyVetoException , do pacote java.beans , pois o frame pode ter problemas na ação de fechar, por algum motivo, e, nesse caso, se a exceção não for tratada, além de não fechar, a aplicação seria abortada. O Java tem muito disso, quando a operação é crítica e pode resultar na finalização forçada da aplicação, ele exige o tratamento da exceção. Se isso não for feito, não é possível executar o método.

Figura 3.24. Aplicação MDI – Menu Flutuante

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

Page 82: Programação Visual em Java

82

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.

O segundo item, o itemFechar , simplesmente executa o método setClosed() , da mesma forma que foi feito no botão BotaoFechar .

Com os itens criados, é necessário mostrar o menu de alguma forma e isso é feito através do método show() . A questão a ser resolvida é: onde ele irá ser mostrado? Como a intenção é fazer com que a área de atuação desse menu flutuante seja somente o frame interno IFrameUm, é nele que foi adicionado um ouvinte de eventos baseado na interface MouseListener e implementado o método mouseReleased() . Isso porque o menu flutuante vai ser mostrado quando ocorrer uma ação do mouse. No código da implementação, foi utilizado o método isPopupTrigger() para verificar se o botão que foi clicado é o correspondente ao botão padrão para abrir menus flutuantes da plataforma atual, no caso do Windows, o botão direito. Os parâmetros do método show() envolvem o componente sobre o qual o menu flutuante irá aparecer e as coordenadas do clique do mouse, que é onde o menu flutuante irá ser desenhado

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.

3.12 Aplicação com Vários Frames

Existem situações em que o estilo de aplicação MDI não é aplicável, e nem desejado. Nesses casos, as aplicações devem trabalhar com um frame principal que abre outros frames normais, não internos, que possuem suas áreas de atuação dentro da plataforma utilizada, e não no frame

Page 83: Programação Visual em Java

83

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 class VariosFrames extends JFrame implements ActionListener { private JButton abreFrameUm; private JButton abreFrameDois; private JFrame FrameDois; public VariosFrames() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Sys tem.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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == abreFrameUm) { FrameUm frame = new FrameUm(); frame.show(); } if (origem == abreFrameDois) { FrameDois = new JFrame(); FrameDois.setTitle("Frame Dois"); FrameDois.setSize(200,100); FrameDois.setLocation(350,230); JPanel painelFDois = new JPanel(); painelFDois.setLayout(new BorderLayout()); JButton Fecha = new JButton("Fechar"); painelFDois.add(Fecha,"South"); Container P = FrameDois.getContentPane(); P.add(painelFDois); Fecha.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FrameDois.dispose(); } }); FrameDois.show();

Page 84: Programação Visual em Java

84

} } public static void main(String args[]) { VariosFrames fr = new VariosFrames(); fr.setVisible(true); } } class FrameUm extends JFrame implements ActionListe ner { private JButton Fecha; 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); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() == Fecha) { dispose(); } } }

Figura 3.25. Aplicação normal com criação de outros frames

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

Page 85: Programação Visual em Java

85

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.

O segundo botão (abreFrameDois ) também cria uma instância de um frame, chamada FrameDois , mas faz isso internamente, sem criar uma classe a parte. Dependendo da complexidade do frame, isso pode ser um pouco complicado de se fazer, ou pelo menos, o código fica um pouco mais confuso. Talvez seja uma melhor idéia construir uma classe para cada frame a ser criado.

Como as duas instâncias de frame foram criadas dentro do frame principal, no momento que este for finalizado, automaticamente os outros frames também serão.

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 class TabelaFormaUm extends JFrame implement s ActionListener { private JButton BSair; public TabelaFormaUm() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){Sys tem.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", n ew Float(30)}, {"14.055", "Forno microondas", new F loat(15)}, {"08.078", "DVD portátil", new Float (85)}, {"05.150", "Freezer vertical", new F loat(25)}, {"10.004", "Aparelho de Som 300W", n ew Float(60)}}; JTable tabela = new JTable(linhas, colunas); JScrollPane rolagemTabela = new JScrollPane(tab ela);

Page 86: Programação Visual em Java

86

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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == BSair) { System.exit(0); } } public static void main(String args[]) { TabelaFormaUm fr = new TabelaFormaUm(); fr.setVisible(true); } }

Figura 3.26. Uma tabela simples

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.

Page 87: Programação Visual em Java

87

Na execução, algumas características são pré-definidas, como:

• cabeçalhos das colunas formatados automaticamente.

• largura das colunas distribuídas igualmente.

• 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.

• redimensionamento das colunas, bastando posicionar o cursor na linha separatória de duas colunas, no cabeçalho, e arrastar para o local desejado.

• seleção de linhas, permitindo a seleção de múltiplas linhas, com a tecla Shift , e de linhas intercaladas, com a tecla Ctrl .

• no caso de existência de barras de rolagem, apenas os dados da tabela são movimentados, permanecendo o cabeçalho em seu lugar de origem.

• 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.

3.13.1 Modelos de Tabela

Apesar de fácil de ser criada, geralmente a maneira apresentada no primeiro exemplo não é a mais indicada para criação de tabelas. Para que se possa ter maior controle sobre a tabela, é necessário criar um modelo de tabela, que se responsabilizará em manipular os dados. Tais modelos são implementados pela interface TableModel (AbstractTableModel e DefaultTableModel ). O exemplo a seguir cria uma tabela com características particulares, baseado no DefaultTableModel . import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; public class TabelaFormaDois extends JFrame impleme nts ActionListener { private JButton btnExcluir; private JButton btnIncluir; private JButton btnMostrar; private JTextField texto; private JTable tabela; private int incCod = 0; public TabelaFormaDois() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){S ystem.exit(0);}}); setTitle("Tabela - Forma Dois"); setSize(430,250); setLocation(100,50); Container P = getContentPane(); P.setLayout(new BorderLayout());

Page 88: Programação Visual em Java

88

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", "A tivo" } )); tabela.getColumnModel().getColumn(0).setPreferr edWidth(20); tabela.getColumnModel().getColumn(0).setResizab le(false); tabela.getColumnModel().getColumn(1).setPreferr edWidth(150); tabela.getColumnModel().getColumn(1).setResizab le(true); tabela.getColumnModel().getColumn(2).setPreferr edWidth(150); tabela.getColumnModel().getColumn(2).setResizab le(true); tabela.getColumnModel().getColumn(3).setPreferr edWidth(60); tabela.getColumnModel().getColumn(3).setResizab le(true); tabela.getColumn(tabela.getColumnName(4)).setCe llEditor (new DefaultCe llEditor(cbAtivo)); tabela.getColumnModel().getColumn(4).setPreferr edWidth(50); tabela.getColumnModel().getColumn(4).setResizab le(true); tabela.getTableHeader().setReorderingAllowed(fa lse); tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF ); JScrollPane rolagemTabela = new JScrollPane(tab ela); 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == btnIncluir) { DefaultTableModel dtm = (DefaultTableModel)ta bela.getModel(); dtm.addRow(new Object[]{ new Integer(++incCod), "Cliente " + incCod, "Endereço " + incCod, new Double(999.99), "Sim" }); } if (origem == btnExcluir) {

Page 89: Programação Visual em Java

89

int linhas[] = tabela.getSelectedRows(); DefaultTableModel dtm = (DefaultTableModel)ta bela.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).to String()); } } public static void main(String args[]) { TabelaFormaDois fr = new TabelaFormaDois(); fr.setVisible(true); } }

Figura 3.27. Uma tabela baseada no DefaultTableMode l

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() .

As colunas deixaram de ser passíveis de reorganização a partir do método setReorderingAllowed() , setado para false. O método setAutoResizeMode() configura o modo de redimensionamento automático das colunas da tabela, sendo que o AUTO_RESIZE_OFF desliga esse redimensionamento. Os outros modos existentes são:

Page 90: Programação Visual em Java

90

• AUTO_RESIZE_NEXT_COLUMN: redimensiona apenas a próxima coluna.

• AUTO_RESIZE_SUBSEQUENT_COLUMNS: redimensiona todas as colunas subseqüentes, sendo o padrão.

• AUTO_RESIZE_LAST_COLUMN: redimensiona apenas a última coluna.

• AUTO_RESIZE_ALL_COLUMNS: redimensiona todas as colunas da tabela.

Após, a tabela é inserida em um JScrollPane , para perimitir a existência de barras de rolagem, e este, por fim, é inserido no contêiner.

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 .

• public int getRowCount() : retorna o número de linhas da tabela.

• public int getColumnCount() : retorna o número de colunas da tabela.

A classe criada é o próprio modelo da tabela e os métodos apresentados devem ser implementados, obrigatoriamente. Muitos outros métodos existem, e eles podem ser sobrepostos para realizar as ações desejadas para a tabela específica. Por exemplo, o método getColumnName() atribuirá os nomes A, B, C, etc. aos nomes das colunas, a não ser que ele seja sobreposto para que atribua nomes significativos.

Assim, é necessário sobrepor os métodos existentes na classe AbstractTableModel da melhor forma possível, para que atenda às necessidades do modelo específico da tabela que será implementada. Na verdade, uma vez tendo o modelo bem elaborado, é possível utiliza-lo na criação de várias tabelas. O código a seguir implementa várias sobreposições de métodos para exemplificar a criação de um modelo e de uma tabela baseada nesse modelo. import javax.swing.*; import javax.swing.table.*;

Page 91: Programação Visual em Java

91

import java.awt.*; import java.awt.event.*; import java.util.*; public class TabelaFormaTres extends JFrame impleme nts ActionListener { private JButton btnExcluir; private JButton btnIncluir; private JButton btnMostrar; private JButton btnAlterar; private JButton btnMostrarClasse; private JTextField texto; private JTable tabela; private int incCod = 0; private ModeloTabela modelo; public TabelaFormaTres() { addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){S ystem.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 p ara inserção // dinâmica de objetos ArrayList dados = new ArrayList(); // criação de um arranjo para os títulos no cab eç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, t rue}; // 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 ModeloTa bela modelo = new ModeloTabela(dados, colunas, edica o); tabela = new JTable(modelo); tabela.getColumnModel().getColumn(0).setPreferr edWidth(50); tabela.getColumnModel().getColumn(0).setResizab le(false); tabela.getColumnModel().getColumn(1).setPreferr edWidth(200); tabela.getColumnModel().getColumn(1).setResizab le(true); tabela.getColumnModel().getColumn(2).setPreferr edWidth(200); tabela.getColumnModel().getColumn(2).setResizab le(true); tabela.getColumnModel().getColumn(3).setPreferr edWidth(80); tabela.getColumnModel().getColumn(3).setResizab le(true); tabela.getColumnModel().getColumn(4).setPreferr edWidth(55); tabela.getColumnModel().getColumn(4).setResizab le(true); tabela.getTableHeader().setReorderingAllowed(fa lse); tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF ); tabela.setSelectionMode(ListSelectionModel.SING LE_SELECTION);

Page 92: Programação Visual em Java

92

JScrollPane rolagemTabela = new JScrollPane(tab ela); 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == btnIncluir) { modelo.addRow(new Object[]{ new Integer(++incCod), "Cliente " + incCod, "Endereço " + incCod, new Double(999.99), new Boolean(true) }); } if (origem == btnExcluir) { modelo.removeRow(tabela.getSelectedRow()); } if (origem == btnMostrar) { if (tabela.getSelectedRow()>=0) texto.setText(modelo.getValueAt(tabela.getS electedRow(), tabela.getSelectedColumn()).toString ()); } if (origem == btnAlterar) { if (tabela.getSelectedRow()>=0) modelo.setValueAt(texto.getText(),tabela.getSelec tedRow(), tabela.getSelectedColumn()); } if (origem == btnMostrarClasse) { if (tabela.getSelectedRow()>=0) texto.setText(modelo.getColumnClass(

Page 93: Programação Visual em Java

93

tabela.getSelectedColu mn()).toString()); } } public static void main(String args[]) { TabelaFormaTres fr = new TabelaFormaTres(); fr.setVisible(true); } } class ModeloTabela extends AbstractTableModel { private ArrayList linhas = null; private String[] colunas = null; private boolean[] colEditavel; public ModeloTabela(ArrayList lin, String[] col, boolean[] editavel) { setLinhas(lin); setColunas(col); colEditavel = editavel; } public ArrayList getLinhas() { return linhas; } public void setLinhas(ArrayList dados) { linhas = dados; } public String[] getColunas() { return colunas; } public void setColunas(String[] nomes) { colunas = nomes; } public int getColumnCount() { return colunas.length; } public int getRowCount() { return linhas.size(); } public String getColumnName(int numCol) { return colunas[numCol];

Page 94: Programação Visual em Java

94

} public boolean isCellEditable(int numCol) { return colEditavel[numCol]; } public Object getValueAt(int numLin, int numCol) { Object[] linha = (Object[])getLinhas().get(numL in); return linha[numCol]; } public void setValueAt(Object dado, int numLin, i nt numCol) { if (isCellEditable(numCol)) { Object[] linha = (Object[])getLinhas().get(nu mLin); linha[numCol] = dado; fireTableDataChanged(); } } public void addRow(Object[] dados) { getLinhas().add(dados); fireTableDataChanged(); } public void removeRow(int numLin) { getLinhas().remove(numLin); fireTableDataChanged(); } public Class getColumnClass(int numCol) { Object[] linha = (Object[])getLinhas().get(0); return linha[numCol].getClass(); } }

Page 95: Programação Visual em Java

95

Figura 3.28. Uma tabela baseada no modelo criado a partir do AbstractTableModel

Antes de tudo, é importante entender a classe ModeloTabela , que é derivada de AbstractTableModel . O conteúdo das linhas é armazenado em um objeto linhas , do tipo ArrayList . Um ArrayList permite armazenar qualquer tipo de objeto de uma forma dinâmica, ou seja, não é necessário determinar o tamanho dele na sua declaração. Assim, será possível inserir ou excluir linhas a qualquer momento.

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:

• public void setLinhas(ArrayList dados) : alimenta o arranjo das linhas

• public ArrayList getLinhas() : retorna o arranjo das linhas.

• public void setColunas(String[] nomes) : alimenta o arranjo das colunas.

• public String[] getColunas() : retorna o arranjo das colunas.

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:

Page 96: Programação Visual em Java

96

• public boolean isCellEditable(int numCol) : retorna true se a coluna numCol for editável, e false , caso contrário.

• public Object getValueAt(int numLin, int numCol) : Implementação obrigatória. Obtém o valor contido na célula de coordenadas numLin , numCol .

• public void setValueAt(Object dado, int numLin, int numCol) : define um novo valor para a célula de coordenadas numLin , numCol , se esta for editável (testado a partir do método isCellEditable() ). Percebe-se que, após inserido o objeto na célula, é invocado o método fireTableDataChanged() , que tem a função de realizar a efetiva alteração dos dados da tabela.

• public void addRow(Object[] dados) : inclui uma linha na tabela a partir de um arranjo de objetos.

• public void removeRow(int numLin) : exclui a linha numLin da tabela.

• public Class getColumnClass(int numCol) : retorna a classe do objeto contido na coluna numCol .

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() .

Adicionalmente, o setSelectionMode() determina que só é possível selecionar uma linha por vez (SINGLE_SELECTION). Os outros dois valores possíveis são: MULTIPLE_INTERVAL_SELECTION, que permite a seleção de uma ou mais linhas, de forma contígua ou não, e; SINGLE_INTERVAL_SELECTION, que permite a seleção de uma ou mais linhas, desde que seja de forma contígua.

A tabela criada é, então, jogada em um JScrollPane e esse no contêiner. Após, os botões Incluir , Excluir , Mostrar , Alterar e Classe são inseridos, além do JTextField texto . As ações desses botões foram implementadas no ActionPerformed :

• Incluir : utiliza o método addRow() do modelo para incluir uma nova linha no final da tabela.

Page 97: Programação Visual em Java

97

• 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.

• Alterar : Se houver linha selecionada, o conteúdo da célula selecionada é alterado pelo valor contido no campo texto , a partir do método setValueAt() .

• Classe : utiliza o método getSelectedColumn() para capturar a classe da célula selecionada, mostrando no campo texto .

3. Banco de Dados: Conectividade Utilizando JDBC

A pa import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.sql.*; import javax.swing.border.*; public class CriaTabelas extends JFrame implements ActionListener { private JButton btnExcluir; private JButton btnIncluir; private JButton btnLimpar; private JButton btnConectar; private JButton btnDesconectar; private JButton btnCriar; private JTextField nomeCampo; private JTextField tipoCampo; private JTextField fonteDados; private JTextField usuario; private JPasswordField senha; private JTextField nomeTabela; private JList lista; private Vector campos; private JLabel lblCon; private Connection con; private String chavePrimaria; 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();

Page 98: Programação Visual em Java

98

// 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.SINGL E_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);

Page 99: Programação Visual em Java

99

P.add(PSul, "South"); btnExcluir.addActionListener(this); btnIncluir.addActionListener(this); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == btnConectar) { String sFonte = "jdbc:odbc:" + fonteDados.get Text().trim(); String sUsuario = usuario.getText().trim(); String sSenha = senha.getText().trim(); try { System.setProperty("jdbc.drivers","sun.jdbc .odbc.JdbcOdbcDriver"); con = DriverManager.getConnection(sFonte, s Usuario, sSenha); JOptionPane.showMessageDialog(this, "Banco conectado com sucesso!", "Mensagem", JOptionPane.WARNING_MESSAGE ); lblCon.setText("Conectado"); }catch (SQLException eSQL) { // exceções de SQL eSQL.printStackTrace(); JOptionPane.showMessageDialog(this, "Falha na conexão com o banco!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); }catch (Exception e) { // demais exceções e.printStackTrace(); JOptionPane.showMessageDialog(this, "Falha na conexão com o banco!\n" + "Mensagem: " + e.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } } if (origem == btnDesconectar) { try { con.close(); lblCon.setText("Desconectado"); }catch (SQLException eSQL) { // exceções de SQL eSQL.printStackTrace(); JOptionPane.showMessageDialog(this, "Não foi possível desconectar o ban co!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } } if (origem == btnIncluir) { String item = nomeCampo.getText() + " " + tip oCampo.getText(); if (campos.isEmpty()) { JOptionPane.showMessageDialog(this, "O primeiro campo será a chave prim ária da tabela",

Page 100: Programação Visual em Java

100

"Mensagem", JOptionPane.WARNING_MESS AGE); chavePrimaria = nomeCampo.getText(); } campos.addElement(item); lista.setListData(campos); } if (origem == btnExcluir) { if (lista.getSelectedIndex()>= 0) { campos.removeElementAt(lista.getSelectedInd ex()); 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); } } } public static void main(String args[]) { CriaTabelas fr = new CriaTabelas(); fr.setVisible(true); } }

Page 101: Programação Visual em Java

101

A

import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.sql.*; import java.util.*; import javax.swing.table.*; public class Consulta extends JFrame implements Act ionListener { private JButton btnSair; private JButton btnPesqNome; private JButton btnPesqCod; private JTextField nome; private JTextField codigo; private Connection con; private ModeloTabelaBD modelo; private JTable tabela; private Statement sentenca; private ResultSet registros; 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();

Page 102: Programação Visual em Java

102

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 d e objetos ArrayList dados = new ArrayList(); // criação de um array para os títulos no cabeç alho String[] colunas = new String[] { "Código", "No me", "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 Clien tes 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_MES SAGE); } else do { dados.add(new Object[]{ new Integer(Integer.parseInt(registros.getStr ing("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 ModeloTa belaBD modelo = new ModeloTabelaBD(dados, colunas, edi cao); tabela = new JTable(modelo); tabela.getColumnModel().getColumn(0).setPreferr edWidth(50);

Page 103: Programação Visual em Java

103

tabela.getColumnModel().getColumn(0).setResizab le(false); tabela.getColumnModel().getColumn(1).setPreferr edWidth(200); tabela.getColumnModel().getColumn(1).setResizab le(true); tabela.getColumnModel().getColumn(2).setPreferr edWidth(240); tabela.getColumnModel().getColumn(2).setResizab le(true); tabela.getTableHeader().setReorderingAllowed(fa lse); tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF ); tabela.setSelectionMode(ListSelectionModel.SING LE_SELECTION); JScrollPane rolagemTabela = new JScrollPane(tab ela); 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == btnPesqNome) { Selecao("SELECT * FROM Clientes WHERE NOME LI KE '%" + nome.getText() + "%' ORDER BY NOME"); } if (origem == btnPesqCod) { Selecao("SELECT * FROM Clientes WHERE CODIGO = " + codigo.getText() + " ORDER BY CODIGO" ); } 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 ban co!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } } } public void Selecao(String sentencaSQL) { // apaga todas as linhas da tabela for (int i= modelo.getRowCount()-1; i >= 0; i-- ) modelo.removeRow(i); try { sentenca = con.createStatement(); registros = sentenca.executeQuery(sentencaSQL ); boolean proximoRegistro = registros.next(); if (!proximoRegistro)

Page 104: Programação Visual em Java

104

{ JOptionPane.showMessageDialog(this, "Nenhum registro foi encontrado!", "Mensagem", JOptionPane.WARNING_MES SAGE); } 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); } } public Connection conectaBanco(String sFonte,Stri ng sUsuario,String sSenha) { Connection conexao = null; try { System.setProperty("jdbc.drivers","sun.jdbc.o dbc.JdbcOdbcDriver"); conexao = DriverManager.getConnection(sFonte, sUsuario, sSenha); }catch (SQLException eSQL) { // exceções de SQL eSQL.printStackTrace(); JOptionPane.showMessageDialog(this, "Falha na conexão com o banco!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); }catch (Exception e) { // demais exceções e.printStackTrace(); JOptionPane.showMessageDialog(this, "Falha na conexão com o banco!\n" + "Mensagem: " + e.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } return conexao; } public static void main(String args[]) { Consulta fr = new Consulta(); fr.setVisible(true); } } class ModeloTabelaBD extends AbstractTableModel { private ArrayList linhas = null;

Page 105: Programação Visual em Java

105

private String[] colunas = null; private boolean[] colEditavel; public ModeloTabelaBD(ArrayList lin, String[] col , boolean[] editavel) { setLinhas(lin); setColunas(col); colEditavel = editavel; } public ArrayList getLinhas() { return linhas; } public void setLinhas(ArrayList dados) { linhas = dados; } public String[] getColunas() { return colunas; } public void setColunas(String[] nomes) { colunas = nomes; } public int getColumnCount() { return colunas.length; } public int getRowCount() { return linhas.size(); } public String getColumnName(int numCol) { return colunas[numCol]; } public boolean isCellEditable(int numCol) { return colEditavel[numCol]; } public Object getValueAt(int numLin, int numCol) { Object[] linha = (Object[])getLinhas().get(numL in); return linha[numCol]; } public void setValueAt(Object dado, int numLin, i nt numCol)

Page 106: Programação Visual em Java

106

{ if (isCellEditable(numCol)) { Object[] linha = (Object[])getLinhas().get(nu mLin); linha[numCol] = dado; fireTableDataChanged(); } } public void addRow(Object[] dados) { getLinhas().add(dados); fireTableDataChanged(); } public void removeRow(int numLin) { getLinhas().remove(numLin); fireTableDataChanged(); } public Class getColumnClass(int numCol) { Object[] linha = (Object[])getLinhas().get(0); return linha[numCol].getClass(); } }

D

D import javax.swing.*; import java.awt.*;

Page 107: Programação Visual em Java

107

import java.awt.event.*; import java.sql.*; import java.util.*; import javax.swing.table.*; public class Cadastro extends JFrame implements Act ionListener { private JButton btnSair; private JButton btnIncluir; private JButton btnAlterar; private JButton btnExcluir; private JButton btnPesqNome; private JTextField nome; private Connection con; private ModeloTabelaBD modelo; private JTable tabela; private Statement sentenca; private ResultSet registros; 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 d e objetos ArrayList dados = new ArrayList(); // criação de um array para os títulos no cabeç alho String[] colunas = new String[] { "Código", "No me", "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 ModeloTa belaBD modelo = new ModeloTabelaBD(dados, colunas, edi cao); tabela = new JTable(modelo); tabela.getColumnModel().getColumn(0).setPreferr edWidth(50); tabela.getColumnModel().getColumn(0).setResizab le(false); tabela.getColumnModel().getColumn(1).setPreferr edWidth(200); tabela.getColumnModel().getColumn(1).setResizab le(true); tabela.getColumnModel().getColumn(2).setPreferr edWidth(240); tabela.getColumnModel().getColumn(2).setResizab le(true); tabela.getTableHeader().setReorderingAllowed(fa lse);

Page 108: Programação Visual em Java

108

tabela.setAutoResizeMode(JTable.AUTO_RESIZE_OFF ); tabela.setSelectionMode(ListSelectionModel.SING LE_SELECTION); JScrollPane rolagemTabela = new JScrollPane(tab ela); 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); } public void actionPerformed(ActionEvent evt) { Object origem = evt.getSource(); if (origem == btnPesqNome) { Selecao("SELECT * FROM Clientes WHERE NOME LI KE '%" + nome.getText() + "%' ORDER BY NOME"); } if (origem == btnIncluir) { FrameCadastro frame = new FrameCadastro(con, null, null, null, 'I'); frame.show(); } if (origem == btnAlterar) { if (tabela.getSelectedRow()>=0) { FrameCadastro frame = new FrameCadastro(con , modelo.getValueAt(tabela.getSelectedRow() ,0).toString(), modelo.getValueAt(tabela.getSelectedRow(),1 ).toString(), modelo.getValueAt(tabela.getSelectedRow(),2 ).toString(), 'A'); frame.show(); } else JOptionPane.showMessageDialog(this, "Não existe registro selecionado!\n ", "Mensagem", JOptionPane.WARNING_MES SAGE); } if (origem == btnExcluir) { try { if (JOptionPane.showConfirmDialog(null,"Conf irma Exclusão?", "Confirmação", JOptionPane.YES_NO_OPT ION, JOptionPane.WARNING_MESSAGE) == 0) { sentenca = con.createStatement();

Page 109: Programação Visual em Java

109

String sentencaSQL ="DELETE FROM Clientes WHE RE Codigo= " + modelo.getValueAt(tabela.getSelectedRow(),0 ).toString(); sentenca.executeUpdate(sentencaSQL); sentenca.close(); Selecao("SELECT * FROM Clientes WHERE NOM E LIKE '%" + nome.getText() + "%' ORDER BY NOM E"); } }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 ban co!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } } } public void Selecao(String sentencaSQL) { // apaga todas as linhas da tabela for (int i= modelo.getRowCount()-1; i >= 0; i-- ) modelo.removeRow(i); try { sentenca = con.createStatement(); registros = sentenca.executeQuery(sentencaSQL ); boolean proximoRegistro = registros.next(); if (!proximoRegistro) { JOptionPane.showMessageDialog(this, "Nenhum registro foi encontrado!", "Mensagem", JOptionPane.WARNING_MES SAGE); } 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();

Page 110: Programação Visual em Java

110

JOptionPane.showMessageDialog(this, "Não foi possível carregar os dados!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } } public Connection conectaBanco(String sFonte,Stri ng sUsuario,String sSenha) { Connection conexao = null; try { System.setProperty("jdbc.drivers","sun.jdbc.o dbc.JdbcOdbcDriver"); conexao = DriverManager.getConnection(sFonte, sUsuario, sSenha); }catch (SQLException eSQL) { // exceções de SQL eSQL.printStackTrace(); JOptionPane.showMessageDialog(this, "Falha na conexão com o banco!\n" + "Mensagem: " + eSQL.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); }catch (Exception e) { // demais exceções e.printStackTrace(); JOptionPane.showMessageDialog(this, "Falha na conexão com o banco!\n" + "Mensagem: " + e.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } return conexao; } public static void main(String args[]) { Cadastro fr = new Cadastro(); fr.setVisible(true); } } class FrameCadastro extends JFrame implements Actio nListener { private JButton OK; private JButton Cancelar; private JTextField txtCodigo; private JTextField txtNome; private JTextField txtEndereco; private Connection conexao; private char TipoOperacao; public FrameCadastro(Connection con, String Cod, String Nome, String Endereco, char Tipo) { conexao = con; TipoOperacao = Tipo; setSize(250,140); setLocation(220,190); Container P = getContentPane(); JPanel painelFC = new JPanel();

Page 111: Programação Visual em Java

111

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"); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() == OK) { if (txtCodigo.getText().trim().equals("") || txtNome.getText().trim().equals("")) { JOptionPane.showMessageDialog(this, "Campos Código e Nome devem ser preenchid os!\n", "Erro", JOptionPane.ERROR_MESSAGE); } else { try { Statement sentenca = conexao.createStatement(); String sentencaSQL = null; if (TipoOperacao == 'I') sentencaSQL = "INSERT INTO Clientes (" + "Codigo, Nome, Endereco) "+ "VALUES ("+ Integer.parseInt(txtCodigo.getText())+", '"+ txtNome.getText() + "', '" + txtEndereco.getText()+"')"; else sentencaSQL = "UPDATE Clientes SET Nome = '" + txtNome.getText() + "', Endereco = '" + txtEndereco.getText()+"' WHERE Codigo = " + Integer.parseInt(txtCodigo.getText());

Page 112: Programação Visual em Java

112

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.

Page 113: Programação Visual em Java

113

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

Page 114: Programação Visual em Java

114

Bibliografia Cesta, André Augusto. Tutorial: “A Linguagem de Programação JAVA”. Instituto de

Computação. UNICAMP, 1996. Disponível em http://www.dcc.unicamp.br

Davis, Stephen R. Aprenda Java agora. 2.ed. Rio de Janeiro : Campus, 1997. 401p.

Deitel, Harvey M. Java : como programar. 3.ed. Porto Alegre : Bookman, 2001. 1201p.

Flanagan, David. Java : o guia essencial. Rio de Janeiro : Campus, 2000. 718 p.

Lemay, Laura; Cadenhead, Rogers. Aprenda em 21 dias Java 2. Rio de Janeiro : Campus, 1999. 661p.

Schützer, Waldeck; Massago, Sadao. Programação Java. Departamento de Matemática Universidade Federal de São Carlos – UFSCar. 1999. Disponível em: http://www2.dm.ufscar.br/~waldeck/curso/java/

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.