You are on page 1of 195

Java Avançado com acesso JDBC a

Banco de Dados, Arquivos, Swing e


Eventos
Java Avançado

Sumário

1. Frameworks para interfaces gráficas...........................1


Objetivos.....................................................................................2
Abstract Window Toolkit (AWT) ..................................................3
Swing..........................................................................................4
Exercícios....................................................................................7

2. Gerenciadores de Layout............................................1
Objetivos.....................................................................................2
Introdução...................................................................................3
FlowLayout..................................................................................4
BorderLayout..............................................................................6
GridLayout..................................................................................9
Exercícios..................................................................................11

3. Tratamento de Eventos....................... ......................13


Objetivos...................................................................................14
Listeners...................................................................................15
Formas de Tratamento de Eventos...........................................16
Eventos de Mouse.....................................................................23
Exercícios..................................................................................36

4. Componentes para Interface Gráfica...........................1


Objetivos.....................................................................................2
JFrame.........................................................................................3
JLabel..........................................................................................6
JButton........................................................................................9
JTextField e JPasswordField........................................................12
JTextArea...................................................................................16
JPanel........................................................................................19
JComboBox................................................................................21
Construindo Menus...................................................................24
Entendendo as Caixas de Diálogo.............................................36
JOptionPane..............................................................................37
JTable........................................................................................41
JScrollPane................................................................................44
JFileChooser..............................................................................46
Exercícios..................................................................................48

5. Look And Feel...................... ......................................1


Objetivos....................................................................................2
Aparência e Comportamento......................................................3
Exercícios....................................................................................6

6. Arquivos................................................. ...................1
I
Frameworks para interfaces gráficas

Objetivos.....................................................................................2
Introdução...................................................................................3
Hierarquia de Dados...................................................................4
Arquivos e Fluxos........................................................................7
Testando Arquivos.....................................................................13
Criando um Arquivo..................................................................16
Lendo Dados de um Arquivo.....................................................25
Gerenciamento de memória: Garbage Collector ......................34
Exercícios..................................................................................35

7. Acesso a Banco de Dados....................................... .....1


Objetivos.....................................................................................1
Introdução...................................................................................2
JDBC Drivers................................................................................3
Aplicação vs JDBC Driver............................................................7
JDBC URLs...................................................................................8
Server Side Driver.....................................................................11
Acessando Bases de Dados por JDBC.......................................12
Etapa 1: Connect......................................................................13
Etapa 2: Query..........................................................................16
Etapa 3: Process results............................................................20
Etapa 4: Close...........................................................................23
MetaData..................................................................................26
Tipo de Dados...........................................................................27
Resumo Tecnologia JDBC ..........................................................28
Acessando Bases de Dados com JDBC......................................29
Registrando Fonte de Dados de ODBC......................................35
Manipulando Banco de Dados com ODBC.................................37
Processamento de Transações..................................................48
Exercícios..................................................................................49

II
1.Frameworks para
interfaces gráficas

1
Frameworks para interfaces gráficas

Objetivos
• Conhecer os diferentes frameworks existentes para construção de
interfaces gráficas
• Enteder as relações e a evolução destes frameworks
• Conhecer as diferenças entre estes frameworks

2
Frameworks para interfaces gráficas

Abstract Window Toolkit (AWT)

O framework AWT (Abstract Window Toolkit – pacote java.awt) foi a


primeira interface gráfica moderna e difundida para a linguagem Java.

Tendo como características possuir componentes de “peso pesado”, ou


seja, componente que estão associados diretamente a capacidade da
plataforma local apresenta como problema principal as diferenças de interação
com o usuário sensitivas a plataforma.

Este framework serviu de “base” para a construção do Swing que utiliza


alguns de seus recursos. Atualmente este pacote é utilizado para completar
partes que não foram re-escritas em Swing.

Em todo programa Swing sempre haverá alguma classe AWT sendo


utilizada pois existem eventos e componentes que não foram re-
implementados no Swing pelo AWT já atender as necessidades.

3
Frameworks para interfaces gráficas

Swing

As classes que são utilizadas para criar os componentes são parte dos
componentes GUI do Swing do pacote javax.swing. Esses são os mais novos
componentes GUI da plataforma do Java 2.

DICA: Uma forma fácil de diferenciar classes Swing de classes AWT é pelo
seu prefixo, todas classes Swing inicial com a letra “J”.

Os componentes Swing (como são comumente denominados) são escritos,


manipulados e exibidos completamente em Java (chamados componentes Java
puros).

Os componentes GUI originais do pacote java.awt (Abstract Windowing


Toolkit - também chamado de AWT) estão diretamente associados com as
capacidades de GUI da plataforma local. Então, um programa Java executando
em diferentes plataformas Java tem uma aparência diferente e, às vezes, até
diferentes interações de usuário em cada plataforma. Juntos, o aspecto e a
maneira como o usuário interage com o programa são conhecidos como
aparência e comportamento ("look and feel") desse programa.

Os componentes do Swing permitem ao programador especificar uma


aparência e um comportamento diferente para cada plataforma, ou uma
aparência e um comportamento uniforme entre todas as plataformas, ou até
mesmo alterar a aparência e comportamento enquanto o programa está
executando.

Os componentes Swing são freqüentemente referidos como componentes


de peso leve - são completamente escritos em Java de modo a não "serem
pesados" pelas complexas capacidades GUI da plataforma em que são
utilizados.

Os componentes AWT (muitos dos quais são equivalentes dos


componentes Swing) que são vinculados à plataforma local são
correspondentemente chamados de componentes de peso pesado - contam
com o sistema de janela da plataforma local para determinar sua
funcionalidade e sua aparência e comportamento.

Cada componente de peso pesado tem um "peer" (um equivalente do


pacote java.awt.peer) que é responsável pelas interações entre o componente
e a plataforma local para exibir e manipular o componente. Vários
componentes Swing ainda são componentes de peso pesado.

Em particular, as subclasses de java.awt.Window que exibem janelas na


tela ainda requer em interação direta com o sistema local de janelas.

A hierarquia de herança das classes que define atributos e


comportamentos que são comuns para a maioria dos componentes Swing.

4
Frameworks para interfaces gráficas

java.lang.Object

java.awt.Component

java.awt.Container

javax.swing.JComponent

Cada classe é exibida com o nome de seu pacote e nome de classe


completamente qualificado. Grande parte da funcionalidade de cada
componente GUI é derivada dessas classes.

Uma classe que herda da classe Component é um componente. Por


exemplo, a classe Container herda da classe Component e a classe Component
herda de Object. Portanto, um Container é um Component e um Object, e um
Component é um Object.

Uma classe que herda da classe Container é um Container. Portanto, um


JComponent é um Container.

A classe Component define os métodos que podem ser aplicados a um


objeto de qualquer subclasse de Component. Dois dos métodos que se
originam na classe Component são paint e repaint.

É importante entender os métodos de classe Component, porque grande


parte da funcionalidade herdada por cada subclasse de Component é definida
originalmente pela classe Component. As operações comuns para a maioria
dos componentes GUI (tanto Swing como AWT) estão localizadas na classe
Component.

Um Container é uma coleção de componentes relacionados. Em


aplicativos com JFrames e em Applets, anexamos os componentes ao painel de
conteúdo - um Container. A classe Container define o conjunto de métodos que
podem ser aplicados a um objeto de qualquer subclasse de Container.

Um método que se origina na classe Container é add. Outro método que


origina na classe Container é setLayout, que é utilizado para especificar o
gerenciador de layout que ajudam um Container a posicionar e dimensionar
seus componentes.

A classe JComponent é a superclasse para a maioria dos componentes


Swing. Essa classe define o conjunto de métodos que pode ser aplicado a um
objeto de qualquer subclasse de JComponent.

Os componentes Swing que derivam da subclasse JComponent têm muitos


recursos, incluindo:

5
Frameworks para interfaces gráficas

• Uma aparência e um comportamento plugável, que podem ser


utilizados para personalizar a aparência e o comportamento quando o
programa executa em plataformas diferentes.

• Teclas de atalho (chamadas de mnemónicas) para acesso direto a


componentes GUI pelo teclado.

• Capacidades comuns de tratamento de eventos para casos onde vários


componentes GUI iniciam as mesmas ações em um programa.

• Breves descrições do propósito de um componente GUI (chamadas de


dicas de ferramenta). Elas são exibidas quando o cursor de mouse é
posicionado sobre o componente por um breve instante.

• Suporte a tecnologias de auxilio ao deficiente físico como leitores de


tela de braile para pessoas cegas.

• Suporte para localização de interface com o usuário - personalizando a


interface com o usuário para exibir em diferentes idiomas e
convenções culturais.

6
Frameworks para interfaces gráficas

Exercícios

1. Explique a relação existente entre Swing e AWT.

2. Qual a diferença entre componentes de “peso pesado” e componentes de


“peso leve”?

3. Como identificar facilmente pelo nome de uma classe de interface gráfica


se esta faz parte do Swing ou AWT?

7
Frameworks para interfaces gráficas

Espaço para anotações

8
2.Gerenciadores de Layout

1
Tratamento de Eventos

Objetivos
• Apresentar os principais gerenciadores de layout de interface gráfica

• BorderLayout

• FlowLayout

• GridLayout

• Discutir as principais implementações de layout

• Identifir a melhor implementação de acordo com o foco de utilização

2
Tratamento de Eventos

Introdução

Os gerenciadores de layout são fornecidos para organizar componentes


GUI em um conteiner para propósitos de apresentação. Eles fornecem
capacidades básicas de layout que são mais fáceis de utilizar do que
determinar a posição e o tamanho exatos de cada componente GUI. Isso
permite ao programador concentrar-se na “aparência e comportamento”
básicos e deixar os gerenciadores de layout processar a maioria dos detalhes
de layout.

Alguns designers de GUI também permitem ao programador utilizar os


gerenciadores de layout descritos abaixo:

Gerenciador de
Descrição
Layout
Padrão para java.awt.Applet, java.awt.Panel e
FlowLayout javax.swing.JPanel. Coloca os componentes
seqüencialmente (da esquerda para a direita) na
ordem que foram adicionados. Também é possível
especificar a ordem dos componentes utilizando o
método add de Container que aceita um Component e
uma posição de índice inteiro como argumentos.

Padrão para os painéis de conteúdo de JFrames


BorderLayout (e outras janelas) e JApplets. Organiza os
componentes em cinco áreas: Norte, Sul, Leste, Oeste
e Centro.

GridLayout Organiza os componentes nas linhas e colunas.

Tabela 2-1: Descrição dos gerenciadores de layout

A maioria dos exemplos anteriores de applet e de aplicativos em que


criamos nossa própria GUI utilizou o gerenciador de layout FlowLayout. A
classe FlowLayout herda da classe Object e implementa a interface
Layout.Manager, que define os métodos que um gerenciador de layout utiliza
para organizar e dimensionar componentes GUI em um conteiner.

3
Tratamento de Eventos

FlowLayout

FlowLayout é o gerenciador de layout mais básico. Os componentes GUI


são colocados em um conteiner da esquerda para a direita na ordem em que
são adicionados ao mesmo. Quando a borda do conteiner é alcançada, os
componentes continuam na próxima linha.

A classe FlowLayout permite aos componentes GUI ser alinhados à


esquerda, centralizados (o padrão) e alinhados à direita.

package com.targettrust.java.capitulo02;

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

public class FlowLayoutDemo extends JFrame {

private JButton left, center, right;


private Container c;
private FlowLayout layout;

public FlowLayoutDemo() {

super( "FlowLayout Demo" );


layout = new FlowLayout();
c = getContentPane();
c.setLayout( layout );

left = new JButton( "Left" );


left.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
layout.setAlignment( FlowLayout.LEFT );
layout.layoutContainer( c );
}
});
c.add( left );

center = new JButton( "Center" );


center.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
layout.setAlignment( FlowLayout.CENTER );
layout.layoutContainer( c );
}
});
c.add( center );

right = new JButton( "Right" );


right.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
layout.setAlignment( FlowLayout.RIGHT );
4
Tratamento de Eventos

layout.layoutContainer( c );
}
});
c.add( right );

setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 300, 75 );
setVisible(true);
}

public static void main( String args[] ) {


FlowLayoutDemo app = new FlowLayoutDemo();
}
}

Código 2-1: Exemplo de utilização de FlowLayout.

O aplicativo de exemplo cria três objetos JButton e os adiciona ao


aplicativo que utiliza um gerenciador de layout FlowLayout.

Os componentes são automaticamente alinhados no centro. Quando o


usuário clica em Left, o alinhamento para o gerenciador de layout é alterado
para um FlowLayout alinhado à esquerda. Quando o usuário clica em Right, o
alinhamento para o gerenciador de layout é alterado para um FlowLayout
alinhado à direita. Quando o usuário clica em Center, o alinhamento para o
gerenciador de layout é alterado para um como visto anteriormente, um layout
do container é estabelecido com o método setLayout de classe Container.

Configuramos o gerenciador de layout do painel de conteúdo como o


FlowLayout. Normalmente, o layout é configurado antes de quaisquer
componentes GUI serem adicionados a um conteiner.

Figura 2-1:Exemplo de interface construída com FlowLayout

Cada tratador de evento actionPerformed do botão executa duas


instruções. Por exemplo, o método actionPerformed para o botão left utiliza o
método FlowLayout setAlignment para alterar o alinhamento para o
FlowLayout para um FlowLayout alinhado à esquerda (FlowLayout .LEFT).

O método de interface LayoutManager layoutContainer para especificar


que o painel de conteúdo deve ser reorganizado com base no layout ajustado.
De acordo com qual botão foi clicado, o método actionPerformed para cada
botão configura o alinhamento do FlowLayout como FlowLayout.LEFT,
FlowLayout.CENTER ou FlowLayout.RIGHT.

5
Tratamento de Eventos

BorderLayout

O gerenciador de layout BorderLayout (o gerenciador de layout-padrão


para o painel de conteúdo) organiza componentes em cinco regiões: Norte,
Sul, Leste, Oeste e Centro (Norte corresponde à parte superior do container).

A classe BorderLayout herda de Object e implementa a interface


LayoutManager2 (uma subinterface de LayoutManager que adiciona vários
métodos para um processamento de layout aprimorado).

Até cinco componentes podem ser adicionados diretamente a um


BorderLayout — um para cada região. Os componentes colocados nas regiões
Norte e Sul estendem-se horizontalmente para os lados do conteiner e tem a
mesma altura que o componente mais alto colocado nessas regiões.

As regiões Leste e Oeste expandem-se verticalmente entre as regiões


Norte e Sul e tem a mesma largura que o componente mais largo colocado
nessas regiões.

O componente colocado na região Centro expande-se para tomar todo o


espaço restante no layout. Se todas as cinco regiões são ocupadas, o espaço
do container inteiro é coberto por componentes GUI. Se a região Norte ou a
região Sul não for ocupada, os componentes GUI nas regiões Leste, Centro e
Oeste expandem-se verticalmente para preencher o espaço restante.

Se a região Leste ou Oeste não for ocupada, o componente GUI na região


Centro expande-se horizontalmente para preencher o espaço restante. Se a
região Centro não for ocupada, a área é deixada vazia — os outros
componentes GUI não se expandem para preencher o espaço restante.

O aplicativo BorderLayoutDemo demonstra o gerenciador de layout


BorderLayout utilizando cinco JButtons.

package com.targettrust.java.capitulo02;

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

public class BorderLayoutDemo extends JFrame implements ActionListener {

private JButton b[];


private String names[] = {"Hide North", "Hide South", "Hide East",
"Hide West", "Hide Center"};
private BorderLayout layout;

public BorderLayoutDemo() {
super( "BorderLayout Demo" );
layout = new BorderLayout( 5, 5 );
6
Tratamento de Eventos

Container c = getContentPane();
c.setLayout( layout );
b = new JButton[ names.length ];

for ( int i = 0; i < names.length; i++ ) {


b[ i ] = new JButton( names[ i ] );
b[ i ].addActionListener( this );
}

c.add( b[ 0 ], BorderLayout.NORTH );
c.add( b[ 1 ], BorderLayout.SOUTH );
c.add( b[ 2 ], BorderLayout.EAST );
c.add( b[ 3 ], BorderLayout.WEST );
c.add( b[ 4 ], BorderLayout.CENTER );

setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

setSize( 300, 200 );


setVisible(true);
}

public void actionPerformed( ActionEvent e ) {


for ( int i = 0; i < b.length; i++ ) {
if ( e.getSource() == b[ i ] ) {
b[ i ].setVisible( false );
} else {
b[ i ].setVisible( true );
}
}
layout.layoutContainer( getContentPane() );
}

public static void main( String args[] ) {


BorderLayoutDemo app = new BorderLayoutDemo();
}
}
Código 2-2: Exemplo de utilização de BorderLayout.

No construtor de BorderLayout os argumentos especificam o número de


pixels entre componentes que são organizados horizontalmente (espaçamento
horizontal) e o número de pixels entre componentes que são organizados
verticalmente (espaçamento vertical), respectivamente.

O construtor-padrão BorderLayout fornece 0 pixel de espaçamento


horizontal e verticalmente. Utilizamos o método setLayout para configurar o
layout do painel de conteúdo como layout.

Adicionar componentes a um BorderLayout requer um método add


diferente da classe Container, que aceita dois argumentos – o Component para
adicionar e a região em que o Component será colocado. Por exemplo,
especificamos que o b[0] deve ser colocado na posição NORTE.

7
Tratamento de Eventos

Figura 2-2: Exemplo de interface com BorderLayout

Os componentes podem ser adicionados em qualquer ordem, mas apenas


um componente pode ser adicionado a cada região. Quando o usuário clica em
um JButton particular no layout, o método actionPerformed é chamado. O
comando for utiliza a seguinte estrutura condicional:

Para ocultar o JButton particular que gerou o evento. O método setVisible


(herdado em JButton da classe Component) é chamado com um argumento
“false”. Se o JButton atual no array não é o que gerou o evento, o método
setVisible é chamado com um argumento true para assegurar que o JButton é
exibido na tela.

Utilizamos o método LayoutManager layoutContainer para recalcular o


layout do painel de conteúdo. Tente redimensionar a janela de aplicativo para
ver como as várias regiões redimensionam-se baseadas na largura e altura da
janela.

8
Tratamento de Eventos

GridLayout

O gerenciador de layout GridLayout divide o container em uma grade de


modo que os componentes podem ser colocados nas linhas e colunas. A classe
GridLayout herda diretamente da classe Object e implementa a interface
LayoutManager.

Cada Component em um GridLayout tem a mesma largura e altura. Os


componentes são adicionados a um GridLayout iniciando a célula na parte
superior esquerda da grade e prosseguindo da esquerda para a direita até a
linha estar cheia. Então o processo continua da esquerda para a direita na
próxima linha da grade, e assim por diante.

Este exemplo demonstra o gerenciador de layout GridLayout utilizando


seis JButtons.

package com.targettrust.java.capitulo02;

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

public class GridLayoutDemo extends JFrame implements ActionListener {

private JButton b[];


private String names[] = { "one", "two", "three", "four", "five", "six" };
private boolean toggle = true;
private Container c;
private GridLayout grid1, grid2;

public GridLayoutDemo() {
super( "GridLayout Demo" );
grid1 = new GridLayout( 2, 3, 5, 5 );
grid2 = new GridLayout( 3, 2 );
c = getContentPane();
c.setLayout( grid1 );
b = new JButton[ names.length ];
for (int i = 0; i < names.length; i++ ) {
b[ i ] = new JButton( names[ i ] );
b[ i ].addActionListener( this );
c.add( b[ i ] );
}
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 300, 150 );
setVisible(true);
}

public void actionPerformed( ActionEvent e ) {


if ( toggle ) {
c.setLayout( grid2 );
} else {
c.setLayout( grid1 );
}

9
Tratamento de Eventos

toggle = !toggle;
c.validate();
}

public static void main( String args[] ) {


GridLayoutDemo app = new GridLayoutDemo();
}
}
Código 2-3: Exemplo de utilização de GridLayout.

Defininos dois objetos GridLayout. O construtor GridLayout utilizado


especifica um GridLayout com 2 linhas, 3 colunas, 5 pixels de espaçamento
horizontal entre os Components na grade e 5 pixels de espaçamento vertical
entre Components na grade.

O próximo construtor GridLayout especifica um GridLayout com 3 linhas, 2


colunas e nenhum espaçamento.

Figura 2-3: Exemplo de interface GridLayout

Os objetos JButton nesse exemplo sâo inicialmente organizados utilizando


grid1 (associado ao painel de conteúdo com o método setLayout). O primeiro
componente é adicionado à primeira coluna da primeira linha. O próximo
componente é adicionado à segunda coluna da primeira linha etc. Quando um
JButton é pressionado, o método actionPerformed é chamado. Cada chamada
para actionPerformed alterna o layout entre grid2 e grid1.

Redesenhos um container cujo layout foi alterado onde o método


Container validate recalcula o layout do container com base no gerenciador de
layout atual para o Container e o conjunto atual de componentes GUI exibidos.

10
Tratamento de Eventos

Exercícios

1. Quais as diferenças entre FlowLayout, BorderLayout e GridLayout?

2. Crie um tabuleiro de Xadrez utilizando os gerenciadores de Layout que


você estudou neste capítulo. Para isto veja a imagem abaixo:

11
Tratamento de Eventos

Espaço para anotações

12
Tratamento de Eventos

3.Tratamento de Eventos

13
Tratamento de Eventos

Objetivos
• Entender como podem ser tratados os eventos na linguagem java
• Conhecer as principais interfaces para tratar eventos
• Criar uma aplicação e utilizar o mecanismo de tratamento de eventos

14
Tratamento de Eventos

Listeners

Quando ocorre uma interação com o usuário, um evento é


automaticamente enviado para o programa. Informações de eventos GUI são
armazenadas em um objeto de uma classe que estende AWTEvent.

Os tipos de evento de pacote java.awt.Event são ainda utilizados com os


componentes Swing. Também foram adicionados outros tipos de evento que
são específicos para vários tipos de componentes Swing. Novos tipos de
evento de componente do Swing são definidos no pacote javax.swing.Event.

Para processar um evento de interface gráfica com o usuário, o


programador deve realizar duas tarefas principais - registrar um ouvinte de
eventos (Listener) e implementar um tratador (handler) de eventos.

Um ouvinte de eventos para um evento GUI é um objeto de uma classe


que implementa uma ou mais das interfaces ouvintes de eventos dos pacotes
java.awt.Event e javax.swing.Event.

Muitos dos tipos de ouvinte de eventos são comuns aos componentes


Swing e AWT. Esses tipos são definidos no pacote java.awt.Event. Tipos
adicionais de ouvinte de eventos que são específicos de componentes Swing
são definidos no pacote javax.swing.Event.

Um objeto ouvinte de eventos "ouve" tipos específicos de eventos gerados


no mesmo objeto ou por outros objetos (normalmente componentes GUI) em
um programa. Um tratador de eventos é um método que é automaticamente
chamado em resposta a um tipo de evento em particular. Cada interface
ouvinte de eventos especifica um ou mais métodos de tratamento de evento
que devem ser definidos na classe que implementa a interface ouvinte de
eventos.

Lembre-se de que as interfaces definem métodos abstract.

Qualquer classe que implementa uma interface deve definir todos os


métodos dessa interface; caso contrário, a classe é uma classe abstract e não
pode ser utilizada para criar objetos. O uso de ouvintes de eventos em
tratamento de eventos é conhecido como modelo de delegação de evento - o
processamento de um evento é delegado a um objeto particular no programa.

Quando um evento ocorre, o componente GUI com o qual o usuário


interagiu notifica seus ouvintes registrados chamando o método de tratamento
de evento apropriado de cada ouvinte. Por exemplo, quando o usuário
pressiona a tecla Enter em um JTextField, o método actionPerformed do
ouvinte registrado é chamado.

15
Tratamento de Eventos

Formas de Tratamento de Eventos

Já conhecendo o funcionamento dos Listener’s (conforme item anterior)


deve-se compreender de que forma capturar estes eventos através dos
ouvintes (Listeners).

Existem várias interfaces de tratamento de eventos, o objetivo deste


capítulo é explicar as formas de como trabalhar com estas interfaces e não as
interfaces propriamente ditas. Desta forma, este capítulo é baseado em uma
única interface a ActionListener, a fim de facilitar o estudo.

Todas interfaces (ActionListener, MouseListener, WindowListener,


KeyListener, MouseMotionListener) serão detalhadas no próximo capítulo

O tratamento de eventos pode ser feito através de três formas, conforme


seguem as subseções deste capítulo.

16
Tratamento de Eventos

Implementando uma interface

Esta forma de realizar o tratamento de eventos consiste em uma classe


implementar uma interface para que a mesma possa ter comportamentos que
a “habilitem” tratar determinados tipos de eventos. Isto pode ser feito pela
própria classe onde os ventos são originados ou por outra classe. Os objetos
criados a partir desta classe terão a capacidade de responder a eventos.
Existem várias interfaces que descrevem tipos de comportamentos, tais como:
ActionListener, MouseListener, WindowListener, KeyListener,
MouseMotionListener.

Estas interfaces possuem métodos abstratos que obrigatoriamente devem


ser implementados quando utilizadas, estes métodos são os responsáveis pelo
tratamento dos eventos.

Veja abaixo um exemplo de implementação de interface pela própria


classe onde os eventos são originados:

package com.targettrust.java.capitulo03;

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

public class ExemploEventos extends JFrame implements ActionListener {

public ExemploEventos() {

super( "Exemplo de tratamento de eventos" );

JButton botao = new JButton("Teste");


botao.setSize(80, 20);

getContentPane().setLayout(new FlowLayout());
getContentPane().add(botao);
botao.addActionListener(this);

setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize( 350, 200 );
setVisible( true );
}

public void actionPerformed(ActionEvent e) {


JOptionPane.showMessageDialog(getContentPane(), e.getActionCommand());
}

public static void main(String[] args) {


ExemploEventos app = new ExemploEventos();
}
}
Código 3-1: Código fonte de exemplo de tratamento de eventos.

17
Tratamento de Eventos

O programa acima exemplifica o tratamento de eventos através da


utilização de uma interface AcionListener. Ao implementer a interface action
listener é necessário utilizar o método actionPerformed() o qual recebe como
parâmetro o evento.

Além de implementer a interface ActionListener e programas o método


actionPerformed o programa realize uma achamada ao método
addActionListener do objeto botao (JButton), este é feito para registrar ao
ouvinte quais objetos devem ser tratados.

Resumindo, implementer interfaces para tartar eventos se divide em 3


passos básicos:

1. Implementar a interface

2. Implementar seus métodos abstratos

3. Definir quais objetos serão escutados, adicionando-os ao


listener.

18
Tratamento de Eventos

Delegando o tratamento a outro objeto

A segunda forma de realizar o tratamento de eventos é delegando a um


outro objeto o tratamento dos eventos, ou seja, o programa possui uma classe
com a GUI e uma outra classe apenas para tartar os eventos desta.

package com.targettrust.java.capitulo03;

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

public class DelegandoEventos extends JFrame {

public DelegandoEventos() {
setTitle("Exemplo de Tratamento de Eventos");
setSize(400, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);

JButton botao = new JButton("Sair");


botao.setSize(80, 20);

getContentPane().setLayout(new FlowLayout());
getContentPane().add(botao);
botao.addActionListener(new TratandoEventos());

setVisible(true);
}

public static void main(String[] args) {


DelegandoEventos app = new DelegandoEventos();
}
}
Código 3-2: Delegando a outro objeto o tratamento de eventos, contrução da GUI.

O programa acima cria a GUI com uma janela e um botão sair.


Observando o código nota-se a chamada ao método
botao.addActionListener(new TratandoEventos()). Este método esta delegando
a outra classe (TratandoEventos) o tratamento dos eventos sobre o botão sair.

Abaixo segue o código da classe TratandoEventos:


19
Tratamento de Eventos

package com.targettrust.java.capitulo03;

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

public class TratandoEventos implements ActionListener {


public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
Código 3-3: Tratando evento do botão sair.

Neste programa foi implementada a interface ActionListener e


implementado o método actionPerformed que esta recebendo como parâmetro
os eventos do botão sair do primeiro programa pois foi adicionado ao ouvinte.

Ao receber qualquer açaõ sobre este botão o programa realize um


System.exit(0);

20
Tratamento de Eventos

Utilizando Classes Anônimas Internas

A terceira e última forma de realizar tratamento de eventos é através de


classes anônimas internas (Anonymys Inner Class). Este modo de tratamento é
semelhante a delegar a outro objeto (veja o tópico anterior) com a diferença
de não possuir uma classe nomeada para tratar o evento, ou seja, o objeto é
criado com uma instrução “new” no proprio método addActionListener.

Resumindo, esta é uma forma mais prática de implementer o tratamento


de eventos, pois não existe a necessidade de duas classes nomeadas e
possivelmente em arquivos separados.

package com.targettrust.java.capitulo03;

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

public class ClassesAnonimas extends JFrame {


public ClassesAnonimas() {
super("Exemplo de Tratamento de Eventos");

JButton botao = new JButton("Sair");


botao.setSize(80, 20);

getContentPane().setLayout(new FlowLayout());
getContentPane().add(botao);
botao.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
System.exit(0);
}
}
);
setSize(400, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}

public static void main(String[] args) {


new ClassesAnonimas();
}
}
Código 3-4: Tratando eventos com classes anônimas internas.

Prestando atenção no método addActionListener() do objeto botão


(JButton) verifica-se que não existe a chamada a uma classe criada
anteriormente e sim a um objeto criadao dentro do método através da
instrução new.

O trecho de código “new ActionListener() { … }”, possui a mesma


funcionalidade que foi detalhada na subseção anterior deste mesmo capítulo
com a diferença de não nomear uma nova classe e sim fazer a declaração
desta no próprio método de ligação com o ouvinte.
21
Tratamento de Eventos

Interfaces para Tratamento de Eventos

O objetivo desta subseção é explicar o funcionamento de cada uma das


interfaces existentes para tratamento de eventos.

Categoria Nome da interface Adaptador Métodos

Acão ActionListener - public void actionPerformed(ActionEvent e)

Item ItemListener - public void itemStateChanged(ItemEvent e)

Movimento do mouse MouseMotionListener MouseMoutionAdapter public void mouseDragged(MouseEvent e)


public void mouseMoved(MouseEvent e)

Botão do mouse MouseListener MouseAdapter public void mousePressed(MouseEvent e)


public void mouseReleased(MouseEvent e)
public void mouseEntered(MouseEvent e)
public void mouseExited(MouseEvent e)
public void mouseClicked(MouseEvent e)

Tecla KeyListener KeyAdapter public void keyPressed(KeyEvent e)


public void keyReleased(KeyEvent e)
public void keyTyped(KeyEvent e)
Foco FocusListener FocusAdapter public void focusGained(FocusEvent e)
public void focusLost(FocusEvent e)
Ajuste AjustmentListener public void adjustmentValueChanged(AdjustmentEvent e)

Componente ComponentListener ComponentAdapter public void componentMoved(ComponentEvent e)


public void componentHidden(ComponentEvent e)
public void componentResized(ComponentEvent e)
public void componentShown(ComponentEvent e)

Janela WindowListener WindowAdapter public void windowClosing(WindowEvent e)


public void windowOpened(WindowEvent e)
public void windowIconified(WindowEvent e)
public void windowDeiconified(WindowEvent e)
public void windowClosed(WindowEvent e)
public void windowActivated(WindowEvent e)
public void windowDeactivated(WindowEvent e)

Recipiente ContainerListener ContainerAdapter public void componentRemoved(ContainerEvent e)


public void componentAdded(ContainerEvent e)

Texto TextListener - public void textValueChanged(TextEvent e)

Mouse Wheel MouseWheelListener - public void mouseWheelMoved(MouseWheelEvent e)

Estado da Janela WindowStateListener - public void windowStateChanged(WindowEvent e)

22
Tratamento de Eventos

Eventos de Mouse

Esta seção apresenta as interfaces ouvintes de eventos MouseListener e


MouseMotionListener para tratar eventos de mouse.

Os eventos de mouse podem ser capturados por qualquer componente


GUI que deriva de java.awt.Component. Os métodos de interfaces
MouseListener e MouseMotionListener são resumidos em:
• public void mousePressed( MouseEvent e ) { … }

Chamado quando um botão do mouse é pressionado com o cursor de


mouse em um componente.
• public void mouseClicked( MouseEvent e ) { … }

Chamado quando um botão do mouse é pressionado e liberado em um


componente sem mover o cursor do mouse.
• public void mouseReleased( MouseEvent e ) { … }

Chamado quando um botão do mouse é liberado depois de ser


pressionado. Esse evento sempre é precedido por uni evento mousePressed.
• public void mouseEntered( MouseEvent e ) { … }

Chamado quando o cursor do mouse entra nos limite de um componente.


• public void mouseExited( MouseEvent e ) { … }

Chamado quando o cursor do mouse deixa os limite de um componente.


• public void mouseDragged( MouseEvent e ) { … }

Chamado quando o botão do mouse é pressionado e o mouse é movido.


Esse evento é sempre precedido por uma chamada para mousePressed.
• public void mouseMoved( MouseEvent e ) {…}

Chamado quando o mouse é movido com o cursor do mouse em um


componente.

Cada um dos métodos de tratamento de eventos do mouse aceita um


objeto MouseEvent como seus argumentos. Um objeto MouseEvent contém as
informações sobre o evento de mouse que ocorreu, incluindo as coordenadas x
e y da localização onde o evento ocorreu.

23
Tratamento de Eventos

Os métodos MouseListener e MouseMotionListener são chamados


automaticamente quando o mouse interage com um Component se os objetos
ouvintes estão registrados em um Component particular. O método
mousePressed é chamado quando um botão do mouse é pressionado com o
cursor do mouse sobre um componente.

Utilizando métodos e constantes da classe InputEvent (a superclasse de


MouseEvent), um programa pode determinar em que botão do mouse o
usuário clicou.

O método mouseClicked é chamado sempre que um botão do mouse é


liberado sem mover o mouse depois de uma operação mousePressed.

O método mouseReleased é chamado sempre que um botão do mouse é


liberado.

O método mouseEntered é chamado quando o cursor do mouse entra nos


limites fisicos de um Component.

O método mouseExited é chamado quando o cursor de mouse deixa os


limites fisicos de um Component.

O método mouseDragged é chamado quando o botão do mouse é


pressionado e mantido pressionado e o mouse é movido (um processo
conhecido como arrastar). O evento mouseDragged é precedido por um evento
mousePressed e seguido por um evento mouseReleased.

O método mouseMoved é chamado quando o mouse é movido com o


cursor de mouse sobre um componente (e nenhum botão do mouse
pressionado).

O aplicativo MouseTracker demonstra os métodos MouseListener e


MouseMotionListener. A classe do aplicativo implementa as duas interfaces de
modo a poder ouvir seus próprios eventos de mouse.

Observe que todos os sete métodos dessas duas interfaces devem ser
definidos pelo programador quando uma classe implementa as duas
interfaces.

package com.targettrust.java.capitulo03;

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

public class MouseTracker extends JFrame implements MouseListener,


MouseMotionListener {

private JLabel statusBar;

public MouseTracker() {
super( "Demonstrando Evento do mouse" );
statusBar = new JLabel();

24
Tratamento de Eventos

getContentPane().add( statusBar, BorderLayout.SOUTH );


addMouseListener( this );
addMouseMotionListener( this );
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
setSize( 275, 100 );
show();
}

public void mouseClicked( MouseEvent e ) {


statusBar.setText( "Clicked em [" + e.getX() + ", " + e.getY() +
"]" );
}

public void mousePressed( MouseEvent e ) {


statusBar.setText( "Pressed em [" + e.getX() + ", " + e.getY() +
"]" );
}

public void mouseReleased( MouseEvent e ) {


statusBar.setText( "Released em [" + e.getX() + ", " + e.getY() +
"]" );
}

public void mouseEntered( MouseEvent e ) {


statusBar.setText( "Mouse na janela" );
}

public void mouseExited( MouseEvent e ) {


statusBar.setText( "Mouse fora da janela " );
}

public void mouseDragged( MouseEvent e ) {


statusBar.setText( "Dragged em [" + e.getX() + ", " + e.getY() +
"]" );
}

public void mouseMoved( MouseEvent e ) {


statusBar.setText( "Moved em [" + e.getX() + ", " + e.getY() + "]" );
}

public static void main( String args[] ) {


MouseTracker app = new MouseTracker();
}

}
Código 3-5: Tratando eventos do mouse

Cada evento de mouse resulta na exibição de um String em JLabel


statusBar na parte inferior da janela. Definimos JLabel statusBar e o anexamos
ao painel de conteúdo.

Até agora, toda as vezes que utilizamos o painel de conteúdo, o método


setLayout foi chamado para configurar o gerenciador de layout do painel de
conteúdo como um FlowLayout. Isso permitiu ao painel de conteúdo exibir os
componentes GUI que anexamos a ele da esquerda para a direta. Se os
componentes GUI não se ajustarem em uma linha, o FlowLayout cria linhas
adicionais para continuar exibindo os componentes GUI.
25
Tratamento de Eventos

Realmente, o gerenciador padrão de layout é um BorderLayout que divide a


área do painel de conteúdo em cinco regiões - norte, sul, leste, oeste e centro.

Figura 3-1: Exemplo de tratamento de eventos do mouse

Utilizamos uma nova versão do método Container add para anexar


statusBar à região BorderLayout.SOUTH, que se estende ao longo de toda a
parte inferior do painel de conteúdo.

Registramos o objeto de janela MouseTracker como o ouvinte para seus


próprios eventos de mouse. Os métodos add.MouseListener e
addMouseMotionListener são os métodos Component que podem ser utilizados
para registrar ouvintes de eventos de mouse para um objeto de qualquer
classe que estenda Component.

Quando o mouse entra ou sai da área do aplicativo, o método


mouseEntered e o método mouseExited são chamados, respectivamente.

Ambos os métodos exibem uma mensagem na statusBar indicando que o


mouse está dentro do aplicativo ou que o mouse está fora do aplicativo.

Quando quaisquer dos outros cinco eventos ocorrem, eles exibem uma
mensagem na statusBar que inclui um String representando o evento que
ocorreu e as coordenadas onde o evento de mouse ocorreu.

As coordenadas x e y do mouse em que o evento ocorreu são obtidas com


os métodos MouseEvent getX e getY, respectivamente.

26
Tratamento de Eventos

Classes Adaptadoras

Muitas das interfaces ouvintes de eventos fornecem múltiplos métodos:


MouseListener e MouseMotionListener são exemplos.

Não é sempre desejável definir cada método em uma interface ouvinte de


evento.

Por exemplo, um programa pode precisar apenas do tratador de interface


MouseListener mouseClicked ou do tratador MouseMotionListener
mouseDragged.

Em nossos aplicativos de janela (subclasses de JFrame), o término do


aplicativo foi tratado com o windowClosing da interface WindowListener, que
na realidade especifica sete métodos de tratamento de eventos de janela.

Para muitas das interfaces ouvintes que contém múltiplos métodos, os


pacotes java.awt.Event e javax.swing.Event fornecem classes adaptadoras de
ouvinte de eventos.

Uma classe adaptadora implementa uma interface e fornece uma


implementação padrão (com o corpo de um método vazio) de cada método na
interface. As classes adaptadoras java.awt.Event são mostradas abaixo junto
com as interfaces que elas implementam.

Implementa a Interface Classe Adaptadora de Eventos

ComponentListener ComponentAdapter

ContainerListener ContainerAdapter

FocusListener FocusAdapter

KeyListener KeyAdapter

MouseListener MouseAdapter

MouseMotionListener MouseMotionAdapter

WindowListener WindowAdapter

Tabela 3-1: Interfaces implementadas por classes adaptadoras.

O programador pode estender a classe adaptadora para herdar a


implementação padrão de cada método e então anular o(s) método(s)
necessário(s) para tratamento de eventos.

27
Tratamento de Eventos

A implementação padrão de cada método na classe adaptadora tem um


corpo vazio.

Isso é exatamente o que temos feito em cada exemplo de aplicativo que


estende JFrame e define o método windowClosing para tratar o fechamento da
janela e o encerramento do aplicativo.

O aplicativo Painter utiliza o tratador de evento mouseDragged para criar


um programa simples de desenho. O usuário pode desenhar figuras com o
mouse arrastando o mouse no fundo da janela.

Como não pretendemos utilizar o método mouseMoved, nosso


MouseMotionListener é definido como uma subclasse de MouseMotionAdapter.

Essa classe já define mouseMoved e mouseDragged, então podemos


simplesmente anular mouseDragged para fornecer a funcionalidade de
desenho.

package com.targettrust.java.capitulo03;

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

public class Painter extends JFrame {


private int xValue = -10, yValue = -10;
private Container c;
public Painter() {
super( "Painter" );
c = getContentPane();
c.add(new Label( "Arraste o mouse para desenhar" ),
BorderLayout.SOUTH);

addMouseMotionListener(
new MouseMotionAdapter() {
public void mouseDragged( MouseEvent e ) {
xValue = e.getX();
yValue = e.getY();
repaint();
}
}
);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 300, 150 );
setVisible(true);
}

public void paint( Graphics g ) {


g.fillOval( xValue, yValue, 4, 4 );
}

public static void main( String args[] ) {


Painter app = new Painter();
}
}
Código 3-6: Código exemplo de classes adaptadoras.

28
Tratamento de Eventos

As variáveis de instância xValue e yValue armazenam as coordenadas do


evento mouseDragged.

Inicialmente, as coordenadas são configuradas fora da área de janela para


evitar que uma oval seja desenhada na área de fundo na primeira chamada a
paint quando a janela é exibida.

Registramos um MouseMotionListener para ouvir os eventos de


movimento de mouse da janela (lembre-se de que uma chamada para um
método que não é precedida por uma referência e por um operador de ponto é
na realidade precedida por “this.”, indicando que o método é chamado para a
instância atual da classe em tempo de execução).

Definimos uma classe interna anônima que estende a classe


MouseMotionAdapter (que implementa MouseMotionListener).

A classe interna anônima herda uma implementação padrão dos métodos


mouseMoved e mouseDragged. Portanto, a classe interna anônima já satisfaz o
requisito de que em todos os métodos de uma interface devem ser
implementados.

Entretanto, os métodos padrão não fazem nada quando são chamados.

Portanto, anulamos o método mouseDragged para capturar as


coordenadas x e y do evento de mouse arrastado e as armazenamos nas
variáveis de instância xValue e yValue; então, chamamos repaint para começar
a desenhar a próxima oval no fundo (o que é realizado pelo método paint).

Registramos um WindowListener para ouvir os eventos de janela da janela


de aplicativo (tais como fechar a janela). Definimos uma classe interna
anônima que estende a classe WindowAdapter (que implementa
WindowListener).

29
Tratamento de Eventos

Figura 3-2: Exemplo de utilização de classes adaptadoras.

A classe interna anônima herda uma implementação padrão dos sete


diferentes métodos de tratamento de eventos de janelas. Portanto, a classe
interna anônima já satisfaz o requisito de que uma interface deve ser
implementada em todos os métodos.

Entretanto, os métodos padrão não fazem nada quando são chamados.


Então, anulamos o método windowClosing para terminar o aplicativo quando o
usuário clica na caixa de fechamento da janela de aplicativo.

Repare que, quando você arrasta o mouse, todos os ovais permanecem na


janela. isso é devido a um recurso especial dos componentes GUI Swing
chamado de buffer duplo em que todo desenho realmente ocorre em uma
imagem armazenada na memória, e então a imagem inteira é exibida na
janela (ou outro componente GUI).

Isso ajuda a melhorar a qualidade gráfica em uma GUI Swing.

O aplicativo MouseDetails demonstra como determinar o número de


cliques de mouse (isto é, a contagem de cliques) e como distinguir entre
diferentes botões do mouse.

O ouvinte de eventos nesse programa é um objeto da classe interna


MouseClickHandler que estende MouseAdapter para possamos definir apenas o
método mouseClicked de que precisamos nesse exemplo.

package com.targettrust.java.capitulo03;

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

public class MouseDetails extends JFrame {

private String s = "";


private int xPos, yPos;

public MouseDetails() {
super( "Mouse clicks and buttons" );
addMouseListener( new MouseClickHandler() );
setSize( 350, 150 );
show();
}

public void paint( Graphics g ) {


g.drawString( "Clicked @ [" + xPos + ", " + yPos + "]", xPos, yPos );
}

public static void main( String args[] ) {


MouseDetails app = new MouseDetails();

30
Tratamento de Eventos

private class MouseClickHandler extends MouseAdapter {

public void mouseClicked( MouseEvent e ) {

xPos = e.getX();
yPos = e.getY();
String s = "Clicked " + e.getClickCount() + " vez(s)";

if ( e.isMetaDown() ) s += " com o botão direito do mouse";


else if ( e.isAltDown() ) s += " com o botão do centro";
else s += " com o botão da esquerda";
setTitle( s );
repaint();
}
}
}
Código 3-7: Exemplo de utilização de classes adaptadoras.

Um usuário de um programa Java pode estar em um sistema com um, dois


ou três botões do mouse. Java fornece um mecanismo para distinguir entre os
botões do mouse.

Figura 3-3: Exemplo de utilização de classes adaptadoras.

A classe MouseEvent herda vários métodos de classe InputEvent que


podem distinguir entre botões do mouse em um mouse de múltiplos botões ou
podem simular um mouse de múltiplos botões com um pressionamento de
tecla combinado e dique do botão do mouse.

Os métodos InputEvent utilizados para distinguir entre cliques do botão do


mouse são:
Método Descrição
InputEvent

Esse método retoma true quando o usuário clica com o


isMetaDown botão direito de um mouse com dois ou três botões. Para simular
() um clique de botão direito com um mouse de um botão, o
usuário pode pressionar a tecla Meta no teclado e clicar no botão

31
Tratamento de Eventos

do mouse.

Esse método retoma true quando o usuário clica no botão


isAltDown ( ) do centro do mouse em um mouse com três botões. Para simular
um clique com o botão do centro do mouse em um mouse com
um ou dois botões, o usuário pode pressionar a tecla Alt no
teclado e clicar no botão do mouse.

Tabela 3-2: Quadro de métodos InputEvent

Java pressupõe que cada mouse contém um botão esquerdo do mouse.

Portanto, é simples testar um clique com o botão esquerdo do mouse.


Entretanto, usuários com mouse de um ou dois botões devem utilizar uma
combinação de pressionamentos de teclas no teclado e clicar no mouse ao
mesmo tempo para simular os botões ausentes no mouse.

No caso de um mouse com um ou dois botões, esse programa pressupõe


que o botão do centro do mouse é clicado se o usuário mantém pressionada a
tecla <Alt> e clica no botão do mouse esquerdo em um mouse de dois botões
ou com botão único do mouse em um mouse de um botão.

No caso de um mouse de um botão, esse programa pressupõe que o


botão direito do mouse é clicado se o usuário mantém pressionada a tecla
Meta e clica no botão do mouse.

O método mouseClicked primeiro captura as coordenadas onde o evento


ocorreu e as armazena em variáveis de instância xPos e yPos da classe
MouseDetails. Criamos um String contendo o número de cliques de mouse
(como retomado pelo método MouseEvent getClickCount).

A estrutura condicional utiliza os métodos isMetaDown e isAltDown para


determinar qual botão do mouse o usuário clicou e acrescenta um string
apropriado para String s em cada caso.

O String resultante exibido na barra de título da janela com o método


setTitle (herdado na classe JFrame da classe Frame). Chamamos repaint para
iniciar uma chamada a paint para desenhar um String na localização em que o
usuário clicou com o mouse.

32
Tratamento de Eventos

Tratando Eventos do Teclado

Esta seção apresenta a interface ouvinte de eventos KeyListener para


tratar eventos do teclado. Eventos de tecla são gerados quando as teclas no
teclado são pressionadas e liberadas. Uma classe que implementa KeyListener
deve fornecer definições para os métodos keyPressed keyReleased e
keyTyped, cada uma das quais recebe um KeyEvent como seu argumento.

A classe KeyEvent é uma subclasse de InputEvent.

O método keyPressed é chamado em resposta ao pressionamento de


qualquer tecla.

O método keyTyped é chamado em resposta ao pressionamento de


qualquer tecla que não é uma tecla de ação (por exemplo, uma tecla de seta,
<Home>, <End>, <Page Up>, <Page Down>, uma tecla de função, <Num
Lock>, <Print Screen>, <Scroll Lock>, <Caps Lock> e <Pause>).

O método keyReleased é chamado quando a tecla é liberada depois de


qualquer evento keyPressed ou keyTyped.

Consulte referência aos métodos KeyListener. A classe KeyDemo


implementa a interface KeyListener, então todos os três métodos são definidos
no aplicativo.

package com.targettrust.java.capitulo03;

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

public class KeyDemo extends JFrame implements KeyListener {

private String line1 = "", line2 = "";


private String line3 = "";
private JTextArea textArea;

public KeyDemo() {
super( "Demostrando eventos de mouse" );
textArea = new JTextArea( 10, 15 );
textArea.setText( "Pressione uma tecla " );
textArea.setEnabled( false );
addKeyListener( this );
getContentPane().add( textArea );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 350, 100 );
setVisible(true);
}

public void keyPressed( KeyEvent e ) {


line1 = "Key pressed: " + e.getKeyText( e.getKeyCode() );
setLines2and3( e );

33
Tratamento de Eventos

public void keyReleased( KeyEvent e ) {


line1 = "Key released: " + e.getKeyText( e.getKeyCode() );
setLines2and3( e );
}

public void keyTyped( KeyEvent e ) {


line1 = "Key typed: " + e.getKeyChar();
setLines2and3( e );
}

private void setLines2and3( KeyEvent e ) {


line2 = "Esta é a tecla " + ( e.isActionKey() ? "" : "não " ) + "é
uma tecla de ação";
String temp = e.getKeyModifiersText( e.getModifiers() );
line3 = "Modificador pressionado: " + ( temp.equals( "" ) ?
"nenhum"
: temp );
textArea.setText( line1 + "\n" + line2 + "\n" + line3 + "\n" );
}

public static void main( String args[] ) {


KeyDemo app = new KeyDemo();
}
}
Código 3-8: Exemplo de tratamento de eventos de teclado.

O construtor registra o aplicativo para tratar seus próprios eventos de


tecla com o método addKeyListener.

O método addKeyListener é definido na classe Component, então cada


subclasse de Component pode notificar KeyListeners de eventos de tecla para
esse Component.

Adicionamos a JTextArea textArea (onde a saída do programa é exibida) ao


painel de conteúdo. Quando um único Component é adicionado a um
BorderLayout, o Component ocupa o inteiro Container por default.

Os métodos keyPressed e keyReleased utilizam o método KeyEvent


getKeyCode para obter o código de tecla virtual da chave que foi pressionada.
A classe KeyEvent mantém um conjunto de constantes — o código de tecla
virtual constante — que representa cada tecla no teclado.

34
Tratamento de Eventos

Figura 3-4: Exemplo de tratamento de eventos do teclado.

Essas constantes podem ser comparadas com o valor de retorno de


getKeyCode para testar as teclas individuais no teclado. O valor retornado por
getKeyCode é passado para o método KeyEvent getKeyText, que retorna um
String contendo o nome da tecla que foi pressionada.

Para uma lista completa de constantes de tecla virtual, veja a


documentação on-line para a classe KeyEvent (pacote java.awtEvent).

O método keyTyped utiliza o método KeyEvent getKeyChar para obter o


valor Unicode do caractere digitado.

Todos os três métodos de tratamento de eventos terminam chamando o


método setLines2and3 e passando para ele o objeto KeyEvent. Esse método
utiliza o método KeyEvent isActionKey para determinar se a tecla no evento
era uma tecla de ação.

Além disso, o método InputEvent getModifiers é chamado para determinar


se quaisquer teclas modificadoras (como <Shift>, <Alt> e <Ctrl>) foram
pressionadas quando o evento de tecla ocorreu.

O resultado desse método é passado para o método KeyEvent


getKeyModifiersText, que produz um string contendo os nomes das teclas
modificadoras pressionadas.

Nota: Se você precisa testar uma tecla específica no teclado, a classe


KeyEvent fornece uma constante de tecla para cada tecla no teclado. Essas
constantes podem ser utilizadas a partir dos tratadores de eventos de tecla
para determinar se uma tecla particular foi pressionada. Além disso, para
determinar se as teclas <Alt>, <Ctrl>, <Meta> e <Shift> são pressionadas
individualmente, os métodos InputEvent isAltDown, IsControlDown,
isMetaDown e isShiftDown retornam um boolean indicando se a tecla particular
foi pressionada durante o evento de tecla.

35
Tratamento de Eventos

Exercícios

1. Para praticar o tratamento de eventos, crie uma interface gráfica de


uma tela de login de acordo com a figura abaixo:

2. Implemente um listener para realizar o encerramento do processo java


criado pelo método main da aplicação quando o usuário clicar no ‘X’ da janela.

3. Implemente listeners para os botões que possam realizar ações de


umclique de mouse. Para o botão sair faça também o encerramento do
processo.

4. Para o campo de senha implemente um listener que seja capaz de ouvir


eventos de teclado. Este deve realizar alguma ação quando a tecla ENTER for
pressionada sobre o campo.

36
Tratamento de Eventos

Espaço para anotações

37
Tratamento de Eventos

38
4.Componentes para
Interface Gráfica

1
Acesso a Banco de Dados

Objetivos
• Apresentar os componentes mais utilizados em uma GUI Swing

• Entender a relação entre estes componentes

• Saber quando utilizar determinado componente

• Aprender como utilizar dois ou mais componentes em conjunto

2
Acesso a Banco de Dados

JFrame

Janelas em uma interface gráfica são áreas retangulares que podem ser
exibidas em qualquer área da tela.

A classe JFrame é responsável pela exibição de janelas para o usuário


(conforme ilustração abaixo) com os recursos mínimos para sua utilização.
Como por exemplo, bordas, barra de títulos, operações de minimizar,
maximizar, etc.

Figura 4-1: Exemplo de janela JFrame

Para que um JFrame seja exibido, propriedades básicas devem ser


definidas, como as suas dimensões, se estará visível ou não entre outras. O
programa abaixo mostra a criação de um JFrame definindo seu título e
dimensões.
package com.targettrust.java.capitulo04;

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

public class JanelaPrincipal extends JFrame {


public JanelaPrincipal() {
setTitle( "Janela de Exemplo" );

setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize( 400, 300 );
setVisible(true);
}

public static void main(String args[]) {


JanelaPrincipal app = new JanelaPrincipal();
}
}
Código 4-1: Exemplo de utilização de JFrame.
3
Acesso a Banco de Dados

O programa acima extende a classe JFrame, tendo como objetivo exibir


uma janela na tela do usuário.

O método estático main esta presente para que o programa possa ser
executado. Apenas para relembrar, qualquer programa em uma aplicação Java
Swing (que não seja applet) inicia sua execução no método estático main.

No método main encontramos a seguinte: instrução new JanelaPrincipal().


Esta será responsável por criar uma nova instância da classe JanelaPrincipal
que é um JFrame.

A partir deste momento o construtor da classe será executado e este irá


configurar através de métodos da classe JFrame como a mesma será exibida.

A primeira propriedade que o programa ira definir são as dimensões da


Janela. Isto é feito através de chamada ao método setSize() da classe JFrame,
este método pode ser chamado recebendo como parâmetro um objeto
java.awt.Dimension ou diretamente com dois inteiros, o primeiro definindo a
largura e o segundo a altura. Caso as dimensões não sejam definidas (método
setSize()), será criada uma janela com dimensões nulas (zero de largura e zero
de altura).

Em seguida o título será definido com a chamada a setTitle();. Este


método irá definir como título a String recebida como parâmetro.

Antes de a janela ser exibida, deve ser decidido o que o programa irá
realizar quando for efetuada uma operação de fechar a janela. No AWT fazia-se
necessário implementar um evento com o código responsável pela operação
de fechar a janela. No Swing foi criado um novo método que pode realizar
operações padroões de fechamento.

Para utilizar estas funções padrão foi adicionado o método


setDefaultCloseOperation(). Este pode receber como parâmetro as constantes
da tabela abaixo:

DO_NOTHING_ON_CLOS Não realiza nenhuma


E operação quando a janela for
fechada.
HIDE_ON_CLOSE Automáticamente oculta a
janela quando esta for fechada
através de uma chamada ao
método hide().
DISPOSE_ON_CLOSE Automaticamente esconde e
descarta a janela. Através de uma
chamada ao método dispose().
EXIT_ON_CLOSE Termina a aplicação através
do mátodo System.Exit(0).
4
Acesso a Banco de Dados

Tabela 4-1: Operações padrões de fechamento de janela

No programa exemplo, foi utilizada o método de saída padrão


EXIT_ON_CLOSE.

Neste ponto do programa, as propriedades básicas para exibição de uma


janela já estão definidas então deve ser executada uma instrução para exibir a
janela na tela através do método show().

5
Acesso a Banco de Dados

JLabel

Os rótulos fornecem instruções de texto ou informações sobre uma GUI.


Os rótulos são definidos com a classe JLabel - uma subclasse de JComponent.
Um rótulo exibe uma única linha de texto de leitura.

Uma vez que os rótulos são criados, os programas raramente alteram um


conteúdo do rótulo.

package com.targettrust.java.capitulo04;

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

public class LabelTest extends JFrame {


private JLabel label1, label2, label3;

public LabelTest() {

super( "Testing JLabel" );


Container c = getContentPane();
c.setLayout( new FlowLayout() );
label1 = new JLabel( "Label com texto" );
label1.setToolTipText( "Tool tip de um label" );
c.add( label1 );

Icon javalogo = new ImageIcon(getClass().getResource("javalogo2.gif"));


label2 = new JLabel("Label com texto e imagem", javalogo,
SwingConstants.LEFT );
label2.setToolTipText( "Tool tip de um label" );
c.add( label2 );

label3 = new JLabel();


label3.setText( "Label com texto e icone abaixo" );
label3.setIcon( javalogo );
label3.setHorizontalTextPosition( SwingConstants.CENTER );
label3.setVerticalTextPosition( SwingConstants.BOTTOM );

c.add( label3 );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 275, 170 );
setVisible(true);
}

public static void main( String args[] ) {


LabelTest app = new LabelTest();
}
}
Código 4-2: Exemplo de utilização de JLabel.

6
Acesso a Banco de Dados

O programa declara três referências JLabel. Os objetos JLabel são


instanciados no construtor. A instrução new cria um objeto JLabel com o texto
"Label with text".

O texto é exibido no rótulo automaticamente. O método setToolTipText


(herdada na classe JLabel da classe JComponent) especifica uma dica de
ferramenta que é exibida automaticamente quando o usuário posiciona o
cursor do mouse sobre o rótulo na GUI. Quando executar esse programa, tente
posicionar o mouse sobre cada rótulo para ver sua dica de ferramenta.

O método add adiciona label1 ao painel de conteúdo.

Muitos componentes Swing podem exibir imagens especificando um ícone


como um argumento para seu construtor ou utilizando um método que
normalmente é chamado de setIcon. Um Icon é um objeto de qualquer classe
que implementa a interface Icon (pacote javax.swing).

Uma dessas classes é ImageIcon (pacote javax.swing), que suporta dois


formatos de imagem - Graphics Interchange Format (GIF) e Joint Photographic
Experts Group (JPEG). Os nomes de arquivo para cada um desses tipos
possuem extenções gif ou jpg (ou jpeg), respectivamente.
O arquivo “javalogo.gif” contém a imagem para carregar e armazenar no
objeto ImageIcon. Pressupõe-se que esse arquivo esteja no mesmo diretório
que o programa. O objeto ImageIcon é atribuido à referência Icon bug. Lembre-
se, a classe ImageIcon implementa a interface Icon, portanto um ImageIcon é
um Icon.

Figura 4-2: Exemplo de JLabel

A classe JLabel suporta a exibição de Icons. O construtor JLabel é utilizado


para criar um rótulo que exibe o texto "Label with text and icon" e o Icon que
“logojava” referencia, e é alinhado à esquerda (isto é, o icone e o texto estão o
lado esquerdo da área do rótulo na tela).

A interface SwingConstants (pacote javax.swing) define um conjunto de


constantes inteiras comuns (como SwingConstants LEFT) que são utilizadas
com muitos componentes Swing. Por default, o texto aparece à direita da
imagem quando um rótulo contém tanto texto como imagem.

Os alinhamentos horizontal e vertical de um rótulo podem ser


configurados com os métodos setHorizontalAlignment e setVerticalAligninent,
7
Acesso a Banco de Dados

respectivamente. A dica de ferramenta é adicionada para label2 e adicionamos


label2 ao painel de conteúdo.

A classe JLabel fornece muitos métodos para configurar um rótulo depois


que ele foi instanciado. Cria-se um JLabel e invocamos o construtor sem
argumentos (padrão). Esse rótulo não tem texto ou Icon.

Utiliza-se o método JLabel setText para configurar o texto exibido no


rótulo. Um método correspondente getText recupera o texto atual exibido em
um rótulo. Utilizamos um método JLabel setIcon para configurar o Icon exibido
no rótulo. Um método correspondente getIcon recupera o Icon atual exibido em
um rótulo. Utilizamos os métodos JLabel setHorizontalTextPosition e
setVerticalTextPosition para especificar a posição do texto no rótulo.

As instruções precedentes indicam que o texto será centralizado


horizontalmente e aparecerá na parte inferior do rótulo. Portanto, o Icon
aparecerá acima do texto.Configuramos o texto de dica de ferramenta para o
label3 e após adicionamos label3 ao painel de conteúdo.

8
Acesso a Banco de Dados

JButton

Um botão é um componente em que o usuário clica para acionar uma


ação específica. Um programa Java pode utilizar vários tipos de botões,
incluindo botões de comando, caixas de seleção, botões de alternação e
botões de opção. Consulte a documentação SDK na qual mostra a hierarquia
de herança dos botões do Swing que abordaremos neste ítem.

Todos os tipos de botão são subclasses de AbstractButton (pacote


javax.swing), o qual define muitos dos recursos que são comuns aos botões do
Swing.

Um botão de comando gera um ActionEvent quando o usuário clica no


botão com o mouse. Os botões de comando são criados com a classe JButton,
que herda da classe AbstractButton. O texto na face de um JButton é chamado
de rótulo de botão (caption). Uma GUI pode ter muitos JButtons, mas cada
rótulo de botão em geral deve ser único.

O aplicativo abaixo cria dois JButtons e demonstra que JButtons (como


JLabels) suportam a exibição de ícones. O tratamento de eventos para os
botões é realizado por uma única instância de classe interna ButtonHandler.

package com.targettrust.java.capitulo04;

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

public class ButtonTest extends JFrame {

private JButton plainButton, fancyButton;

private class ButtonHandler implements ActionListener {


public void actionPerformed( ActionEvent e ) {
JOptionPane.showMessageDialog( null, "Você pressionou: " +
e.getActionCommand() );
}
}

public ButtonTest() {
super( "Testando botões" );

Container c = getContentPane();
c.setLayout( new FlowLayout() );

plainButton = new JButton( "Botão sem ícone" );


c.add( plainButton );

Icon bug1 = new ImageIcon( getClass().getResource("javalogo1.gif") );


Icon bug2 = new ImageIcon( getClass().getResource("javalogo2.gif") );

fancyButton = new JButton( "Fancy Button", bug1 );


fancyButton.setRolloverIcon( bug2 );

9
Acesso a Banco de Dados

c.add( fancyButton );

ButtonHandler handler = new ButtonHandler();

fancyButton.addActionListener( handler );
plainButton.addActionListener( handler );

pack();
setVisible(true);
}

public static void main( String args[] ) {


ButtonTest app = new ButtonTest();
}
}
Código 4-3: Exemplo de utilização de JButton.

Declaramos duas referências para as instâncias de classe JButton -


plainButton e fancyButton (que são instanciadas no construtor). Criamos
plainButton com o rótulo de botão “PlainButton” e adicionamos o botão ao
painel de conteúdo.

Um JButton pode exibir ícones. Para fornecer ao usuário um nível extra de


interatividade visual com a GUI, um JButton também pode ter um ícone
rollover, ou seja, um ícone que é exibido quando o mouse é posicionado sobre
o botão.

O ícone no botão altera-se quando o mouse se move para dentro e para


fora da área do botão na tela. Criamos dois objetos ImageIcon que
representam o Icon padrão e o Icon rollover para o JButton criado.

Ambas as instruções pressupõem que os arquivos de imagem são


armazenados no mesmo diretório que o programa (que é geralmente o caso
para aplicativos que utilizam imagens).

Criamos fancyButton com texto-padrão “Fancy Button” e o Icon bug1. Por


default, o texto é exibido à direita do ícone. Utilizamos o método
setRolloverIcon (herdado da classe AbstractButton na classe JButton) para
especificar a imagem exibida no botão quando o usuário posiciona o mouse
sobre o botão. Adicionamos o botão ao painel de conteúdo.

Figura 4-3: Exemplo de JButton


10
Acesso a Banco de Dados

JButtons (como JTextFields) geram ActionEvents. Como mencionado


anteriormente, um ActionEvent pode ser processado por qualquer objeto
ActionListener. Registramos um objeto ActionListener para cada JButton.

A classe interna ButtonHandler define actionPerformed para exibir um


caixa de diálogo de mensagem contendo o rótulo para o botão que foi
pressionado pelo usuário.

O método ActionEvent getActionCommand retoma o rótulo do botão que


gerou o evento.

11
Acesso a Banco de Dados

JTextField e JPasswordField

JTextFields e JPasswordFields (pacote javax.swing) são áreas de uma única


linha em que o texto pode ser inserido via teclado pelo usuário ou o texto pode
ser simplesmente exibido.

Um JPasswordField mostra que um caractere foi digitado quando o usuário


insere os caracteres, mas oculta os caracteres assumindo que eles
representam uma senha que deve permanecer conhecida apenas para o
usuário.

Quando o usuário digita os dados em um JTextField ou JPasswordField e


pressiona a tecla Enter, um evento de ação ocorre. Se um ouvinte de evento é
registrado, o evento é processado e os dados no JTextField ou JPasswordField
podem ser utilizados no programa.

A classe JTextField estende a classe JTextComponent (pacote


javax.swing.text), que fornece muitos recursos comuns para os componentes
baseados em texto do Swing.

A classe JPasswordField estende JTextField e adiciona vários métodos que


são especificos ao processamento de senhas.

O aplicativo de exemplo utiliza as classes JTextField e JPasswordField para


criar e manipular quatro campos. Quando o usuário pressiona Enter no campo
atualmente ativo (o componente atualmente ativo "tem o foco"), uma caixa
diálogo de mensagem contendo o texto no campo é exibida. Quando um
evento ocorre no JPasswordField, a senha é revelada.

package com.targettrust.java.capitulo04;

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

public class TextFieldTest extends JFrame {

private JTextField text1, text2, text3;


private JPasswordField password;

public TextFieldTest() {
super( "Testando JTextField e JPasswordField" );
Container c = getContentPane();
c.setLayout( new FlowLayout() );
text1 = new JTextField( 10 );
c.add( text1 );

text2 = new JTextField( "Digite um texto aqui: " );


c.add( text2 );

12
Acesso a Banco de Dados

text3 = new JTextField( "Campo não editável", 20 );


text3.setEditable( false );
c.add( text3 );

password = new JPasswordField( "Sua senha" );


c.add( password );

TextFieldHandler handler = new TextFieldHandler();

text1.addActionListener( handler );

text2.addActionListener( handler );
text2.addMouseListener( handler );

text3.addActionListener( handler );
addMouseWheelListener(handler);
password.addActionListener( handler );

setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 325, 100 );
setVisible(true);
}

public static void main( String args[] ) {


TextFieldTest app = new TextFieldTest();
}

private class TextFieldHandler implements ActionListener, MouseListener,


MouseWheelListener {

public void actionPerformed( ActionEvent e ) {


String s = "";

if ( e.getSource() == text1 )
s = "text1: " + e.getActionCommand();
else if ( e.getSource() == text2 )
s = "text2: " + e.getActionCommand();
else if ( e.getSource() == text3 )
s = "text3: " + e.getActionCommand();
else if ( e.getSource() == password ) {
s = "password: " + e.getActionCommand();
}

JOptionPane.showMessageDialog( null, s );
}

public void mouseClicked(MouseEvent e) {


text2.setText("");
}

public void mouseEntered(MouseEvent e) {}

public void mouseExited(MouseEvent e) {}

public void mousePressed(MouseEvent e) {}

public void mouseReleased(MouseEvent e) {}

public void mouseWheelMoved(MouseWheelEvent e) {


JOptionPane.showMessageDialog( null, "Wheel!!!!" );
}

13
Acesso a Banco de Dados

Código 4-4: Exemplo de utilização de JTextField e JPasswordField.

São declaradas três referências a JTextFields (text1, text2 e text3) e um


JPasswordField (password).

Cada uma delas é instanciada no construtor. Defnimos JTextField text1


com 10 colunas de texto. A largura do campo de texto será a largura em pixels
do caractere médio na fonte atual do campo de texto multiplicado por 10.

Adicionamos text1 ao painel de conteúdo. Definimos JTextField text2 com


o texto inicial "Enter text here" para exibir no campo de texto. A largura do
campo de texto é determinada pelo texto. Adicionamos text2 ao painel de
conteúdo.

Definimos JTextField text3 e chamamos o construtor JTextField com dois


argumentos - o texto-padrão "Uneditable textfield" para exibir no campo de
texto e o número de colunas (20).A largura do campo de texto é determinada
pelo número de colunas especificadas.

Figura 4-4: Exemplo de JTextField e JPasswordField

Utilizamos o método setEditable (herdado no JTextField da classe


JTextComponent) para indicar que o usuário não pode modificar o texto no
campo de texto.

Adicionamos text3 ao painel de conteúdo. Definimos JPasswordField


password com o texto "Hidden text" para exibir no campo de texto. A largura
do campo de texto é determinada pelo texto. Repare que o texto é exibido
como uma string de asteriscos quando o programa executa.

Adicionamos password ao painel de conteúdo. Para o tratamento de


eventos nesse exemplo, definimos a classe interna TextFieldHandler. O
tratador da classe JTextField (discutido em detalhe brevemente) implementa a
interface ActionListener. Portanto, cada instância da classe TextFieldHandler é
um ActionListener.

14
Acesso a Banco de Dados

Definimos uma instância da classe TextFieldHandler e a atribui à


referencia handler. Essa instância será utilizada como o objeto ouvinte de
eventos para os JTextFields e o JPasswordField nesse exemplo.

Após instruções de registro de evento que especificam o objeto ouvinte de


eventos para cada um dos três JTextFields e para o JPasswordField são
especificadas. Depois que essas instruções executam, o objeto que handler
referencia está ouvindo eventos (isto é, será notificado quando um evento
ocorrer) nesses quatro objetos.

Em cada caso, o método addActionListener da classe JTextField é


chamado para registrar o evento.

O método addActionListener recebe como seu argumento um objeto


ActionListener. Portanto, qualquer objeto de uma classe que implemente a
interface ActionListener (isto é, qualquer objeto que é um ActionListener )
pode ser fornecido como um argumento para esse método.

O objeto que handler referencia é um ActionListener porque sua classe


implementa a interface ActionListener. Agora, quando o usuário pressiona
Enter em qualquer desses quatro campos, o método actionPerformed na
classe TextFieldHandler é chamado para tratar o evento.

O método actionPerformed utiliza seu método ActionEvent do argumento


getSource para determinar o componente GUI com o qual o usuário interagiu e
cria um String para exibir em uma caixa de diálogo de mensagem.

O método ActionEvent getActionCommand retorna o texto no JTextField


que gerou o evento.

Se o usuário interagiu com o JPasswordField, Instruções realizam a


coerção da referência de Component retornada por e.getSource() para uma
referência JPasswordField de modo utilizamos o método JPasswordField
getPassword para obter a senha e criar o String a ser exibido.

O método getPassword retorna a senha como um array de tipo char que é


utilizado como um argumento para um construtor de String para criar um
String. Exibimos uma caixa de mensagem indicando o nome de referência do
componente GUI e o texto que o usuário digitou no campo.

Observe que mesmo um JTextField não editável pode gerar um evento.


Também observe que o texto real da senha é exibido quando se pressiona
Enter no JPasswordField (é claro que normalmente você não faria isso!)

Utilizar uma classe separada para definir um ouvinte de eventos é uma


prática de programação comum para separar a interface GUI da
implementação de seu tratador de evento.

15
Acesso a Banco de Dados

JTextArea

A classe JTextArea é destinada a exibir uma área para manipulação de


múltiplas linhas de texto. Da mesma forma que a classe JTextField, esta classe
herda JTextComponent.

package com.targettrust.java.capitulo04;

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

public class TextAreaTest extends JFrame {


private String texto2;
private String texto;
private JTextArea txtArea1;
private JTextArea txtArea2;
private Container c;

public TextAreaTest() {
texto2 = new String("");
texto = new String("Digite aqui");
txtArea1 = new JTextArea(texto, 10, 15);
txtArea2 = new JTextArea(texto2, 10, 15);

c = getContentPane();

// Define o gerenciador de layout a ser utilizado e suas propriedades


FlowLayout layout = new FlowLayout();
c.setLayout(layout);
layout.setAlignment(FlowLayout.LEFT);

// Define as propriedades da janela que sera exibida


setSize( 400, 300 );
setTitle("Utilizando JTextArea");

// Define a operacao padrao para fechamento (encerrar programa)


setDefaultCloseOperation(EXIT_ON_CLOSE);

// Cria a JTextArea 1
c.add(txtArea1);

// Adiciona barra de rolagem na JTextArea


getContentPane().add(new JScrollPane(txtArea1));

// Adiciona o botao de copiar somente o texto selecionado


JButton copiarSelecionado = new JButton("Copiar Selecionado");
c.add(copiarSelecionado);

// Adiciona o botao de copiar todo o texto selecionado


JButton copiarTudo = new JButton("Copiar Tudo");
c.add(copiarTudo);

// Cria a JTextArea 2
c.add(txtArea2);

16
Acesso a Banco de Dados

// Adiciona barra de rolagem na JTextArea


c.add(new JScrollPane(txtArea2));

// Adiciona os eventos aos botoes


copiarTudo.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
txtArea2.setText(txtArea1.getText());
}
}
);

copiarSelecionado.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
txtArea2.setText(txtArea1.getSelectedText());
}
}
);

// Exibe a janela na tela


setVisible(true);
}

public static void main(String args[]) {


TextAreaTest app = new TextAreaTest();
}
}
Código 4-5: Exemplo de utilização de JTextArea.

O programa acima exemplifica a utilização de um JTextArea através da


criação de um programa simples que exibe duas caixas de texto (JTextArea) na
tela e dois botões (JButton).

Os botões no exemplo permitem duas operações. O primero botão


chamado “Copiar Tudo” quando clicado ira copiar o texto digitado na primeira
JTextArea para a segunda JTextArea.

O segundo botão chamado “Copiar Selecionado” quando acionado irá


copiar somente o texto selecionado na primeira JTextArea para a segunda
JTextArea.

A imagem abaixo mostra a tela do programa exemplo:

17
Acesso a Banco de Dados

Figura 4-5: Imagem da tela do programa de exemplo de JTextArea.

No programa, declaramos duas JTextArea, uma chamada txtArea1, e outra


chamada txtArea2. Instanciamos as duas através da operação new JTextArea()
que recebe como parâmetro o texto inicial da caixa de texto, o número de
linhas e o número de colunas. Inicializamos a txtArea1 com o texto “Digite
aqui” e a caixa txtArea2 sem texto inicial.

O programa adiciona a as duas caixas de texto uma barra de rolagem


(JScrollPane).

Além disso, são criados dois botões (conforme já visto no tópico sobre
JButton) os quais ao serem clicados realizam diferentes operações. Ambos os
botões inserem texto na segunda JTextArea através do método setText.

Para realizar esta operação (definir o texto da segunda JTextArea – objeto


txtArea2) o primeiro botão (“Copiar Tudo”) realiza uma chamada ao método
getText() da primeira JTextArea (objeto txtArea1) copiando desta forma todo o
texto da primeira para a segunda caixa de texto.

Já o segundo botão, utiliza-se do método getSelectedText() para copiar


apenas o texto selecionado da primeira para a segunda caixa de texto.

A tabela abaixo exibe alguns métodos úteis e sua função na classe


JTextArea.

insert(String str, int pos) Insere o texto na posição expecificada.


replaceRange(String str, Substitui o texto pelo informado no
int start, int end) primeiro parâmetro, da posição inicial
até a final.
setTabSize(int size) Define o tamanho da tabulação
(quando pressionado a tecla TAB).
setFont(Font f) Define a fonte utilizada na caixa de
texto.
Tabela 4-2: Métodos principais da classe JTextArea.

18
Acesso a Banco de Dados

JPanel

Ao desenvolver interfaces mais complexas, cada componente deverá ser


colocado em um local exato para que a aplicação fique com uma GUI
interessante para o usuário.

Para conseguir localiza-los em posições exatas, torna-se necessária a


utilização de “áreas” ou “grupos” de componentes. Estes são chamados de
painéis. Os painéis são controlados pela classe JPanel que é uma subclasse de
JComponent.

Resumindo, um painel é um agrupamento de componentes, sendo que


estes componentes podem ser até mesmo outros painéis.

Figura 4-6: Exemplo de utilização de JPanel.

Na imagem acima verificamos a utilização de um JPanel, esta GUI mostra


a utilização de dois painéis com dois diferentes gerenciadores de layout. O
primeiro painel utilizando BorderLayout e o segundo utilizando GridLayout.

package com.targettrust.java.capitulo04;

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

public class Paineis extends JFrame {

public Paineis() {

19
Acesso a Banco de Dados

getContentPane().setLayout(new BorderLayout());

JPanel painelGrid = new JPanel();


GridLayout layout = new GridLayout(1, 3);
painelGrid.setLayout(layout);

setTitle("Exemplo de Paineis");

JButton esquerda = new JButton("Esquerda");


JButton meio = new JButton("Meio");
JButton direita = new JButton("Direita");

painelGrid.add(esquerda);
painelGrid.add(meio);
painelGrid.add(direita);

getContentPane().add(painelGrid, BorderLayout.SOUTH);

setSize( 400, 300 );


setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}

public static void main(String args[]) {


Paineis app = new Paineis();
}

}
Código 4-6: Utilização de painéis com JPanel.

No programa acima, a primeira linha do construtor modifica o painel


padrão do JFrame para um BorderLayout através do método
getContentPane().setLayout(). Este procedimento define o primeiro
gerenciador de layout a ser utilizado no primeiro painel.

Logo em seguida é realizada a declaração de um novo painel utilizando-se


da classe JPane e também definido um novo gerenciador de layout o
GridLayout e após as duas declarações é associado ao segundo painel o
GridLayout.

São instanciados quatro objetos, três botões e uma caixa de texto. Os


botões são adicionados ao segundo painel através do método add() do painel,
já a caixa de texto é associada ao primeiro painel através do mesmo método.

Ao final o segundo painel (contendo os botões) é adicionado na região sul


do primeiro painel através do método add(), com isso faz com que a caixa de
texto expanda-se por toda a região norte do primeiro painel.

20
Acesso a Banco de Dados

JComboBox

Uma caixa de combinação (ou combo box, às vezes também chamada de


lista drop-down) fornece uma lista de itens entre os quais o usuário pode
escolher. As caixas de combinação são implementadas com a classe
JComboBox, que herda da classe JComponent. JComboBoxs geram ItemEvents
como JCheckBoxs e JRadioButtons.

package com.targettrust.java.capitulo04;

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

public class ComboBoxTest extends JFrame {


private JComboBox images;
private JLabel label;
private String names[] = {"img1.gif", "img2.gif", "img3.gif", "img4.gif"};
private Icon icons[] =
{ new ImageIcon( getClass().getResource(names[ 0 ] ) ),
new ImageIcon( getClass().getResource(names[ 1 ] ) ),
new ImageIcon( getClass().getResource(names[ 2 ] ) ),
new ImageIcon( getClass().getResource(names[ 3 ] ) )
};

public ComboBoxTest() {
super( "JComboBox" );
Container c = getContentPane();
c.setLayout( new FlowLayout() );
images = new JComboBox( names );
images.setMaximumRowCount( 3 );

images.addItemListener(
new ItemListener() {
public void itemStateChanged( ItemEvent e ) {
label.setIcon( icons[ images.getSelectedIndex() ] );
}
}
);

c.add( images );
label = new JLabel( icons[ 0 ] );
c.add( label );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 350, 100 );
setVisible(true);
}

public static void main( String args[] ) {


ComboBoxTest app = new ComboBoxTest();
}
}
Código 4-7: Exemplo de utilização de JComboBox.

21
Acesso a Banco de Dados

Através deste exemplo podemos verificar a utilização de um JComboBox a


fim de fornecer uma lista de quatro nomes de arquivo de imagem. Quando um
nome de arquivo de imagem é selecionado, a imagem correspondente é
exibida como um Icon em um JLabel.

Declaramos e inicializamos o array de ícones de com quatro novos objetos


ImageIcon. O array String names contém os nomes dos quatro arquivos de
imagem que são armazenados no mesmo diretório que o aplicativo.

Criamos um objeto JComboBox utilizando os Strings no array names como


os elementos na lista. Um índice numérico monitora a ordem de itens na
JComboBox. O primeiro item é adicionado no índice 0; o próximo item é
adicionado no índice 1, etc.

O primeiro item adicionado a uma JComboBox aparece como o item


atualmente selecionado quando a JComboBox é exibida. Outros itens são
selecionados clicando na JComboBox. Quando clicada, a JComboBox expande
em uma lista na qual o usuário pode fazer uma seleção.

Utilizamos o método JComboBox setMaximumRowCount para estabelecer


o número máximo de elementos que são exibidos quando o usuário clica na
JComboBox. Se houver mais itens na JComboBox que o número máximo de
elementos que são exibidos, a JComboBox fornece automaticamente uma
barra de rolagem que permite ao usuário visualizar todos os elementos na
lista.

Figura 4-7: Exemplo de JComboBox

O usuário pode clicar nas setas de rolagem na parte superior e inferior da


barra de rolagem para mover-se para cima e para baixo pela lista, um
elemento por vez, ou o usuário pode arrastar a caixa de rolagem no meio da
barra de rolagem para cima e para baixo para mover-se pela lista.

Para arrastar a caixa de rolagem, mantenha o botão do mouse


pressionado com o cursor de mouse na caixa de rolagem e mova o mouse.

Registramos uma instância de uma classe interna anônima que


implementa ItemListener como o ouvinte para JComboBox images. Quando o
usuário faz uma seleção de imagens, o método itemStateChanged configura o
22
Acesso a Banco de Dados

Icon como label. O Icon é selecionado do array icons determinando o número


do índice do item selecionado no JComboBox através do método
getSelectedlndex.

23
Acesso a Banco de Dados

Construindo Menus

Em qualquer GUI os menus são fundamentais, pois permitem ao usuário


realizar ações sem deixar uma tela confusa com muitos itens ou botões
descnecessários.

Os menus se dividem em dois tipos básicos, as barras de menu e os


menus popup ou menus de contexto.

24
Acesso a Banco de Dados

Barras de Menus (JMenuBar)

A classe JMenuBar tem por objetivo gerenciar uma barra de menus. Uma
barra de menus comumente é utilizada em aplicações, estando localizada
abaixo do título da janela.

No Swing uma barra de menu somente podem ser associados a classes


que possuam o método setJMenuBar, as classes em que mais comumente
utilizamos menus são JFrame e JApplet.

A ilustração abaixo exemplifica o funcionamento dos objetos de menu:

Figura 4-8: Classes utilizadas em uma barra de menus.

Conforme verificamos na ilustração acima, temos um primeiro círculo


delimitando uma área JMenuBar. Esta área é o espaço para o menu, ou seja
esta classe é quem indica qual vai ser o tipo do menu, neste caso uma barra
de menu.

Logo em seguida verificqmos um indicativo para a classe JMenu, esta


classe é responsável por agrupar itens de um menu como no exemplo acima
agrupar as cores do texto ou as funções de arquivo. Um menu não
necessariamente precisa de uma classe JMenu, pode-se associar diretamente
os itens a JMenuBar. Esta classe pode ser utilizada em todos os tipos de menus
não ficando restrita apenas as barras como veremos mais a frente.

Dentro dos grupos de menu (JMenu) estão colocados os itens (JMenuItem),


esta é a parte funcional e “programável” do menu, ou seja estes são os objetos
que são a pondo final do menu, fazendo uma analogia a uma árvore, os itens
seriam as folhas.

25
Acesso a Banco de Dados

Os itens de menu podem derivar de dois outros tipos também,


JCheckBoxMenuItem e JRadioButtonMenuItem, estes responsáveis por exibirem
um item radio ou check no menu conforme veremos a frente.

Segue o código fonte exemplo que foi utilizado para construção da tela
acima:

package com.targettrust.java.capitulo04;

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

public class ExemploMenu extends JFrame {

JMenuBar barra = new JMenuBar();


JLabel texto = new JLabel();

public ExemploMenu() {
FlowLayout layout = new FlowLayout();
layout.setAlignment(FlowLayout.CENTER);
getContentPane().setLayout(layout);

setTitle("Exemplo de JMenuBar, JMenu e JMenuItem");


setSize( 400, 300 );
setDefaultCloseOperation(EXIT_ON_CLOSE);

JMenu arquivo = new JMenu("Arquivo");


arquivo.setMnemonic('A');

JMenuItem sair = new JMenuItem("Sair");


arquivo.add(sair);

barra.add(arquivo);

JMenu cor = new JMenu("Cor do Texto");


cor.setMnemonic('C');

JMenuItem azul = new JMenuItem("Azul");


JMenuItem vermelho = new JMenuItem("Vermelho");
JMenuItem verde = new JMenuItem("Verde");

cor.add(azul);
cor.add(vermelho);
cor.add(verde);

barra.add(cor);

setJMenuBar(barra);

texto.setText("Curso Java");
texto.setSize(100, 14);
texto.setForeground(Color.BLUE);
getContentPane().add(texto);

// Continua na próxima página


azul.addActionListener(

26
Acesso a Banco de Dados

new ActionListener() {
public void actionPerformed(ActionEvent e) {
texto.setForeground(Color.BLUE);
}
}
);

vermelho.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
texto.setForeground(Color.RED);
}
}
);

verde.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
texto.setForeground(Color.GREEN);
}
}
);

sair.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);

setVisible(true);
}

public static void main(String args[]) {


ExemploMenu app = new ExemploMenu();
}
}
Código: 4-8: Construindo uma barra de menus.

No programa acima, a primeira ação realizada é a criação de uma


instância de JMenuBar chamada barra. Este objeto será o agregador de todos
os itens filhos do menu.

No construtor são criados novos objetos chamados arquivo e cor. Estes


serão os agrupadores (os dois grupos de menus). Ou seja, serão os itens que
ficaram visíveis na barra logo que o programa for executado. Estes recebem
como parâmetro na sua construção o nome a ser exibido ou o Label. Após criar
estes objetos, é realizada uma chamada ao método setMnemonic() da classe
JMenu, o qual definirá qual será a letra da palavra que servirá como atalho
para este menu (exemplo Arquivo, a vogal “A” é a letra ou tecla de atalho para
este menu).

Na seqüência são criados objetos JMenuItem que serão os itens do menu


efetivamente, estes recebem como parâmetro em sua contrução o nome a ser
exibido.

27
Acesso a Banco de Dados

Após os itens do menu criados, o programa realiza a associação destes


itens a seus grupos, através do método add() da classe JMenuItem(), como
exemplo cor.add(azul), onde cor é o JMenu e azul é o JMenuItem, em outras
palavras é feita a ligação do item como menu (grupo).

Da mesma forma como é feita esta relação, também deve-se associar os


JMenu’s a barra de menus (JMenuBar) e isto é feito através do método add() da
classe JMenuBar, por exemplo barra.add(cor), onde é efeivamente feita a
ligação do JMenu (cor) a JMenuBar (barra).

Neste ponto os menus estão configurados e relacionados, então são


adicionados ao JFrame através do método setJMenuBar(barra) e finalmente
executado o método show() do JFrame para que seja exibido o programa em
tela.

Resumindo a montagem do menu. Os menus são associados em cascata,


ou seja, associa-se o item ao grupo que pode estar relacionado a outro grupo
com outros itens e assim sucesivamente até chegar à barra de menus.

Agora o programa começa a associar funcionalidade aos botões e esta é


feita através de implementação de código nos métodos addActionListner() da
classe JMenuItem. Os JMenuItem’s do grupo cor (“Cor do Texto”) possuem
todos o mesmo código fonte, modificando a cor do JLabel da tela para a cor
clicada através dp método setForeground da classe JLabel. O único JMenuItem
com implementação diferente é o “Sair” que efetua uma chamada a
System.exit() encerrando a aplicação.

28
Acesso a Banco de Dados

Utilizando JRadioButtonMenuItem

Conforme citado acima, podemos também utilizar itens radio na


construção de menus para gerar uma situação como a da figura abaixo:

Figura 4-9: Exemplo de utilização de JRadioButtonMenuItem.

Segue abaixo o código exemplo:

package com.targettrust.java.capitulo04;

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

public class ExemploMenuRadioButton extends JFrame {

JMenuBar barra = new JMenuBar();

public ExemploMenuRadioButton() {
FlowLayout layout = new FlowLayout();
layout.setAlignment(FlowLayout.CENTER);
getContentPane().setLayout(layout);

setTitle("Exemplo de JMenuBar, JMenu e JMenuItem");

JMenu cores = new JMenu("Cores");

ButtonGroup grupo = new ButtonGroup();


JRadioButtonMenuItem azul = new JRadioButtonMenuItem("Azul");
JRadioButtonMenuItem verde = new JRadioButtonMenuItem("Verde");
JRadioButtonMenuItem vermelho = new JRadioButtonMenuItem("Vermelho");

grupo.add(azul);

29
Acesso a Banco de Dados

grupo.add(verde);
grupo.add(vermelho);

cores.add(azul);
cores.add(verde);
cores.add(vermelho);

barra.add(cores);

setJMenuBar(barra);

setSize( 400, 300 );


setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}

public static void main(String args[]) {


ExemploMenuRadioButton app = new ExemploMenuRadioButton();
}
}
Código 4-9: Criando menus com JRadioButtonMenuItem.

O programa exemplo acima é semelhante ao programa exibido


anteriormente, desta forma neste tópico será dado enfoque as áreas diferentes
deste código.

A primeira ação para construção de um JRadioButtonMenuItem é a criação


de um grupo de botões. Este grupo tem por função dizer quais são os itens que
estarão inclusos no radio para fins de restringir que exista apenas um item
selecionado do mesmo grupo.

A criação deste grupo é feita através do objeto grupo, instanciado a partir


da classe ButtonGroup.

Na seqüência são criados os itens de JRadioButtonMenuItem


efetivamente, declarando os objetos azul, verde e vermelho. Após a declaração
destes itens, os mesmos são associados ao grupo de botões e após associados
ao JMenu.

Este código fará com que sejam exibidos três itens radio no menu
permitindo a seleção de apenas um destes.

30
Acesso a Banco de Dados

JCheckBoxMenuItem

Conforme citado acima, podemos também utilizar itens check na


construção de menus para gerar uma situação como a da figura abaixo:

Figura 4-10: Exemplo de utilização de JCheckBoxMenuitem.

Segue abaixo o código de exemplo:

package com.targettrust.java.capitulo04;

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

public class ExemploMenuCheckBox extends JFrame {

JMenuBar barra = new JMenuBar();

public ExemploMenuCheckBox() {

FlowLayout layout = new FlowLayout();


layout.setAlignment(FlowLayout.CENTER);
getContentPane().setLayout(layout);

setTitle("Exemplo de JMenuBar, JMenu e JMenuItem");

JMenu estilo = new JMenu("Estilo da Fonte");

JCheckBoxMenuItem negrito = new JCheckBoxMenuItem("Negrito");


JCheckBoxMenuItem italico = new JCheckBoxMenuItem("Italico");
JCheckBoxMenuItem sublinhado = new JCheckBoxMenuItem("Sublinhado");

estilo.add(negrito);
estilo.add(italico);

31
Acesso a Banco de Dados

estilo.add(sublinhado);

barra.add(estilo);
setSize(400, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setJMenuBar(barra);

setVisible(true);
}

public static void main(String args[]) {


ExemploMenuCheckBox app = new ExemploMenuCheckBox();
}
}
Código 4-10: Criando menus com JCheckBoxMenuItem.

O programa exemplo acima funciona exatamente do mesmo modo que os


programas explicados nos tópicos anteriores tendo como única diferença a
substituição dos itens JMenuItem por JCheckBoxMenuItem.

32
Acesso a Banco de Dados

JPopupMenu

A classe JPopupMenu é responsável pela exibição de pequenos menus


(menus de contexto) os quais são muito utilizados nos atuais programas de
computador. No Swing são exibidos ao receberem o gatilho pop-up que
geralmente é disparado com o clicar do botão direito do mouse.

Para ilustrar a explicação acima segue a seguinte imagem de um


JPopupMenu:

Figura 4-11: Exemplo de utilização de JPopupMenu.

No programa abaixo é exibido o código fonte que originou a imagem:

package com.targettrust.java.capitulo04;

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

public class PopupMenu extends JFrame implements ActionListener {


private JPopupMenu popupMenu;

public PopupMenu() {
setTitle("Exemplo de JPopupMenu");
getContentPane().setLayout(null);

JMenuItem menuFileNovo = new JMenuItem("Novo");


JMenuItem menuFileAbrir = new JMenuItem("Abrir");
JMenuItem menuFileSalvar = new JMenuItem("Salvar");
JMenuItem menuFileSair = new JMenuItem("Sair");

popupMenu = new JPopupMenu( "Menu" );


popupMenu.add(menuFileNovo);
popupMenu.add(menuFileAbrir);
popupMenu.add(menuFileSalvar);
popupMenu.addSeparator();
popupMenu.add(menuFileSair);

33
Acesso a Banco de Dados

getContentPane().add(popupMenu);

// Continua na próxima página …


enableEvents(AWTEvent.MOUSE_EVENT_MASK);
menuFileNovo.addActionListener(this);
menuFileAbrir.addActionListener(this);
menuFileSalvar.addActionListener(this);
menuFileSair.addActionListener(this);
setSize(400, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}

public void processMouseEvent( MouseEvent event ) {


if(event.isPopupTrigger() ) {
popupMenu.show(event.getComponent(), event.getX(), event.getY());
}
super.processMouseEvent(event);
}

public void actionPerformed( ActionEvent event ) {


String item = event.getActionCommand();

if(item.equals("Novo")) {
JOptionPane.showMessageDialog(getContentPane(),
"Você clicou em Novo");
} else if(item.equals("Abrir")) {
JOptionPane.showMessageDialog(getContentPane(),
"Você clicou em Abrir");
} else if(item.equals("Salvar")) {
JOptionPane.showMessageDialog(getContentPane(),
"Você clicou em Salvar");
} else if(item.equals("Sair")) {
System.exit(0);
}
}

public static void main(String args[]) {


PopupMenu mainFrame = new PopupMenu();
}

}
Código 4-11: Exemplo de utilização de JPopupMenu

No programa acima é declarado um objeto popupMenu a partir da classe


JPopupMenu. Este objeto será o menu efetivamente.

Logo em seguida, no construtor são declarados quatro objetos JMenuItem,


objetos estes que serão os itens do menu e que recebem como parâmetro em
sua construção o seu texto de exibição.

Tendo o programa declarado o JPopupMenu e seus itens, o próximo passo


é associar os itens ao menu, isto é feito através do método add() da classe
JPopupMenu (objeto popupMenu). Note que existe uma chamada a
addSeparator() enrtre o terceiro e o quarto item, esta é utilizada para exibir
um separador (uma linha entre os menus).

34
Acesso a Banco de Dados

Declarados os objetos e feita a ligação entre o menu e seus itens, o


programa adiciona o menu ao painel padrão do JFrame através do método
getContentPane.add().

Neste ponto o menu esta montado e já é exibido em tela, agora o


programa parte para o controle dos eventos que podem ser gerados pelo
menu.

Prestando atenção ao início do código é visualizado que o programa


implementa a interface ActionListener (ver capítulo sobre controle de
eventos), e portanto implementa o método actionPerformed(). Este método é
executado a cada novo evento gerado, como por exemplo clicar com o mouse
sobre um dos itens do menu.

O método actionPerformed() recebe como parâmetro o objeto ActionEvent


e através da propriedade getActionCommand() deste, encontra qual botão foi
clicado. Para cada botão exibe uma caixa de diálogo com o nome da opção que
originou o evento, exceto ao clicar em sair onde é executado um
System.exit(0) terminando a aplicação.

35
Acesso a Banco de Dados

Entendendo as Caixas de Diálogo

Janelas de diálogos são janelas utilizadas para fazer interação com o


usuário, todas as janelas de diálogo partem de um Frame, ou seja, toda vez
que o frame que esta mantendo aquela janela de diálogo é destruído, os
diálogos vinculados a ele também são, cada vez que Frame é minimizado, os
diálogos desaparecem da tela.

Os diálogos podem ser modais ou não, um diálogo modal é aquele em que


quando exibido bloqueia o Frame que o mantem, em outras palavras impede
que o usuário saia do foco dele para a qualquer outra janela do programa.

Todos os diálogos que utilizamos no Swing derivam da classe JDialog que


tem sua origem na java.awt.Dialog.

Normalmente os programas Swing não utilizam diretamente a classe


JDialog e sim a subclasse JOptionPane, a qual já oferece uma solução de mais
fácil utilização para trabalhar com diversos tipos de diálogo.

36
Acesso a Banco de Dados

JOptionPane

Conforme já explicado na subseção anterior, para construir caixas de


diálogo, normalmente é utilizada a classe JOptionPane. Todos os diálogos
gerados através desta classe são modais. Para construir diálogos não modais,
deve ser utilizado diretamente a classe JDialog.

A classe JOptionPane possui métodos para gerar os tipos de diálogos mais


comumente utilizados.

Qualquer dialogo criado com JOptionPane possui um conjunto de ícones


padrões que podem ser utilizados a fim de preservar o Look And Feel de cada
plataforma, ícones customizados também podem ser adicionados quando
necessário.

Figura 4-12: Ícones padrão do JOptionPane.

Para exibir uma caixa de diálogo simples com um texto e um botão de


“OK”, deve-se utilizar o método JOptionPane.showMessageDialog() conforme
segue:

Figura 4-13: Caixa de diálogo utilizando showMessageDialog().

package com.targettrust.java.capitulo04;

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

public class Dialogo extends JFrame {


public Dialogo() {
setTitle("Exemplo de Dialogo");
setDefaultCloseOperation(EXIT_ON_CLOSE);

37
Acesso a Banco de Dados

setSize(400, 300);
setVisible(true);
JOptionPane.showMessageDialog(getContentPane(), "Mensagem de teste",
"Titulo da mensagem", JOptionPane.INFORMATION_MESSAGE);
}

public static void main(String args[]) {


Dialogo app = new Dialogo();
}
}
Código 4-12: Código fonte para construção de um diálogo utilizando showMessageDialog().

No programa acima é importante destacar os parâmetros para chamada


do método estático showMessageDialog():

WARNING_MESSAGE Mensagem com ícone de atenção do


Look And Feel da plataforma.
ERROR_MESSAGE Mensagem com ícone de erro do Look
And Feel da plataforma.
INFORMATION_MESSAGE Mensagem com ícone de mensagem
do Look And Feel da plataforma.
PLAIN_MESSAGE Mensagem sem ícone
Tabela 3-3: Tipos de mensagem.

Component Frame de referência, é a janela ou o


parentComponent frame onde ficará associado o diálogo.
Object message Mensagem a ser exibida no diálogo,
pode ser uma String ou até mesmo um
painel contendo imagens, etc.
String title Define o título da janela de diálogo.
int messageType Tipo da mensagem a ser exibida,
informação, aviso, erro, etc. (conforme
tabela 3-3).
Icon icon Ícone da mensagem, este é utilizado
para JOptionPane com ícones
personalizados independentes do Look
And Feel.
Tabela 4-4: Parâmetros do método showMessageDialog().

Para exibir uma caixa de dialogo com opções de confirmação podemos


utilizar o método showConfirmDialog(), conforme exemplo abaixo:

38
Acesso a Banco de Dados

Figura 4-13: Caixa de diálogo utilizando JConfirmDialog().

Segue o código fonte utilizado:

package com.targettrust.java.capitulo04;

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

public class ConfirmDialog extends JFrame {


public ConfirmDialog() {
setTitle("Exemplo de Dialogo");

setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(400, 300);
show();

JOptionPane.showConfirmDialog(getContentPane(), "Confirma?");
}

public static void main(String args[]) {


ConfirmDialog app = new ConfirmDialog();
}
}
Código: 4-13: Exibindo um JConfirmDialog.

Consulte a API do SDK para conhecer maiores variações deste método.

Para exibir uma caixa de diálogo JOptionPane personalizada esta


disponível o método showOptionDialog():

Figura 4-14: Utilizando JOptionDialog().

package com.targettrust.java.capitulo04;

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

public class OptionDialog extends JFrame {


private Object[] options = {"Sair sem salvar", "Salvar e sair",
"Voltar ao sistema"};

public OptionDialog() {
setSize(400, 300);
setTitle("Exemplo de Dialogo");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
int selecionado = JOptionPane.showOptionDialog(getContentPane(),
"Existem registros não salvos.", "Sair",

39
Acesso a Banco de Dados

JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE,
null, options, options[0]);
}

public static void main(String args[]) {


OptionDialog app = new OptionDialog();
}

}
Cóldigo 4-14: Utilização de JOptionDialog().

A chamada ao método showOptionDialog(), possui uma sintaxe um pouco


diferente das estudadas anteriormente.

Esta chamada pode ser realizada de duas formas, a primeira delas é


definindo quais serão os botões a exibir através do parâmetro
JOptionPane.YES_NO_OPTION, utilizando um dos disponíveis na tabela abaixo:

YES_NO_OPTION Exibe um dois botões com nome “Sim”


e “Não” conforme configuração do
Look And Feel da plataforma local.
YES_NO_CANCEL_OPTION Exibe um três botões com nome “Sim”,
“Não” e “Cancelar” conforme
configuração do Look And Feel da
plataforma local.
OK_CANCEL_OPTION Exibe um dois botões com nome “Ok”
e “Cancelar” conforme configuração
do Look And Feel da plataforma local.
Tabela 4-5: Conjuntos de botões pré-configurados para JOptionPane.

A segunda forma é como o programa acima realiza, utilizando os dois


últimos parâmetros deste método para informar no primeiro um vetor com o
nome dos botões e no segundo o nome do botão padrão.

40
Acesso a Banco de Dados

JTable

A classe JTable é utilizada para exibir tabelas de dados e caso necessário


permitir que o usuário manipule estes dados.

Para maior compreensão segue o exemplo de criação de uma tabela


simples:

Figura 4-15: Criando uma JTable simples

package com.targettrust.java.capitulo04;

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

public class Tabelas extends JFrame {


public Tabelas() {
getContentPane().setLayout(new GridLayout(1,0));
setTitle("Exemplo de tabelas");

Object[] nomeColunas = {"CÓDIGO", "FRUTA", "COR"};

Object[][] dados = {
{new Integer(1), "Maça", "Vermelho"},
{new Integer(2), "Banana", "Amarelo"},
{new Integer(3), "Limão", "Verde"}
};

JTable tabela = new JTable(dados, nomeColunas);


tabela.setSize(200, 50);

JScrollPane scrollPane = new JScrollPane(tabela);


getContentPane().add(scrollPane);
setSize(400, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}

public static void main(String args[]) {


Tabelas app = new Tabelas();
}

}
Código 4-15: Exemplo de JTable simples.

41
Acesso a Banco de Dados

Observando o programa exemplo a primeira tarefa a ser realizada é a


montagem da origem dos dados. O programa declara uma matriz de Object[][]
e inicializa a mesma com o conteúdo da JTable. Além disto cria um vetor
Object[] contendo os nomes das colunas.

Montada a origem dos dados, é criado o objeto JTable que recebe como
parâmetros os dados obtidos nas linhas anteriores (o vetor e a matriz). Em
seguida é definido o tamanho da tabela.

Após a tabela montada, o programa define um JScrollPane, adiciona a


tabela a ele e por fim adiciona o JScrollPane ao layout. O JScrollPane
automaticamente irá exibir o nome das colunas no cabeçalho e controlará os
scrolls. Caso deseje utilizar uma JTable sem o JScrollPane, o cabeçalho pode ser
definido através da classe JTableHeader, consulte a API SDK para maiores
informações.

Alterando a largura de uma coluna:

Para modificar a largura de visualização de uma coluna, é necessário


utilizar o seguinte código:
tabela.getColumnModel().getColumn(1).setPreferredWidth(5);
Código 4-16: Alterando a largura de visualização de uma coluna.

No exemplo acima verifica-se que o método getColumn() recebe como


parametro um inteiro. Este inteiro é o número da coluna ou a posição no vetor
(iniciando em zero) que possue o nome das colunas.

Utilizando o auto re-dimensionamento de colunas:

A classe JTable através do método setAutoResizeMode() permite que


colunas sejam redimensionadas automaticamente quando são manipuladas
conforme o exemplo abaixo:
tabela.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
Código 4-17: Ajustando automaticamente a largura das colunas.

No exemplo acima verifica-se que o método setAutoResizeMode() recebe


como parametro uma constante que é a propriedade que dita a forma com a
qual vai ser feito o redimensionamento. Segue abaixo uma tabela com as
constantes disponíveis e suas funções:

42
Acesso a Banco de Dados

AUTO_RESIZE_SUBSEQUENT_COLUM É a forma padrão de


NS redimensionamento. Ajusta todas
as colunas posteriores a coluna
modificada.
AUTO_RESIZE_NEXT_COLUMN Ajusta somente as colunas
imediatamente a esquerda ou a
direita da coluna modificada.
AUTO_RESIZE_ALL_COLUMNS Redimensiona todas as colunas
da tabela.
AUTO_RESIZE_OFF Desliga o redimensionamento
automático de colunas.
Tabela 4-6: Modos de redimensionamento automático de colunas em uma JTable.

43
Acesso a Banco de Dados

JScrollPane

JScrollPane fornece uma visão com scroll de um componente da GUI.


Normalmente é utilizado quando o tamanho de uma tela é menor que a
quantidade de informações que se deseja mostrar. Em outras palavras
JScrollPane é responsável pela exibição de barras de rolagem.

O código para impelentação de um JScrollPane é extremamente simples


veja o exemplo abaixo:

Figura 4-17: Exemplo de JScrollPane.

package com.targettrust.java.capitulo04;

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

public class ExemploScroll extends JFrame {


private JTextArea jTextArea1 = new JTextArea();
private Container c;

public ExemploScroll() {
c = getContentPane();
getContentPane().setLayout(new BorderLayout());

setTitle("Exemplo de JScrollPane");

jTextArea1.setBounds(new Rectangle(70, 45, 210, 140));


JScrollPane scroll = new JScrollPane(jTextArea1);
getContentPane().add(scroll, BorderLayout.CENTER);

setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(400, 300);
setVisible(true);
}

public static void main(String args[]) {


ExemploScroll app = new ExemploScroll();
}
}
Código 4-18: Exemplo de utilização de JScrollPane

44
Acesso a Banco de Dados

No programa exemplo utilizado, é declarada uma JTextArea, logo em


seguida instanciado um objeto de JScrollPane recebendo como parâmetro a
JTextArea e por fim o scroll que possui a caixa de texto é associado ao layout.
Note bem que a caixa de texto não foi adicionada ao layout, mas sim ao scroll
e este por sua vez adicionado.

Ou seja, a utilização de JScrollPane é extremamente simples, instencia-se


um novo objeto passando-se a ele o objeto de destino a ser adicionado o scrol
e por fim este é adicionado ao layout.

O JScrollPane permite que sejam criadas regras para exibição ou não das
barras de rolagem, estas regras são definidas através dos seguintes métodos
que recebem os parâmetros (constantes) indicados nas tabelas seguintes:

setHorizontalScrollBarPolicy
HORIZONTAL_SCROLLBAR_AS_NEED Barra de rolagem exibida
ED somente quando necessário.
HORIZONTAL_SCROLLBAR_ALWAYS Barra de rolagem exibida
independente da necessidade.
HORIZONTAL_SCROLLBAR_NEVER Barra de rolagem nunca é
exibida.
Tabela 4-7: Regras para exibição de bara de rolagem horizontal

setVerticalScrollBarPolicy
VERTICAL_SCROLLBAR_AS_NEEDED Barra de rolagem exibida
somente quando necessário.
VERTICAL_SCROLLBAR_ALWAYS Barra de rolagem exibida
independente da necessidade.
VERTICAL_SCROLLBAR_NEVER Barra de rolagem nunca é
exibida.
Tabela 4-8: Regras para exibição de bara de rolagem vertical

45
Acesso a Banco de Dados

JFileChooser

JFileChooser exibe uma GUI para navegar pelo sistema de arquivos


escolher arquivos ou diretórios, é a conhecida janela para seleção de arquivo
(Ex: Abrir..., Salvar..., etc.).

O Look And Feel irá determinar o que será exibido de opções nestas caixas
de diálogo.

Figura 4-18: Exemplo de JFileChooser.

package com.targettrust.java.capitulo04;

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

public class Arquivo extends JFrame {


private JFileChooser file = new JFileChooser();
private Container c;

public Arquivo() {
c = getContentPane();
c.setLayout(null);
setTitle("Exemplo de JFileChooser");

JButton botao = new JButton("Selecionar Arquivo");


botao.setSize(100, 30);
c.add(botao);

botao.addActionListener(
new ActionListener() {

46
Acesso a Banco de Dados

public void actionPerformed(ActionEvent e ) {


if (file.showOpenDialog(getContentPane()) ==
JFileChooser.APPROVE_OPTION)
{
JOptionPane.showMessageDialog(getContentPane(),
file.getSelectedFile().getName()
);
}
else {
JOptionPane.showMessageDialog(getContentPane(),
"Operação cancelada");
}
}
}
);
setSize(400, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}

public static void main(String args[]) {


Arquivo app = new Arquivo();
}

}
Código: 4-19: Exemplo de utilização de JFileChooser.

No programa acima, é criado um botão (JButton) chamado “Selecionar


Arquivo”, ao clicar em selecionar arquivo é exibida uma janela de escolha de
arquivos no sistema de arquivos.

Para exibir esta janela é utilizado o método showOpenDialog() a classe


JFileChooser. Este método retorna um inteiro com o botão clicado pelo usuário
na janela de selção de arquivos. Este inteiro é testado e caso refira-se a um
OK, exibe o nome do arquivo selecionado, caso contrário exibe um alerta de
operação cancelada.

Para permitir que o usuário selecione apenas diretórios e não arquivos


pode-se utilizar o método:

file.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
Código 4-20: Exemplo de seleção de diretórios com JFileChooser.

Para maiores informações consulte a API SDK sobre JFileChooser.

47
Acesso a Banco de Dados

Exercícios

Neste capítulo você conheceu os componentes gráficos mais comuns para


criação de interfaces gráficas. Agora você irá praticar alguns destes
componentes em um exercício.

1. Crie uma interface gráfica como mostrado na figura abaixo:

48
Acesso a Banco de Dados

Espaço para anotações

49
5.Look And Feel

1
Acesso a Banco de Dados

Objetivos
• Conhecer o funcionamento do Look And Feel
• Aplicar o recurso de Look And Feel na aplicação

2
Acesso a Banco de Dados

Aparência e Comportamento

Um programa que utiliza componentes GUI do Abstract Windowing Toolkit


de Java (pacote java.awt) assume a aparência e comportamento da plataforma
em que o programa executa. Um programa Java executando em um Macintosh
se parece com outros programas que executam em um Macintosh.

Um programa Java executando no Microsoft Windows se parece com


outros programas que executam no Microsoft Windows.

Um programa Java que executa em uma plataforma UNIX se parece outros


programas que executam nessa plataforma UNIX. Isso pode ser desejável, uma
vez que permite aos usuários do programa em cada plataforma utilizar os
componentes GUI com que eles já estão familiarizados. Entretanto, isso
também introduz questões interessantes de portabilidade.

Componentes GUI do Swing de peso leve eliminam muitas dessas


questões fornecendo funcionalidade uniforme de uma plataforma para outra e
definindo aparência e comportamento uniformes para diversas plataformas é
conhecida como aparência de metal - metal look-and-feel). O Swing também
fornece a flexibilidade para personalizar a aparência e comportamento com o
estilo do Microsoft Windows ou com o estilo do Motif (UNIX).

O exemplo abaixo demonstra como alterar a aparência e comportamento


de uma GUI do Swing. O programa cria vários componentes GUI para permitir
ver a alteração na aparência e comportamento de vários componentes GUI ao
mesmo tempo.

A primeira janela da saída mostra a aparência padrão de metal, a segunda


janela de saída mostra a aparência e comportamento do Motif e a terceira
janela de saída mostra a aparência e comportamento do Windows.

package com.target.swing.capitulo05;

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

public class LookAndFeelDemo extends JFrame {

private String strings[] = { "Metal", "Motif", "Windows" };

private UIManager.LookAndFeelInfo[] looks =


UIManager.getInstalledLookAndFeels();

private JRadioButton[] radio;

3
Acesso a Banco de Dados

private ButtonGroup group;


private JButton button;
private JLabel label;
private JComboBox comboBox;

private class ItemHandler implements ItemListener {

public void itemStateChanged( ItemEvent e ) {


// varre os itens para ver qual foi selecionado
for ( int i = 0; i < radio.length; i++ )
if ( radio[ i ].isSelected() ) {
label.setText( "This is a " + strings[ i ] +
" look-and-feel" );
comboBox.setSelectedIndex( i );
change( i );
}
}
}

public LookAndFeelDemo() {
super( "Look and Feel Demo" );

Container c = getContentPane();

JPanel northPanel = new JPanel();


northPanel.setLayout( new GridLayout( 3, 1, 0, 5 ) );

label = new JLabel( "This is a Metal look-and-feel",


SwingConstants.CENTER );
northPanel.add( label );

button = new JButton( "JButton" );


northPanel.add( button );

comboBox = new JComboBox( strings );


northPanel.add( comboBox );

c.add( northPanel, BorderLayout.NORTH );

JPanel southPanel = new JPanel();

radio = new JRadioButton[ strings.length ];


group = new ButtonGroup();

LookAndFeelDemo.ItemHandler handler = new


LookAndFeelDemo.ItemHandler();

southPanel.setLayout( new GridLayout( 1, radio.length ) );

for ( int i = 0; i < radio.length; i++ ) {


radio[ i ] = new JRadioButton( strings[ i ] );
radio[ i ].addItemListener( handler );
group.add( radio[ i ] );
southPanel.add( radio[ i ] );
}

c.add( southPanel, BorderLayout.SOUTH );

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize( 300, 200 );
setVisible(true);
4
Acesso a Banco de Dados

radio[ 0 ].setSelected( true );


}

private void change( int value ) {


try {
UIManager.setLookAndFeel( looks[ value ].getClassName() );
SwingUtilities.updateComponentTreeUI( this );
}
catch ( Exception e ) {
e.printStackTrace();
}
}

public static void main( String args[] ) {


LookAndFeelDemo dx = new LookAndFeelDemo();
}

}
Código 5-1: Exemplo de utilização de Look And Feel

O programa acima define o Look And Feel a ser utilizado através de


programação. Além desta forma, o Look And Feel pode ser definido de outras
duas maneiras conforme segue:

Definindo o Look And Feel através de linha de comando:

Definindo o Look And Feel por linha de comando é possível deixar a


aplicação configurável para que possa ter sua aparênciia e comportamento
modificado sem necessidade de alteração de programa ou configuração.

A execução da aplicação deve seguir o exemplo abaixo:

java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel MyApp


Código 5-2: Exemplo de configuração do Look And Feel através da linha de comando.

Definindo o Look And Feel através do arquivo swing.properties:

Outra maneira de determinar o Look And Feel de uma aplicação Swing é


através do arquivo de configuração swing.properties. Este arquivo esta
localizado no diretório lib do distribuição Java.

Dentro do arquivo, o Look And Feel é definido na seguinte linha:

# Swing properties

swing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel

5
Acesso a Banco de Dados

Exercícios

1. Para a aplicação montada anteriormente adicione o recurso de troca de


aparência gráfica ao item de menu Look And Feel

2. Antes da criação do JFrame na interface da sua aplicação insira a


seguinte linha de comando para que a aparência do JFrame seja alterada.

JFrame.setDefaultLookAndFeelDecorated(true);

6
Acesso a Banco de Dados

Espaço para anotações

7
Acesso a Banco de Dados

8
6.Arquivos

1
Acesso a Banco de Dados

Objetivos
• Apresentar os fluxos de dados:

• InputStream

• OutputStream

• Conhecer classes que permitam:

• Serializar objetos

• Gravar arquivos texto

• Verificar como funciona o coletor de lixo

• Implementar estes recursos na aplicação do curso

2
Acesso a Banco de Dados

Introdução

O armazenamento de dados em variáveis e arrays é temporário – os


dados são perdidos quando uma variável local sai do escopo ou quando o
programa terminar. Arquivos são utilizados para retenção a longo prazo de
grandes quantidades de dados, mesmo depois de terminar o programa que
criou os dados.

Os dados mantidos em arquivos são freqüentemente chamados de dados


persistentes. Os computadores armazenam arquivos em dispositivos de
armazenamento secundários como discos magnéticos, discos ópticos e fitas
magnéticas.

Neste capítulo, veremos como arquivos de dados são criados, atualizados


e processados por programas Java. O processamento de fluxos é um assunto
extenso.

O processamento de arquivos é um dos recursos mais importantes que


uma linguagem deve ter para suportar aplicativos comerciais que, em geral,
processam quantidades maciças de dados persistentes. Neste capitulo,
discutire-mos os poderosos e abundantes recursos de processamento de
arquivos e de fluxos de entrada/saída de Java.

3
Acesso a Banco de Dados

Hierarquia de Dados

Em última instância, todos os itens de dados processados por um


computador são reduzidos a combinações de zeros e uns.

Isso ocorre porque é simples e econômico construir dispositivos


eletrônicos que podem assumir dois estados estáveis – um estado representa 0
e o outro estado representa 1. É notável que as impressionantes funções
realizadas pelos computadores envolvam somente as manipulações mais
fundamentais de 0s e 1s.

O menor item de dados em um computador pode assumir o valor 0 ou o


valor 1. Esse item de dados é chamado de bit (abreviação de “binary digit” —
um dígito que pode assumir um de dois valores).

Os circuitos de computador realizam várias manipulações de bits simples,


tais como examinar o valor de um bit, configurar o valor de um bit e inverter
um bit (de 1 para 0 ou de 0 para 1).

É incômodo para programadores trabalhar com dados na forma de baixo


nível de bits. Em vez disso, os programadores preferem trabalhar com dados
em formas como dígitos decimais (isto é, 0, 1, 2, 3, 4, 5, 6, 7, 8 e 9),letras (por
exemplo, A a Z e a a z) e símbolos especiais (isto é, $, @, %, &, ~, (,), -, +, ~,
:,?, 1 e muitos outros).

Os dígitos, as letras e os símbolos especiais são referidos como


caracteres. O conjunto de todos caracteres utilizado para escrever programas
e representar itens de dados em um computador particular é chamado de o
conjunto de caracteres desse computador.

Como os computadores podem processar somente 1s e 0s, cada caractere


em um conjunto de caracteres do computador é representado como um
padrão de 1s e 0s (caracteres em Java são caracteres unicode compostos de 2
bytes).

Os bytes são mais comumente compostos de oito bits. Os programadores


criam programas e dados com caracteres; os computadores manipulam e
processam esses caracteres como padrões de bits.

Assim como os caracteres são compostos de bits, os campos são


compostos de caracteres. Um campo é um grupo de caracteres que possui um
significado. Por exemplo, um campo consistindo em letras minúsculas e
maiúsculas pode ser utilizado para representar um nome de pessoa.

Os dados processados por computadores formam uma hierarquia de


dados em que itens de dados tomam-se maiores e mais complexos em termos
de estrutura à medida que progredimos de bits, para caracteres, para campos;
etc.

4
Acesso a Banco de Dados

Um registro (isto é, uma class em Java) é geralmente composto de vários


campos (chamados de variáveis de instância em Java). Em um sistema de
folha de pagamento, por exemplo, um registro para um empregado particular
talvez consista nos seguintes campos:
• Número de identificação do empregado

• Nome

• Endereço

• Salário-hora

• Número de isenções reivindicadas

• Lucros no ano até a data atual

• Total de impostos retidos

Portanto, um registro é um grupo de campos relacionados. No exemplo,


cada um dos campos pertence ao mesmo empregado. Naturalmente, uma
empresa particular pode ter muitos empregados e terá um registro de folha de
pagamento para cada empregado. Um arquivo é um grupo de registros
relacionados.

O arquivo de folha de pagamento de uma empresa normalmente contém


um registro para cada empregado. Portanto, um arquivo de folha de
pagamento de uma empresa pequena talvez contenha apenas 22 registros,
enquanto um arquivo de folha de pagamento de uma empresa grande talvez
contenha 100.000 registros.

Não é incomum uma empresa ter muitos arquivos, que contêm alguns
milhões, ou mesmo bilhões, de caracteres de informações.

Para facilitar a recuperação de registros específicos de um arquivo, pelo


menos um campo em cada registro éescolhido como uma chave de registro.

Uma chave de registro identifica um registro como pertencente a uma


parti-cular pessoa ou entidade que é única dentre todos os outros registros. No
registro de folha de pagamento descrito anteriormente, o número de
identificação do empregado normalmente seria escolhido como a chave de
registro.

Há muitas maneiras de organizar registros em um arquivo. O tipo de


organização mais comum é chamado de arquivo seqúencial, no qual os
registros são geralmente armazenados em ordem pelo campo-chave de
registro.

Em um arquivo de folha de pagamento, os registros normalmente são


ordenados pelo número de identificação do empregado.

5
Acesso a Banco de Dados

O primeiro registro de empregado no arquivo contém o número mais baixo


de identificação de empregado e os registros subseqúentes contêm números
de identificação de empregado cada vez mais altos.

A maioria das empresas utiliza muitos arquivos diferentes para armazenar


dados. Por exemplo, empresas podem ter arquivos de folha de pagamento,
arquivos de contas a receber (listagem de valores devidos por clientes),
arquivo de contas a pagar (listagem de valores devidos a fornecedores),
arquivo de inventário (listagem de fatos sobre todos os itens abrangidos pelo
negócio) e muitos outros tipos de arquivo.

Um grupo de arquivos relacionados às vezes é chamado de banco de


dados. Uma coleção de programas projetados para criar e gerenciar bancos de
dados é chamada de sistema de gerenciamento de bancos de dados (database
management system - DBMS).

6
Acesso a Banco de Dados

Arquivos e Fluxos

Java vê cada arquivo como um fluxo seqüencial de bytes. Cada arquivo


acaba com um marcador de fim do arquivo ou em um número específico de
byte registrado em uma estrutura administrativa de dados mantida pelo
sistema. Quando um arquivo é aberto, um objeto é criado e um fluxo é
associado com o objeto.

Três objetos de fluxo são criados para nós automaticamente quando


iniciamos a execução de um programa Java – System.in, System.out e
System.err. Os fluxos associados com esses objetos fornecem canais de
comunicação entre um programa e um arquivo ou dispositivo particular.

Por exemplo, o objeto System.in (objeto de fluxo de entrada padrão)


permite que um programa insira bytes via teclado, o objeto System.out (objeto
de fluxo de saída padrão) permite a um programa dar saída a dados na tela e o
objeto System.err (objeto defluxo de erro padrão) permite a um programa dar
saída a mensagens de erro na tela.

Cada um desses fluxos pode ser redireciona-do por exemplo, System.out


pode ser redirecionado para enviar sua saída para um arquivo em disco.

Para realizar processamento de arquivos em Java, o pacote java.io deve


ser importado. Esse pacote inclui definições para as classes de fluxo como
FilelnputStream (para entrada de um arquivo) e FileOutputStream (para saída
para um arquivo).

Os arquivos são abertos criando-se objetos dessas classes de fluxo que


herdam das classes InputStream e OutputStream, respectivamente. Portanto,
os métodos dessas classes de fluxo também podem ser aplicados a fluxos de
arquivo.

Para realizar entrada e saída de tipos de dados, os objetos de classe


ObjectlnputStream, DatalnputStream, ObjectQutputStream e
DataOutputStream serão utilizados junto com as classes de fluxo de arquivo.
Os relacionamentos de herança de muitas das classes de E/S de Java estão
resumidos no polígrafo.

Java oferece muitas classes para realizar entrada/saída. Fornecemos uma


breve visão geral de cada uma e como elas se relacionam entre si. Colocamos
várias classes de fluxo chave para trabalhar à medida que implementamos
uma variedade de programas de processamento de arquivos que criam,
manipulam e destroem arquivos de acesso seqüencial.

InputStream (uma subclasse de Object) e OutputStream (uma subclasse


de Object) são classes abstract que definem métodos para realizar entrada e
saída respectivamente; suas classes derivadas sobrescrevem esses métodos.

7
Acesso a Banco de Dados

A entrada/saída de arquivos é feita com FilelnputStream (uma subclasse


de InputStream) e FileOutputStream (uma subclasse de OutputStream).

Os pipes são canais de comunicação sincronizados entre threads. Um pipe


é estabelecido entre dois threads. Um thread envia dados para outro gravando
em uma PipedOutputStream (uma subclasse de OutputStream).

A thread de destino lê as informações do pipe via um PipedInputStream


(uma subclasse de InputStream).

Parte da hierarquia de classes do pacote java.io:

java.lang.Object
File
FileDescriptor
InputStream
ByteArraylnputStream
FilelnputStream
FilterlnputStream
BufferedlnputStream
DatalnputStream
PushbacklnputStream
ObjectlnputStream
PipedlnputStream
SequencelnputStream
OutputStream
ByteArrayOutputStream
FileOutputStream
FilterOutputStream
BufferedOutputStream
DataOutputStream
PushbackOutputStream
ObjectOutputStream
PipedOutputStream

Uma PrintStream (uma subclasse de FilterOutputStream) é utilizada para


enviar a saída para a tela (ou a “saída-padrão” como definido por seu sistema
operacional local).

Na verdade, temos utilizado a saída PrintStream por todo o texto até este
ponto; System.out é um PrintStream (assim como System.err).

Um FilterlnputStream filtra um InputStream e um FilterOutStream filtra um


OutputStream; filtrar significa simplesmente que o fluxo de filtro fornece
funcionalidade adicional como armazenamento em buffer, monitoramento de
números de linha ou agregação de bytes de dados em unidades que formam
um tipo de dados primitivo.
8
Acesso a Banco de Dados

Ler dados diretamente como bytes é rápido mas grosseiro. Normalmente


os programas lêem dados como agregados de bytes que formam um int, um
float, um double e assim por diante.

A interface DataInput é implementada pela classe DataInputStream


(discutidas mais adiante neste capítulo), a qual precisa ler tipos de dados
primitivos de um fluxo. DataInputStreams permitem a um programa ler dados
binários de um InputStream.

A interface DataInput inclui métodos read (para os arrays de byte),


readBoolean, readByte, readChar, readDouble, readFloat, readFully (para
arrays de byte), readInt, readLong, readShort, readUnsignedByte,
readUnsignedShort, readUTF (para Strings) e skipBytes.

A interface DataOutput é implementada pela classe DataOutputStream


(uma subclasse de FilterOutputStream), a qual precisa gravar tipos de dados
primitivos em um OutputStream.

DataOutputStreams permitem a um programa gravar dados binários em


um OutputStream. A interface DataOutput inclui métodos flush, size, write
(para um byte), write (para um array de byte), writeBoolean, writeByte,
writeBytes, writeChar, writeChars (para Strings Unicode), writeDouble,
writeFloat, writeInt, writeLong, writeShort e writeUTF.

O armazenamento em buffer (buffering) é uma técnica de aprimoramento


do desempenho de EIS. Com um BufferedOutputStream (uma subclasse de
classe FilterOutputStream), cada instrução de saída não resulta
necessariamente em uma transferência fisica real de dados para o dispositivo
de saída.

Em vez disso, cada operação de saída é dirigida para uma região na


memória, chamada buffe;; que é suficientemente grande para armazenar os
dados de muitas operações de saída. Então a transferência real para o
dispositivo de saída é realizada em uma grande operação física de saída toda
vez que o buffer se enche.

As operações de saída dirigidas para o buffer de saída na memória são


freqüentemente chamadas de operações lógicas de saída. Com um
BufferedInputStream (uma subclasse de classe FilterInputStream), muitos
pedaços ou trechos “lógicos” de dados de um arquivo são lidos como uma
grande operação física de entrada em um buffer de memória.

A medida que o programa solicita cada novo trecho dos dados, é feita
uma busca no buffer (isso é ás vezes referido como uma operação lógica de
entrada).

Quando o buffer está vazio, a operação física de entrada do dispositivo de


entrada é realizada lendo (read in) o próximo grupo de trechos “lógicos” de
dados. Portanto, o número de operações físicas reais de entrada é pequeno
comparado com o número de solicitações de leitura emitido pelo programa.

9
Acesso a Banco de Dados

Com um BufferedOutputStream, um buffer parcialmente preenchido pode


ser forçado a dar saída no dispositivo a qualquer momento com um flush
explícito como segue:

testBufferedoutputStream.flush();

Código 6-1: Descarga do buffer

Uma PushBackInputStream (uma subclasse de classe FilterInputStream) é


utilizada para aplicações mais exóticas que a maioria dos usuários precisa.
Essencialmente, o aplicativo que lê um PushBackInputStream lê bytes do fluxo
e forma agregados consistindo em vários bytes.

As vezes, para determinar que o agregado está completo, o aplicativo


deve ler o primeiro caractere além do fim (“past the end”) do primeiro
agregado.

Uma vez que o programa determinou que o agregado atual está completo,
o caractere extra é reinserido (“pushed back”) no fluxo. PushBackInputStreams
são utilizados por programas como compiladores que analisam sintaticamente
(parse) suas entradas, isto é, eles as dividem em unidades significativas (como
palavras-chave, identificadores e operadores que o compilador Java deve
reconhecer).

Quando variáveis de instância de objetos são enviadas para a saída em


um arquivo de disco, em certo sentido perdemos as informações do tipo do
objeto. Em um disco, temos apenas dados, não as informações de tipo. Se o
programa que lerá esses dados conhece o tipo de objeto a que eles
correspondem, então esses dados são simplesmen-te lidos para objetos desse
tipo.

As vezes, queremos ler ou gravar um objeto inteiro em um arquivo. As


classes ObjectInputStreams e ObjectoutputStream, que implementam
respectivamente as interfaces ObjectInput e ObjectOutput, são utilizadas para
esse propósito. Freqüentemente encadeamos ObjectInputStreams com
FileInputStreams (Também encadeamos ObjectOutputStreams com
FileOutputStreams).

A interface ObjectOutput tem um writeObject que aceita um Object como


um argumento e grava suas informações na OutputStream.
Correspondentemente, a interface ObjectInput requer o método readObject,
que lê e retorna um Object de um InputStream.

Esse objeto, então, pode sofrer coerção para o tipo desejado. Além disso,
essas interfaces incluem outros métodos centrados em Object, bem como os
mesmos métodos que DataInput e DataOutput para leitura e gravação de tipos
de dados primitivos.

10
Acesso a Banco de Dados

O fluxo de E/S de Java inclui capacidades para entrada de arras de byte na


memória e saída de arrays de byte na memória. Um ByteArrayInputStream
(uma subclasse da classe abstract InputStream) realiza suas entradas a partir
de um array de byte na memória.

Um ByteArrayOutputStream (uma subclasse da classe


abstractOutputStream) coloca a saída em um array de byte na memória. Uma
aplicação da E/S de array de byte é a validação de dados.

Um programa pode inserir uma linha inteira por vez do fluxo de entrada
em um array de byte. Então uma rotina de validação pode escrutinar o
conteúdo do array de byte e corrigir os dados, se necessário.

O programa agora pode continuar a entrada a partir do array de byte,


sabendo que os dados de entrada estão no formato adequado. Dar saída para
um array de byte é uma boa maneira de tirar proveito das poderosas
capacidades de formatação de fluxos de saída de Java.

Os dados podem ser preparados em um array de byte para simular o


formato editado de tela. Esse array, então, grava em um arquivo de disco para
preservar a imagem de tela.

Uma SequenceInputStream (uma subclasse da classe


abstractInputStream) permite que vários InputStreams sejam concatenados de
modo que o programa veja o grupo como um único InputStream. À medida que
o fim de cada fluxo de entrada é alcançado, o fluxo é fechado e o próximo fluxo
na seqüência é aberto.

A classe BufferedReader (uma subclasse da classe abstract Reader) e a


classe BufferedWriter (uma subclasse da classe abstract Writer) permitem
eficiente armazenamento em buffer para fluxos baseados em caracteres.

Fluxos baseados em caracteres utilizam caracteres Unicode — esses


fluxos podem processar dados em qualquer linguagem que seja representada
pelo conjunto de caracteres Unicode.

A classe CharArrayReader e a classe CharArrayWriter lêem e gravam um


fluxo de caracteres em um array de caracteres.

Uma PushbackReader (uma subclasse da classe abstract FilterReader)


permite que caracteres sejam colocados de volta em um fluxo de caracteres.
Uma LineNumberReader (uma subclasse de BufferedReader) fornece um fluxo
buferizado de caracteres que monitora números de linha (isto é, uma nova
linha, um retorno de carro ou uma combinação de quebra de linha e de retorno
de carro).

As classes FileReader (uma subclasse de InputStreamReader) e FileWriter


(uma subclasse de OutputStreamWriter) lêem e gravam caracteres em um
arquivo.

11
Acesso a Banco de Dados

As classes PipedReader e PipedWriter fornecem fluxos de caracteres


colocados em pipe. As classes StringReader e StringWriter lêem e gravam
caracteres em Strings. Uma PrintWriter grava caracteres em um fluxo.

A classe File permite que os programas obtenham informações sobre um


arquivo ou diretório.

12
Acesso a Banco de Dados

Testando Arquivos

A aplicação posterior é responsável por realizar o teste em um File


verificando se o usuário está tentando abrir um arquivo ou diretório a partir do
JTextField especificado na tela. Caso o usuário informe um path de um arquivo
o programa efetua a listagem dele, informando as principais características de
um arquivo qualquer.

package com.targettrust.java.capitulo06;

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

public class FileTest extends JFrame implements ActionListener {


private JTextField enter;
private JTextArea output;

public FileTest() {
super( "Testando a classe File" );

enter = new JTextField("Digite o caminho do arquivo ou diretório:" );


enter.addActionListener( this );

output = new JTextArea();

Container c = getContentPane();
ScrollPane p = new ScrollPane();

p.add( output );
c.add( enter, BorderLayout.NORTH );
c.add( p, BorderLayout.CENTER );

setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 400, 400 );
setVisible(true);
}

public void actionPerformed( ActionEvent e ) {


File name = new File( e.getActionCommand() );

// Se existe o arquivo
if ( name.exists() ) {
output.setText(
name.getName() + " existe\n" +
( name.isFile() ? "é um arquivo\n" : "é um arquivo\n" ) +
( name.isDirectory() ? "is a directory\n" : "é um diretório\n") +
( name.isAbsolute() ? "is absolute path\n" : "não é um caminho
absoluto\n" ) +
"\nÚltima modificação: " + name.lastModified() +
"\nTamanho: " + name.length() +
"\nCaminho: " + name.getPath() +
"\nCaminho absoluto: " + name.getAbsolutePath() +

13
Acesso a Banco de Dados

"\nDiretório pai: " + name.getParent() );

if ( name.isFile() ) {
try {
RandomAccessFile r = new RandomAccessFile( name, "r" );
StringBuffer buf = new StringBuffer();
String text;
output.append( "\n\n" );
while( ( text = r.readLine() ) != null ) {
buf.append( text + "\n" );
}
output.append( buf.toString() );
}
catch( IOException e2 ) {
JOptionPane.showMessageDialog( this, "FILE ERROR",
"FILE ERROR", JOptionPane.ERROR_MESSAGE );
}
}
else if ( name.isDirectory() ) {
String directory[] = name.list();
output.append( "\n\nConteúdo do diretório:\n");
for ( int i = 0; i < directory.length; i++ )
output.append( directory[ i ] + "\n" );
}
}
else {
JOptionPane.showMessageDialog(this, e.getActionCommand()+
" Não existe","FILE ERROR",JOptionPane.ERROR_MESSAGE);
}
}
public static void main( String args[] ) {
FileTest app = new FileTest();
}
}

Código 6-2: Testando a classe File

Caso o usuário digitar um path de diretório será realizado uma listagem de


arquivo e subdiretórios pertencentes ao diretório corrente.

14
Acesso a Banco de Dados

Figura 6-1: Classe FileTest rodando

15
Acesso a Banco de Dados

Criando um Arquivo

Java não impõe nenhuma estrutura a um arquivo. Logo, noções como


“registro” não existem em arquivos Java. Portanto, o programador deve
estruturar arquivos para atender aos requisitos de aplicativos. No exemplo a
seguir, vemos como o programador impõe uma estrutura simples de registro a
um arquivo.

O exemplo cria um arquivo de acesso seqüencial simples que poderia ser


utilizado em um sistema de contas a receber para ajudar a gerenciar o valor
devido por um cliente da empresa. Para cada cliente, o programa obtém um
número de conta, o primeiro nome, o sobrenome e o saldo do cliente (isto é, a
quantia que o cliente ainda deve à empresa pelas mercadorias e serviços
recebidos no passado).

Os dados obtidos para cada cliente constituem um registro desse cliente.


O número da conta é utilizado como chave de registro nesse aplicativo; isto é,
o arquivo será criado e mantido ordenado pelo número de conta.

Esse programa assume que o usuário insere os registros em ordem de


número de conta. Em um sistema abrangente de contas a receber, um recurso
de classificação é fornecido para o usuário poder inserir o registro em qualquer
ordem – os registros então seriam classificados e gravados no arquivo.

package com.targettrust.java.capitulo06;

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

public class BankUI extends JPanel {

protected final static String names[] = {"Account number",


"First name",
"Last name",
"Balance"
};
protected JLabel labels[];
protected JTextField fields[];
protected JButton doTask, doTask2;
protected JPanel innerPanelCenter, innerPanelSouth;
protected int size = 4;

public BankUI() {
this( 4 );
}

public BankUI( int mySize ) {


size = mySize;

16
Acesso a Banco de Dados

labels = new JLabel[ size ];


fields = new JTextField[ size ];

for ( int i = 0; i < labels.length; i++ ) {


labels[ i ] = new JLabel( names[ i ] );
}

for ( int i = 0; i < fields.length; i++ ) {


fields[ i ] = new JTextField();
}

innerPanelCenter = new JPanel();


innerPanelCenter.setLayout( new GridLayout( size, 2 ) );

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


innerPanelCenter.add( labels[ i ] );
innerPanelCenter.add( fields[ i ] );
}

doTask = new JButton();


doTask2 = new JButton();

innerPanelSouth = new JPanel();

innerPanelSouth.add( doTask2 );
innerPanelSouth.add( doTask );

setLayout( new BorderLayout() );


add( innerPanelCenter, BorderLayout.CENTER );
add( innerPanelSouth, BorderLayout.SOUTH );
validate();
}

public void clearFields() {


for ( int i = 0; i < size; i++ ) {
fields[ i ].setText( "" );
}
}

public JButton getDoTask() {


return doTask;
}

public JButton getDoTask2() {


return doTask2;
}

public JTextField[] getFields() {


return fields;
}

public String[] getFieldValues() {


String values[] = new String[ size ];

for ( int i = 0; i < size; i++ )


values[ i ] = fields[ i ].getText();

return values;
}

17
Acesso a Banco de Dados

public void setFieldValues( String s[] ) throws


IllegalArgumentException {
if ( s.length != size ) {
throw new IllegalArgumentException( "There must be " + size
+ " Strings in the array" );
}

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


fields[ i ].setText( s[ i ] );
}
}
}

Código 6-3: Código da classe para o painel BankUI

package com.targettrust.java.capitulo06;

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

public class BankAccountRecord implements Serializable {

private int account;


private String firstName;
private String lastName;
private double balance;

public BankAccountRecord() {
this( 0, "", "", 0.0 );
}

public BankAccountRecord( int acct, String first, String last,


double bal ) {
account = acct;
setFirstName( first );
setLastName( last );
setBalance( bal );
}

public int getAccount() {


return account;
}

public double getBalance() {

18
Acesso a Banco de Dados

return balance;
}

public String getFirstName() {


return firstName;
}

public String getLastName() {


return lastName;
}

public void setAccount( int acct ) {


account = acct;
}

public void setBalance( double bal ) {


balance = bal;
}

public void setFirstName( String first ) {


firstName = first;
}

public void setLastName( String last ) {


lastName = last;
}
}

Código 6-4: Classe para representar um “registro” de conta

package com.targettrust.java.capitulo06;

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

public class CreateFile extends JFrame {

private ObjectOutputStream output;


private BankUI userInterface;
private JButton enter, open;

public CreateFile() {
super( "Creating a Sequential File of Objects" );
getContentPane().setLayout( new BorderLayout() );
userInterface = new BankUI();

enter = userInterface.getDoTask();
enter.setText( "Enter" );
enter.setEnabled( false );

enter.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
addRecord();
}
});

addWindowListener(

19
Acesso a Banco de Dados

new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
if(output != null) {
addRecord();
closeFile();
}
System.exit( 0 );
}
});

open = userInterface.getDoTask2();
open.setText( "Save As" );

open.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
openFile();
}
});

getContentPane().add( userInterface, BorderLayout.CENTER );


setSize( 300, 200 );
show();
}
public void addRecord() {
int accountNumber = 0;
BankAccountRecord record;
String fieldValues[] = userInterface.getFieldValues();

// Codigo não é nulo


if ( ! fieldValues[ 0 ].equals( "" ) ) {
try {
accountNumber = Integer.parseInt( fieldValues[ 0 ] );
if ( accountNumber > 0 ) {
record = new BankAccountRecord( accountNumber,
fieldValues[ 1 ], fieldValues[ 2 ],
Double.parseDouble( fieldValues[ 3 ] ) );
output.writeObject( record );
output.flush();
}
userInterface.clearFields();
}
catch ( NumberFormatException nfe ) {
JOptionPane.showMessageDialog( this,
"Bad account number or balance",
"Invalid Number Format", JOptionPane.ERROR_MESSAGE );
}
catch ( IOException io ) {
closeFile();
}
}
}

private void closeFile() {


try {
output.close();
}
catch( IOException ex ) {
JOptionPane.showMessageDialog( this, "Error closing file",
"Error", JOptionPane.ERROR_MESSAGE );
System.exit( 1 );
}
20
Acesso a Banco de Dados

public static void main( String args[] ) {


new CreateFile();
}

private void openFile() {


JFileChooser fileChooser = new JFileChooser();

fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY );

int result = fileChooser.showSaveDialog( this );

if ( result == JFileChooser.CANCEL_OPTION ) {
return;
}

File fileName = fileChooser.getSelectedFile();

if (fileName == null || fileName.getName().trim().equals( "" )){


JOptionPane.showMessageDialog( this, "Invalid File Name",
"Invalid File Name", JOptionPane.ERROR_MESSAGE );
}
else {
try {
output = new ObjectOutputStream(
new FileOutputStream( fileName )
);
open.setEnabled( false );
enter.setEnabled( true );
}
catch ( IOException e ) {
JOptionPane.showMessageDialog( this,
"Error Opening File",
"Error",
JOptionPane.ERROR_MESSAGE );
}
}
}
}

Código 6-5: Janela para gravar um registro

Como a maioria dos programas tem uma GUI semelhante, criamos a


classe BankUI para encapsular essa GUI. Também criamos a classe
BankAccountRecord para encapsular as informações de registro dos clientes
(isto é, conta, nome etc.) utilizadas pelos exemplos deste capitulo.

A classe BankUI contém dois JButtons e os arrays de JLabels e JTextFields.

O número de JLabels e JTextFields é estabelecido pelo construtor. Também


é fornecido um construtor sem argumentos que passa um valor-padrão para o
construtor.

Os métodos getFieldValues, setFieldvalues e clearFields são utilizados


para manipular o texto dos JTextFields. Os métodos getFields, getDoTask e

21
Acesso a Banco de Dados

getDoTask2 retornam componentes GUI individuais para que um programa


cliente possa adicionar ActionListeners, etc.

A classe BankAccountRecord implementa a interface Serializable que


permite que objetos BankAccountRecord sejam utilizados com
ObjectlnputStreams e ObjectOutputStreams. Essa classe contém os membros
de dados private account, firstName, lastName e balance. Essa classe também
fornece os métodos public “get” e “set” para acessar os membros de dados
private.

Agora vamos discutir o código que cria o arquivo de acesso seqüencial.


Nesse exemplo, introduzimos a classe JFileChooser (pacote javax.swing) para
selecionar arquivos. Construimos uma instância de JFileChooser e a atribui à
referência fileChooser.

Chamamos o método setFileSelectionMode para especificar se arquivos


e/ou diretórios podem ser selecionados pelo usuário. Para esse programa,
utilizamos a constante static FILES_ONLY de JFileChooser para indicar que
somente arquivos podem ser selecionados. Outras constantes static são

int result = fileChooser.showSaveDialog( this );

FILES_AND_DIRECTORIES e DIRECTORIES_ONLY.

Código 6-6: Abertura da janela para escolha de um arquivo

Chamamos o método showSaveDialog para exibir o diálogo de


JFileChooser intitulado Save. O argumento this especifica que o diálogo pai de
JFileChooser é utilizado para determinar a posição do diálogo na tela (se null é
passado, o diálogo é exibido no centro da janela).

Quando exibido, um diálogo JFileChooser não permite ao usuário interagir


com qualquer outra janela de programa até o diálogo JFileChooser ser fechado
(clicando em <Save> ou <Close>). Diálogos que se comportam dessa maneira
são chamados de diálogos modais.

O usuário seleciona a unidade, o diretório e o nome do arquivo e clica em


<Save>. O método showSaveDialog retorna um inteiro que especifica o botão
(<Save> ou <Close>) que foi clicado para fechar o diálogo.

22
Acesso a Banco de Dados

Figura 6-2: Janela para coletar dados da conta

Testamos se <Cancel> foi clicado comparando result com a constante


static CANCEL_OPTION. Se foi, o método é encerrado.

Figura 6-3: Janela para selecionar um arquivo a ser salvo

O arquivo que o usuário selecionou é recuperado chamando o método


getSelectedFile. O método getSelectedFile retorna um objeto — do tipo File —
que encapsula as informações sobre o arquivo (isto é, nome, localização etc.).
Esse objeto File não abre o arquivo. Atribuímos esse objeto File à referência
fileName.

Como afirmado anteriormente, arquivos são abertos criando objetos das


classes de fluxo FileInputStrean e FileOutputStream. Nesse exemplo, o arquivo
será aberto para saída, então um objeto FileOutputStream é criado com a
chamada do construtor.

new FileOutputStrean( fileName )

23
Acesso a Banco de Dados

Código 6-7: Criando um canal de saída para um arquivo.

Um argumento é passado para o construtor de FileOutputStream – um


objeto File. Arquivos existentes abertos para saída são truncados - todos os
dados no arquivo são descartados.

A classe FileOutputStream fornece métodos para gravar arravs de byte e


bytes individuais em um arquivo. Para esse programa, precisamos gravar
objetos em um arquivo — uma capacidade não fornecida por FileOutputStrean.

A solução para esse problema é uma técnica chamada encadeamento de


objetos de fluxo – a capacidade de adicionar os serviços de um fluxo a outro.
Para encadear um ObjectOutputStream com o FileOutputStream, passamos o
objeto FileOutputStream para o construtor de ObjectOutputStream.

output = new ObjectOutputStream(new


FileOutputStream(fileName));

Código: 6-8: Criando um canal para gravar objetos

Se ocorre uma IOException (uma exceção que é disparada quando um


arquivo é aberto para gravação em uma unidade com espaço insuficiente,
quando um arquivo de leitura é aberto para gravação, quando um arquivo
inexistente é aberto para leitura, etc.), um JOptionPane é exibido. Se a
construção dos dois fluxos não disparar uma IOException, o arquivo é aberto. A
referência output então pode ser utilizada para gravar objetos no arquivo.

O programa assume que dados foram inseridos corretamente e na ordem


adequada de número de registro. O usuário preenche os JTextFields e clica em
<Enter> para gravar os dados no arquivo.

O método actionPerformed do botão <Enter> chama nosso método


addRecord para realizar a operação de gravação. O método writeObject é
chamado para gravar o objeto record nesse arquivo. O método flush é
chamado para assegurar que quaisquer dados armazenados na memória
sejam gravados no arquivo.

Quando o usuário clica na caixa de fechamento (o x no canto direito


superior da GUI), output é testado contra null quanto à igualdade. Se o fluxo
estiver aberto, os métodos addRecord e closeFile são chamados. O método
closeFile chama o método close para output.

Ao utilizar objetos de fluxo encadeados, o objeto mais externo


(ObjectOutputStream, nesse exemplo) deve ser utilizado para fechar o arquivo.

24
Acesso a Banco de Dados

Lendo Dados de um Arquivo

Dados são armazenados em arquivos a fim de que possam ser


recuperados para processamento quando necessário.

O programa ReadFile lê registros de um arquivo criado pelo programa


anterior e exibe o conteúdo dos registros. Os arquivos são abertos para
entrada criando-se um objeto FileInputStream. O nome do arquivo aberto é
passado como um argumento para o construtor FileInputStream. No último
exemplo, gravamos objetos no arquivo utilizando um objeto
ObjectOutputStream.

Os dados devem ser lidos do arquivo no mesmo formato em que foram


gravados no arquivo. Portanto, utilizamos um ObjectInputStream encadeado
para um FileInputStream nesse programa.

25
Acesso a Banco de Dados

package com.targettrust.java.capitulo06;

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

public class ReadFile extends JFrame {


private ObjectInputStream input;
private BankUI userInterface;
private JButton nextRecord, open;

public ReadFile() {
super( "Reading a Sequential File of Objects" );
getContentPane().setLayout( new BorderLayout() );
userInterface = new BankUI();

nextRecord = userInterface.getDoTask();
nextRecord.setText( "Next Record" );
nextRecord.setEnabled( false );

nextRecord.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
readRecord();
}
}
);

addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
if ( input != null ) {
closeFile();
}
System.exit( 0 );
}
}
);

open = userInterface.getDoTask2();
open.setText( "Open File" );
open.addActionListener(

new ActionListener() {
public void actionPerformed( ActionEvent e ) {
openFile();
}
}
);

getContentPane().add( userInterface, BorderLayout.CENTER );


validate();
setSize( 300, 200 );
show();
}
private void closeFile() {
try {
input.close();
System.exit( 0 );
}

26
Acesso a Banco de Dados

catch ( IOException e ) {
JOptionPane.showMessageDialog( this, "Error closing file",
"Error", JOptionPane.ERROR_MESSAGE );
System.exit( 1 );
}
}
public static void main( String args[] ) {
new ReadFile();
}

private void openFile() {


JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY );

int result = fileChooser.showOpenDialog( this );

if ( result == JFileChooser.CANCEL_OPTION ) {
return;
}

//busca o arquivo selecionado


File fileName = fileChooser.getSelectedFile();

if (fileName == null || fileName.getName().trim().equals( "" )){


JOptionPane.showMessageDialog( this,"Invalid File Name",
"Invalid File Name",JOptionPane.ERROR_MESSAGE );
}
else {
try {
// ler dados para o input
input = new ObjectInputStream(
new FileInputStream( fileName )
);
open.setEnabled( false );
nextRecord.setEnabled( true );
}
catch ( IOException e ) {
JOptionPane.showMessageDialog( this,
"Error Opening File", "Error",
JOptionPane.ERROR_MESSAGE );
}
}
}

public void readRecord() {


BankAccountRecord record;
try {
record = ( BankAccountRecord ) input.readObject();
String values[] = { String.valueOf( record.getAccount() ),
record.getFirstName(),
record.getLastName(),
String.valueOf( record.getBalance() )
};
userInterface.setFieldValues( values );
}
catch ( EOFException eofex ) {
nextRecord.setEnabled( false );
JOptionPane.showMessageDialog( this,
"No more records in file",
"End of File",
JOptionPane.ERROR_MESSAGE );
}
27
Acesso a Banco de Dados

catch ( ClassNotFoundException cnfex ) {


JOptionPane.showMessageDialog( this,
"Unable to create object",
"Class Not Found",
JOptionPane.ERROR_MESSAGE );
}
catch ( IOException ioex ) {
JOptionPane.showMessageDialog( this,
"Error during read from
file", "Read Error",
JOptionPane.ERROR_MESSAGE );
}
}
}

Código 6-9: Classe para ler o arquivo

Como grande parte do código nesse exemplo é semelhante ao anterior,


discutimos somente as linhas principais do código que são diferentes.
Chamamos o método de JFileChooser showOpenDialog para exibir o diálogo
Ope n. O comportamento e GUI são os mesmos (exceto que <Save> é
substituído por <Open>) como o diálogo exibido por showSaveDialog. Criamos
um objeto ObjectInputStream e o atribui a input. O File fileName é passado
para o construtor FileInputStream que abre o arquivo.

O programa lê um registro do arquivo toda vez que o usuário clica no


botão <Next>. O método readRecord é chamado do método actionPerformed
Next para ler um registro do arquivo. A instrução chama o método readObject
para ler um Object do ObjectInputStream.
28
Acesso a Banco de Dados

Figura 6-4: Janela para ler dados da conta

A fim de utilizar métodos BankAccountRecord específicos, fazemos a


coreção do Object retomado para BankAccountRecord. Se o marcador de fim
do arquivo for alcançado durante a leitura, uma EndOfFileException é
disparada.

Para recuperar seqüencialmente dados de um arquivo, os programas


normalmente começam a ler a partir do inicio do arquivo e lêem todos os
dados consecutivamente até que os dados desejados sejam encontrados.
Eventualmente é necessário processar o arquivo várias vezes seqüencialmente
(a partir do início do arquivo) durante a execução de um programa.

Figura 6-5: Janela para seleção de arquivo


29
Acesso a Banco de Dados

A classe FileInputStream não fornece a capacidade de voltar para o


começo do arquivo para Ler o arquivo novamente.

O programa CreditInquiry permite que um gerente de crédito exiba


informações das contas dos clientes com saldo zero (isto é, clientes que não
devem nada à empresa), saldos de crédito (isto é, clientes para quem a
empresa deve dinheiro) e saldos de débito (isto é, clientes que devem dinheiro
à empresa por bens e serviços recebidos no passado).

package com.targettrust.java.capitulo06;

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.text.DecimalFormat;
import javax.swing.*;

public class CreditInquiry extends JFrame {

private JTextArea recordDisplay;


private JButton open, done, credit, debit, zero;
private JPanel buttonPanel;
private ObjectInputStream input;
private FileInputStream fileInput;
private File fileName;
private String accountType;

public CreditInquiry(){

super( "Credit Inquiry Program" );


Container c = getContentPane();
c.setLayout( new BorderLayout() );
buttonPanel = new JPanel();
open = new JButton( "Open File" );
open.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
openFile( true );
}}
);

buttonPanel.add( open );
credit = new JButton( "Credit balances" );
credit.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
accountType = e.getActionCommand();
readRecords();
}
}
);

buttonPanel.add( credit );
debit = new JButton( "Debit balances" );
debit.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {

30
Acesso a Banco de Dados

accountType = e.getActionCommand();
readRecords();
}
}
);

buttonPanel.add( debit );
zero = new JButton( "Zero balances" );
zero.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
accountType = e.getActionCommand();
readRecords();
}
}
);

buttonPanel.add( zero );
done = new JButton( "Done" );

buttonPanel.add( done );
done.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e ) {
if ( fileInput != null ) closeFile();
System.exit( 0 );
}
}
);

recordDisplay = new JTextArea();


JScrollPane scroller = new JScrollPane( recordDisplay );
c.add( scroller, BorderLayout.CENTER );
c.add( buttonPanel, BorderLayout.SOUTH );
credit.setEnabled( false );
debit.setEnabled( false );
zero.setEnabled( false );
pack();
setSize( 600, 250 );
show();
}

private void openFile( boolean firstTime ) {


if ( firstTime ) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = fileChooser.showOpenDialog( this );
if ( result == JFileChooser.CANCEL_OPTION ) return;
fileName = fileChooser.getSelectedFile();
}
if ( fileName == null || fileName.getName().equals( "" ) )
JOptionPane.showMessageDialog( this, "Invalid File Name",
"Invalid File Name",
JOptionPane.ERROR_MESSAGE
);
else {
try {
if ( input != null ) input.close();
fileInput = new FileInputStream( fileName );
input = new ObjectInputStream( fileInput );
open.setEnabled( false );
credit.setEnabled( true );
31
Acesso a Banco de Dados

debit.setEnabled( true );
zero.setEnabled( true );
}
catch ( IOException e ) {
JOptionPane.showMessageDialog( this, "File does not exist",
"Invalid File Name",
JOptionPane.ERROR_MESSAGE );
}
}
}

private void closeFile() {


try {
input.close();
}
catch ( IOException ioe ) {
JOptionPane.showMessageDialog( this, "Error closing file",
"Error", JOptionPane.ERROR_MESSAGE );
System.exit( 1 );
}
}

private void readRecords() {

BankAccountRecord record;
DecimalFormat twoDigits = new DecimalFormat( "0.00" );
openFile( false );

try {
recordDisplay.setText( "The accounts are:\n" );
while ( true ) {
record = ( BankAccountRecord ) input.readObject();
if ( shouldDisplay( record.getBalance() ) )
recordDisplay.append( record.getAccount() + "\t" +
record.getFirstName() + "\t" +
record.getLastName() + "\t" +
twoDigits.format( record.getBalance()
) + "\n" );
}
}

catch ( EOFException eof ) {


closeFile();
}
catch ( ClassNotFoundException cnfex ) {
JOptionPane.showMessageDialog( this, "Unable to create object",
"Class Not Found",
JOptionPane.ERROR_MESSAGE
);
}
catch ( IOException e ) {
JOptionPane.showMessageDialog( this, "Error reading from file",
"Error",
JOptionPane.ERROR_MESSAGE );
}
}

private boolean shouldDisplay( double balance ) {


if ( accountType.equals( "Credit balances" ) && balance < 0 ) {
return true;
} else if (accountType.equals("Debit balances") && balance > 0 ) {
return true;
32
Acesso a Banco de Dados

} else if (accountType.equals("Zero balances") && balance == 0) {


return true;
}
return false;
}

public static void main( String args[] ) {


CreditInquiry app = new CreditInquiry();
}
}

Código 6-10: Classe para ler dados do arquivo

O programa exibe botões que permitem que um gerente de crédito


obtenha as informações de crédito. O botão <Credit> balances produz uma
lista de contas com saldos de crédito. O botão <Debit> balances produz uma
lista das contas com saldos de débito. O botão <Zero> balances produz uma
lista de contas com saldos zero. O botão <Done> termina a execução de
programa.

Os registros são exibidos em uma JTextArea chamada recordDisplay. As


informações de registro são colecionadas lendo o arquivo inteiro e
determinando se cada registro satisfaz o critério para o tipo de conta
selecionado pelo gerente de crédito.

Figura 6-5: Tela par ler os dados do arquivo

Clicar em um botão (que não <Done>) configura a variável accountType


com o texto do botão clicado (por exemplo, <Zero> balances etc.) e invoca o
método readRecords, que faz um loop pelo arquivo e lê cada registro.

O método shouldDisplay é chamado para determinar se o registro atual


satisfaz o tipo de conta solicitado. Se shouldDisplay retornar true, as
informações de conta do registro atual são acrescentadas à JTextArea
denominada recordDisplay. Quando o marcador de fim do arquivo é alcançado,
chamamos closeFile para fechar o arquivo.

33
Acesso a Banco de Dados

Gerenciamento de memória: Garbage Collector

O gerenciamento de memória em Java é automático. Quando um objeto é


criado, uma quantidade de memória é alocada para ele no heap. Quando não
há mais referências para este objeto, ele é marcado para a coleta de lixo.
Quando a coletor de lixo executa, ele procura por objetos marcados e retorna a
memória usada por tais objetos para o heap.

Não há funções free() ou delete() em Java, tal como elas existem em C++.
Para forçar a marcação de um objeto simplesmente remova todas as
referências para este objeto, atribuindo null para todas as referências.

O coletor de lixo executa quando a quantidade de memória livre


disponível para a JVM cai abaixo de um valor arbitrário de limiar. A JVM realiza
a coleta de lixo através de uma thread de baixa prioridade. Quando a JVM não
tem mais nada a fazer, a thread do coletor de lixo recebe algum tempo de CPU
procurando descobrir se há memória que possa ser liberada.

Você pode simplesmente pedir que o coletor de lixo execute chamando o


método gc() da classe System. Entretanto, isto é apenas um pedido para que a
coleta de lixo se realize.

Não há garantias que a JVM aceita a sugestão.

34
Acesso a Banco de Dados

Exercícios

1. Agora que você já viu a parte de arquivos, vamos dicionar na nossa


aplicação que está sendo desenvolvida neste curso o recurso de
serialização de objetos bem como o de gravação em arquivos texto. Os
dados da aplicação serão salvos em um objeto persistente para que você
possa recuperar os memos mais adiante. Para contemplar a parte de
arquivos texto, você deve criar um mecanismo de log para a sua aplicação
e salvar linhas de texto que registram as principais ações do usuário em
um arquivo texto.

Siga as instruções do instrutor para realizar este exercício.

35
7.Acesso a Banco de Dados

1
Objetivos
• Conectar um banco de dados usando Java Database Connectivity
(JDBC)

• Criar e executar uma query usando JDBC

• Executar comandos

• Efetuar commit e rollback de transações

1
Acesso a Banco de Dados

Introdução

Neste capítulo estudaremos o modo de acesso ao banco de dados


utilizando JDBC. Como vimos anteriormente, o Java Database Connectivity
(JDBC) faz parte do pacote java.sql na qual contém um conjunto de interfaces
que especificam o JDBC API. Este pacote faz parte do Java 1.1.7 e Java 2.
• JDBC 1.0 (JDK 1.1)

• JDBC 2.0 (JDK 2)

• JDBC 3.0 (JDK 1.4)

Um driver JDBC implementa o código de conexão e query específicas para


o banco de dados. Os drivers da Oracle/IBM provêem extensões para suportar
datatypes especiais dos bancos de dados.

A Oracle e IBM provêem três drivers:


• Thin client Driver

• Client-based Driver

• Server-based Driver

2
Acesso a Banco de Dados

JDBC Drivers

Thin Client Driver


Este driver é escrito completamente em Java, e pode ser carregado por
um browser Web. É o único driver que não requer nenhuma instalação no lado
cliente, assim sendo, você tem que usar este driver se você estiver
desenvolvendo um applet. Este driver pode conectar qualquer banco de dados
Oracle7 ou um banco de dados Oracle8i/9i. Você deve usar este driver se você
estiver desenvolvendo uma aplicação que pode conectar diferentes versões do
banco.

Por comunicar com o banco de dados, o driver usa uma versão leve do
SQL*Net ou Net8 em cima da camada TCP/IP que pode ser carregado em
tempo de execução.

3
Acesso a Banco de Dados

Client Based Drivers

Há três drivers: o OCI 7 para Oracle7, o OCI 8 para Oracle8/8i e OCI 9 para
Oracle 9i. Cada um dos drivers OCI que usa uma biblioteca de ligação dinâmica
(DLL) deve ser instalado no sistema do cliente. Estes drivers convertem
chamadas de JDBC à Oracle Call Interface (OCI). As chamadas de OCI são
enviadas por SQL*Net ou Net8/9 para o banco de dados.

Você deve usar um dos drivers OCI se você está desenvolvendo um cliente
ou uma aplicação no servidor de aplicação e precisa do máximo de
performance.

No caso IBM existe o driver Client DB2.

4
Acesso a Banco de Dados

Server-Side Driver

Este driver permite o Java Stored Procedures comunicar-se diretamente


com a SQL Engine. O driver comunica-se usando uma biblioteca C.

JDBC, o driver, a biblioteca C e a SQL engine são executado no mesmo


local isso significa que não há nenhuma utilização da rede. O driver pode ser
usado por qualquer programa Java executado no RDBMS; isto inclui Stored
Procedures, Enterprise JavaBeans, e Servlets Java.

5
Acesso a Banco de Dados

Outros Drivers de JDBC

JDBC-ODBC Bridge – a ponte JDBC-ODBC é um driver JDBC desenvolvido


pela JavaSoft. Permite programas Java usar JDBC com drivers de ODBC
existentes. JavaSoft não suporta mais este driver. Agora, já temos drivers em
Java para os principais bancos. ODBC (Open Database Connectivity) é uma API
unificada para conectar bancos de dados SQL. Foi projetado para permitir o
desenvolvimento de aplicações independentes de banco de dados.

6
Acesso a Banco de Dados

Aplicação vs JDBC Driver


Tipo de Driver
Programa

Applet Thin

Client application Client

Thin

EJB, servlet Client


(on the middle tier)
Thin

EJB, servlet Server Side


(in the database)

Stored Procedure Server Side

Tabela 7-1: Tipos de drivers e seus usos

7
Acesso a Banco de Dados

JDBC URLs

JDBC usa uma URL para identificar a conexão de banco de dados. A URL
de um JDBC é um pouco diferente de uma URL de HTTP ou FTP, mas como
qualquer URL, é um localizador de recursos, neste caso, de um banco de
dados. A estrutura de um URL de JDBC é flexível, permitindo assim que cada

jdbc:<subprotocol>:<subname>

* jdbc é o protocolo. Todos os URLs começam com o protocolo


* <subprotocol> é o nome do driver ou mecanismo de conexão ao
banco de dados.
* <subname> identifica o banco de dados. <driver>:@<database>

desenvolvedor especifique o tipo de driver no URL.

8
Acesso a Banco de Dados

Thin Driver

jdbc:oracle:thin:@<host>:<porta>:<SID>
<driver>: thin
<database>: é uma strinig formada por <host>:<port>:<sid>

Por exemplo: jdbc:oracle:thin:@edihost:1521:ORCL

jdbc:db2://<host>:<porta>/<DBName>
<driver>: thin (IBM)
<database>: é uma strinig formada por
<host>:<port>/<DBName>.

Por exemplo:jdbc:db2://serverHostname:port/databaseName

9
Acesso a Banco de Dados

OCI Driver

jdbc:oracle:oci8:@<TNSNAMES>
<driver> é oci8/oci7, dependende de qual driver é utilizado.
<database> é uma entrada de TNSNAMES no arquivo de
tnsnames.ora.

Por exemplo: jdbc:oracle:oci8:@eduhost

10
Acesso a Banco de Dados

Server Side Driver

jdbc:oracle:DBName
<driver> é DBName. Você não especifica um banco de dados,
porque o driver é amarrado a um banco de dados específico.

jdbc:db2:DBName
<driver> é DBName. Você não especifica um banco de dados,
porque o driver é amarrado a um banco de dados específico.

O Banco de Dados é local. Neste caso, é necessário informar o nome da


instância do BD.

11
Acesso a Banco de Dados

Acessando Bases de Dados por JDBC

Existem quatro etapas no processo de query a um banco de dados


relacional:
• Connect

• Query

• Process Results

• Close

12
Acesso a Banco de Dados

Etapa 1: Connect

Para criar uma conexão você precisa seguir os seguintes passos:


• Importar o pacote JDBC

• Registrar o driver

• Connectar com o banco de dados

import java.sql.*;
DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(URL, userId,
password);

13
Acesso a Banco de Dados

Carregando o Driver

Drivers JDBC são registrados pelo DriverManager. Há dois modos para


fazer isto:
• Use o método registerDriver() do DriverManager

• Use o método forName() da classe java.lang.Class para carregar os


drivers JDBC diretamente, como segue:

Class C = class.forName
(“oracle.jdbc.driver.OracleDriver”); //Ou
Class C = class.forName
(“COM.ibm.db2.jdbc.net.DB2Driver”);

14
Acesso a Banco de Dados

Exceções

Ao usar JDBC, a maioria dos métodos possuem exceções, capazes de


contornar qualquer coisa que der errado. Class.forClass() executa uma
ClassNotFoundException se a classe especificada não poder ser encontrada.
Você tem que tratar esta exceção em seu código.

O método getConnection() executa um SQLException se houver qualquer


problema, como um protocolo inválido, um nome de usuário e/ou senha
incorreta.

O SQLException provê a informação seguinte:


• Uma string descreve o erro

• X/Open SQLState

• Um código de erro específico

15
Acesso a Banco de Dados

Etapa 2: Query
• Cria o comando

• Executa a query

16
Acesso a Banco de Dados

Statement

Um objeto Statement envia seu comando SQL para banco de dados. Você
precisa de uma conexão ativa para criar uma declaração de JDBC. A
Declaração tem dois métodos para executar uma query no banco de dados:
• executeQuery () para QUERY

• executeUpdate() para INSERT, UPDATE, DELETE, ou declaração de DDL

JDBC provê dois outros objetos de declaração:


• PregaredStatement para precompição de declarações SQL.

• CallableStatement para declarações que executam Stored Procedures.

17
Acesso a Banco de Dados

Objetos e Interfaces

java.sql.Statement é uma interface, não um objeto. Quando você declara


o objeto Statement, e inicializa este usando o método CreateStatement(), você
está criando a implementação da interface de declaração provido pelo driver
Oracle.

18
Acesso a Banco de Dados

Criando uma Query


• Crie um objeto de declaração vazio

• Execute a query

Por exemplo:

Statement stmt = conn.createStatement ();

ResultSet rset = stmt.executeQuery (“select * from emp”);

statement stmt = conn.createStatementy();


ResultSet rset = stmt.executeQuery(statement);
ResultSet rset = stmt.executeUpdate(statement);

19
Acesso a Banco de Dados

Etapa 3: Process results


• Preparando o conjunto do resultado

• Disponibilizando variáveis Java com o resultado

20
Acesso a Banco de Dados

ResultSet

O JDBC devolve os resultados de uma query em um objeto ResultSet. Um


ResultSet mantém um cursor que aponta o seu registro atual. Use next() para
navegar pelos registros. A classe de ResultSet tem vários métodos que
retornam valores de coluna no registro corrente. Cada método getXXX() tenta
converter o valor da coluna ao tipo Java especificado.

Por exemplo, getInt() pega o valor da coluna como um int, getString()


pega o valor da coluna como uma String, e getDate() retorna o valor de coluna
como uma Data. Cada método getXXX() têm duas versões, permitindo para o
programador especificar a coluna através de número ou através de nome.
Colunas especificadas através do número: as colunas são numeradas de 1 à X.
Colunas especificandas através de nome: os nomes de colunas são case
insensitive.

Para query que não foi especificado o nome da coluna é melhor usar
números de coluna. ResultSet provê um método chamado findColumn() que
devolve o número da coluna para um determinado nome de coluna. O método
getString() pode ser usado para recuperar qualquer tipo de dados. É o método
mais fácil para ser usado em aplicações visuais, quando se quer exibir ou
imprimir os dados. Também pode ser usado quando o usuário monta o
comando SQL de alteração utilizando a declaração SQL UPDATE.

Todos os métodos getXXX() requerem um único parâmetro, com exceção


de getBigDecimal (colname, scale) e getBigDecimal (colindex, scale), ambos
requerem no segundo parâmetro o número de casas decimais.

21
Acesso a Banco de Dados

Processando os Resultados

Navegue pelo conjunto de dados utilizando o método getXXX() para


retornar o valor de cada coluna.

while (rset.next ( ) ) {...}


String val = rset.getString (colname); ou
String val = rset.getString (colindex);

Por exemplo:

while (rset.next ( ) ) {

String title = rset.getString(”TITLE”);

String year = rset.getString(”YEAR”); ... / / Processamento

22
Acesso a Banco de Dados

Etapa 4: Close
• Encerrando a interação com o banco de dados

23
Acesso a Banco de Dados

24
Acesso a Banco de Dados

Fechando uma Conexão

Você tem que fechar todo o ResultSet explicitamente como também sua
declaração. O método close() limpa a memória e os cursores de banco de
dados, assim se você não fecha seu ResultSet explicitamente e sua
declaração, você pode ter sérios problemas de memória.

O driver no servidor roda em uma sessão default, ou seja, você já está


“conectado” e não pode fechar a conexão. Chamando o método close(), neste
caso, não acontece nada. Através deste exemplo abaixo podemos analisar
todos o funcionamento de um programa Java acessando um banco de dados
Oracle utilizando o driver de JDBC.

25
Acesso a Banco de Dados

MetaData

Metadata (java.sql.DatabaseMetaData) é um objeto de informações dos


dados. Em JDBC você usa o método Connection.getMetaData() para retornar
um objeto de DatabaseMetaData. A classe de DatabaseMetaData contém mais
de cem métodos para obter informação sobre um banco de dados.

Alguns exemplos de métodos DatabaseMetaData:


• getColumnPrivileges(): retorna a descrição do direito de acesso da
coluna de uma tabela.

• getColumns(): Retorna uma descrição das colunas de tabela.

• getDatabaseProductName(): Retorna o nome do banco de dados.

• getDriverName(): Retorna o nome deste driver JDBC.

• storesLowerCaseIdentifiers(): o banco de dados armazena minúsculas e


maiúsculas. Pode executar SQL em minúscula?

• supportsAlterTableWithAddColumn(): ALTER TABLE pode adicionar


colunas?

• supportsFullOuterJoins(): Suporta OuterJoins?

26
Acesso a Banco de Dados

Tipo de Dados

A classe java.sql.Types define constantes que são usadas para identificar


tipos de SQL ANSI. ResultSetMetaData.getColumnType() retorna o valor
correspondente de uma destas constantes. Em muitos casos, você pode
adquirir todas as colunas em seu resultado usando getObject() ou getString()
do ResultSet. Por razões de desempenho, ou porque você quer executar
cálculos complexos, às vezes é importante ter seus dados em seu tipo real.

ANSI SQL Java Type ResultSet


Method
CHAR, VARCHAR2 java.lang.String getString( )

LONGVARCHAR java.langString getAsciiStream( )

NUMERIC, java.math.BigDeci getBigDecimal( )


DECIMAL mal

BIT Boolean getBoolean( )

TINYINT Byte getByte( )

SMALLINT Short getShort( )

INTEGER Int getInt( )

BIGINT Long getLong( )

REAL Float getFloat( )

DOUBLE, FLOAT Double getDouble( )

BINARY, byte [ ] getBytes( )


VARBINARY

LONGVARBINARY byte [ ] getBinaryStream( )

DATE java.sql.Date getDate( )

TIME java.sql.Time getTime( )

TIMESTAMP java.sql.Timestamp getTimestamp( )

27
Acesso a Banco de Dados

Resumo Tecnologia JDBC

DriverManager
DriverManager provê acesso a drivers JDBC registrados. DriverManager
entrega conexões a uma fonte de dados especificada por seu método
getConnection().

Connection
A classe Connection é disponibilizada pelo driver JDBC. A Connection
representa uma sessão com um banco de dados. A Conexão é usada para criar
um objeto Statement, usando createStatement().

Statement
Statement executa comandos SQL. Por exemplo, podem ser executadas
querys usando o método executeQuery() e os resultados são disponibilizados
em ResultSet.

ResultSet
JDBC devolve os resultados de uma query em um objeto de ResultSet. Um
ResultSet mantém um cursor. O método next() move o cursor para o próximo
registro. ResultSet tem métodos getXXX() para recuperar valores de colunas.

DatabaseMetaData e ResultSetMetaData
DatabaseMetaData e ResultSetMetaData devolvem metadata sobre o
banco de dados e ResultSet respectivamente. Chame getMetaData() na
Connection ou no ResultSet.

28
Acesso a Banco de Dados

Acessando Bases de Dados com JDBC

O programa abaixo ilustra a conexão com o banco de dados, a consulta ao


banco de dados e a exibição dos resultados. A seguinte discussão apresenta os
aspectos-chave de JDBC do programa.

package com.targettrust.java.capitulo07;

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

public class TableDisplay extends JFrame {


private Connection connection;
private JTable table;

public TableDisplay() {

/* URL para conexões com outros bancos


* Sintaxe: jdbc:db2://serverHostname:port/databaseName
(REMOTE) 10.0.0.30:6790/sample (STARTAR APPLET SERVER)
* String url = "jdbc:db2://10.0.2.12:6789/sample";
*/

String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORADB";

String username = "target";


String password = "target";

try{
/* Conexão com outros bancos
* Class.forName( "COM.ibm.db2.jdbc.app.DB2Driver");
* Class.forName( "COM.ibm.db2.jdbc.net.DB2Driver");
* Class.forName( "org.postgresql.Driver");
***
* Criação de um objeto do driver:
* DriverManager.registerDriver(
new org.postgresql.Driver()
);
*/

Class.forName( "oracle.jdbc.driver.OracleDriver");

connection = DriverManager.getConnection( url, username,


password );
connection.setAutoCommit(false);
}
catch ( ClassNotFoundException cnfex ){
System.err.println( "Failed to load JDBC/ODBC driver." );
cnfex.printStackTrace();
System.exit( 1 ); // terminate program
}
catch ( SQLException sqlex ){
try {
System.err.println( "Unable to connect" );
29
Acesso a Banco de Dados

if( connection != null ) connection.close();


sqlex.printStackTrace();
}
catch (SQLException e) {}
}

getTable();
setTitle("Oracle Connection");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize( 450, 150 );
setVisible(true);
}
private void displayResultSet( ResultSet rs ) throws SQLException {
boolean moreRecords = rs.next();
if ( ! moreRecords ){
JOptionPane.showMessageDialog( this, "ResultSet contained no
records" );
return;
}
Vector columnHeads = new Vector();
Vector rows = new Vector();

try {

ResultSetMetaData rsmd = rs.getMetaData();


for ( int i = 1; i <= rsmd.getColumnCount(); ++i )
columnHeads.addElement( rsmd.getColumnName( i ) );

do {
rows.addElement( getNextRow( rs, rsmd ) );
} while ( rs.next() );

table = new JTable( rows, columnHeads );


JScrollPane scroller = new JScrollPane( table );
getContentPane().add( scroller, BorderLayout.CENTER );
validate();
}
catch ( SQLException sqlex ){
sqlex.printStackTrace();
}
}
private Vector getNextRow( ResultSet rs, ResultSetMetaData rsmd )
throws SQLException {
Vector currentRow = new Vector();

for ( int i = 1; i <= rsmd.getColumnCount(); ++i )


switch( rsmd.getColumnType( i ) ) {
case Types.VARCHAR: currentRow.addElement(
rs.getString( i ) );
break;
case Types.INTEGER: currentRow.addElement(
new Long( rs.getLong( i ) ) );
break;
case Types.DATE: currentRow.addElement(
rs.getString( i ) );
break;
default: currentRow.addElement(
rs.getString( i ) );
}

return currentRow;
}
30
Acesso a Banco de Dados

private void getTable(){


Statement statement= null;
ResultSet resultSet = null;

try {
String query = "SELECT * FROM Emp";

statement = connection.createStatement();
resultSet = statement.executeQuery( query );
displayResultSet( resultSet );

}
catch ( SQLException sqlex ) {
try {
statement.close();
connection.close();
sqlex.printStackTrace();
}
catch (SQLException e) {}
}
}

public static void main( String args[] ) {


final TableDisplay app = new TableDisplay();
}

public void shutDown() {


try {
connection.close();
}
catch ( SQLException sqlex ) {
System.err.println( "Unable to disconnect" );
sqlex.printStackTrace();
}
}
}

Código 7-1: Classe para listar dados de uma tabela

Importamos o pacote java.sql que contém as classes e interfaces para


manipular os bancos de dados relacionais em Java. Declaramos uma referência
Connection (pacote java.sql) chamada connection. Isso irá referenciar um
objeto que implementa a interface Connection.

Um objeto Connection gerencia a conexão entre o programa Java e o


banco de dados. Também fornece suporte para executar instruções de SQL
para fins de manipulaçâo do banco de dados e o processamento de
transações.

O construtor para a classe TableDisplay tenta a conexão com o banco de


dados e, se bem-sucedido, consulta o banco de dados e exibe os resultados
chamando o método utilitário getTable. Especificamos a URL (Uniform
Resource Locator) do banco de dados que ajuda o programa a localizar o
banco de dados (possivelmente em uma rede ou no sistema de arquivos local
do computador), o nome de usuário para efetuar logon no banco de dados e a
senha para efetuar logon no banco de dados.

31
Acesso a Banco de Dados

A URL especifica o protocolo para comunicação (JDBC), o subprotocolo


para comunicação (ODBC) e o nome do banco de dados (ODBC). O
subprotocolo ODBC indica que o programa estará utilizando JDBC para
conectar-se com uma fonte de dados Mícrosoft ODBC.

ODBC é uma tecnologia desenvolvida pela Microsoff para permitir acesso


genérico a diferentes sistemas de bancos de dados na plataforma Windows (e
algumas plataformas UNIX).

O Java 2 Software Development Kit (J2SDK) fornece o driver de banco de


dados de ponte JDBC para ODBC a fim de permitir que qualquer programa Java
acesse qualquer fonte de dados ODBC. O driver é definido pela classe
JdbcOdbcDriver no pacote sun.jdbc.odbc.

Figura 7-1: Listagem de dados da tabela

A definição de classe para o driver de banco de dados deve ser carregada


antes do programa se conectar ao banco de dados. Utilizamos o método static
forName da classe Class (pacote java.lang) para carregar a definição de classe
para o driver de banco de dados (essa linha dispara uma exceção
ClassNotFoundException se a classe não conseguir ser localizada).

Observe que a instrução especifica o nome completo do pacote e o nome


da classe - sun.jdbc.odbcJdbcOdbcDriver.

Para mais informações sobre drivers JDBC e bancos de dados suportados


visite o site JDBC da Sun Microsystems na Web:

http://java.sun. com/products/jdbc/

Utilizamos o método static getConnection da classe DriverManager


(pacote java.sql) para tentar uma conexão com o banco de dados especificado
pela URL. Os argumentos username e password são passados aqui porque
intencionalmente configuramos a fonte de dados para exigir que o usuário

32
Acesso a Banco de Dados

efetue login. Nosso banco de dados é configurado com um nome de usuário –


“anonymous” - e uma senha – “guest” - para propósitos de demonstração.

Se o DriverManager não se conectar ao banco de dados, o método


getConnection dispara uma SQLException. Se a tentativa de conexão é bem-
sucedida, chamamos o método utilitário getTable para recuperar os dados da
tabela EMP.

O método utilitário getTable consulta o banco de dados e, a seguir, chama


o método utilitário displayResultSet pala criar uma JTable (pacote java.swing)
contendo o resultado da consulta.

Declaramos uma referência Statement (pacote java.sql) que irá se referir


a um objeto que implementa a interface Statement. Esse objeto submeterá a
consulta ao banco de dados.

Declaramos uma referência ResultSet (pacote java.sql) que irá se referir a


um objeto que implementa a interface ResultSet. Quando uma consulta é
realizada em um banco de dados, um objeto ResultSet é retomado contendo o
resultado da consulta. Os métodos da interface ResultSet permitem ao
programador manipular os resultados da consulta.

Definimos a consulta a realizar. Nesse exemplo, selecionaremos todos os


registros da tabela EMP (Empregados). Invocamos o método createStatement
de Connection para obter um objeto que implementa a interface Statement.
Agora podemos utilizar statement para consultar o banco de dados.

Realizamos a consulta chamando o método executeQuery de Statement.


Esse método retorna um objeto que implementa ResultSet e contém os
resultados da consulta, O ResultSet é passado para o método utilitário
displayResultSet, assim a instrução é fechada para indicar que terminamos o
processamento da consulta.

O método displayResultSet posiciona-se no primeiro registro no ResultSet.


Com o método next de ResultSet. Inicialmente, o ResultSet é posicionado
antes do primeiro registro, portanto esse método deve ser chamado antes de
você conseguir acessar os resultados.

O método next retorna um boolean indicando se foi capaz de posicionar


no próximo registro. Se o método retoma false, não há mais registros a
processar. Se houver registros, definimos um Vector para armazenar os nomes
de coluna das colunas no ResultSet e defimos outro Vector para armazenar as
linhas de dados do ResultSet. Esses Vectors são utiliiados com o construtor
JTable para construir uma JTable que exibe os dados do ResultSet.

Obtemos os meta dados para o ResultSet os atribui a uma referência


ResultSetMetaData (pacote java.sql)

Os meta dados para o ResultSet descrevem o conteúdo de um ResultSet.


Essas informações podem a ser utilizadas para obter programaticamente
informações sobre os nomes e tipos das colunas ResultSet e podem ajudar o
programador a processar um ResultSet dinamicamente quando informações
33
Acesso a Banco de Dados

detalhadas sobre o ResultSet não são conhecidas antes da consulta. Utilizamos


ResultSetMetaData para recuperar os nomes de cada coluna no ResultSet.

O método getcolumnCount de ResultSetMetaData retoma o número de


colunas no ResultSet e método getColumnName de ResultSetMetaData retoma
o nome da coluna especificada.

Recuperamos cada linha do ResultSet utilizando o método utilitário


getNextRow. O método getNextRow retoma um Vector contendo os dados de
uma linha do ResultSet. Repare na condição rs.next(). Isso move o cursor de
ResultSet que monitora o registro atual no ResultSet para o próximo registro
no ResultSet. Lembre-se de que o método next retorna falso quando não há
mais registros no ResultSet. Portanto, o comando terminará quando não
houver mais registros.

Depois que todas as linhas são convertidas em Vectors, criamos o


componente GUI JTab1e que exibe os registros no ResultSet. O construtor que
utilizamos nesse programa recebe dois Vectors como argumentos.

O primeiro argumento é um Vector de Vectors (semelhante a um array


bidimensional) que contém todos os dados de linhas, O segundo argumento é
um Vector contendo os nomes de coluna para cada coluna. O construtor JTable
utiliza esses Vectors para preencher a tabela.

O método getNextRow recebe um ResultSet e seu correspondente


ResultgetMetaData como argumentos e cria um Vector contendo uma linha de
dados do ResultSet.

A estrutura for faz um loop por cada coluna do conjunto de resultados e


executa a estrutura switch que determina o tipo de dados da coluna. O método
getColumnType de ResultSetMetaData retorna uma constante inteira da classe
Types (pacote java.sql) indicando o tipo dos dados.

Os únicos tipos de dados em nosso banco de dados são Strings e inteiros


longos. O tipo de SQL para strings é Types * VARCHAR e o tipo de SQL para
inteiros longos é Types * INTEGER. Utilizamos o método getString de ResultSet
para obter o String de uma coluna do tipo Types - VARCHAR.

Utilizamos o método getLong de ResultSet para obter o inteiro longo de


uma coluna do tipo Types - INTEGER.

O método shutdown fecha a conexão para o banco de dados com o


método close de Connection.

34
Acesso a Banco de Dados

Registrando Fonte de Dados de ODBC

O exemplo anterior pressupõe que o banco de dados ODBC já foi


registrado como uma fonte de dados ODBC. Para conectar-se ao banco de
dados, uma fonte de dados ODBC deve estar registrada no sistema pela opção
ODBC Data Sources no Control Panel do Windows. Dê um clique duplo nessa
opção para exibir a caixa de diálogo ODBC Data Source Administrator.

Esse diálogo é utilizado para registrador nosso User Data Source Name
(User DSN). Certifique-se de que a guia User DSN esteja selecionada, então
clique em Add para exibir o diálogo Create new Data Source. Como estamos
utilizando um banco de dados do Microsoft Access, selecionamos Microsoft
Access Driver e clicamos em Finish.

O diálogo ODBC Microsoft Access Setup aparece. Inserimos o nome (por


exemplo, Banco) que utilizaremos para referenciar o banco de dados com JDBC
no campo de texto Data Source Name. Você também pode inserir uma
descrição. Clique no botão <Select> para exibir o diálogo Select Database.

35
Acesso a Banco de Dados

Figura 7-2: Criando uma fonte de dados no windows

Utilize esse diálogo para localizar e selecionar o arquivo de banco de


dados MDB em seu sistema (ou na rede). Quando tiver terminado, clique em
<OK> para fechar o diálogo Select Database e retomar ao diálogo ODBC
Microsott Access Setup.

A seguir, clique no botão <Advanced> para exibir o diálogo Set Advanced


Options. Digite o nome de usuário “anonymous” e a senha “guest” nos campos
na parte superior do diálogo, então clique em <OK> para fechar o diálogo.
Clique em <OK> para fechar o diálogo ODBC Microsoft Access.

Repare que o diálogo ODBC Data Source Administrator agora contém a


origem de dados Banco. Clicar em <OK> para fechar o diálogo. Estamos agora
prontos para acessar a origem de dados ODBC pelo driver de ponte de JDBC
para ODBC. Execute o programa anterior para exibir o conteúdo da tabela EMP
do banco de dados MDB.

36
Acesso a Banco de Dados

Manipulando Banco de Dados com ODBC

O próximo exemplo manipula um banco de dados que contém uma tabela


(Address). O programa fornece recursos para inserir novos registros, atualizar
registros existentes e procurar registros no banco de dados.

package com.targettrust.java.capitulo07;

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

public class AddressBook extends JFrame {


private ControlPanel controls;
private ScrollingPanel scrollArea;
private JTextArea output;
private String url;
private Connection connect;
private JScrollPane textpane;

public AddressBook() {
super( "Address Book Database Application" );
Container c = getContentPane();
scrollArea = new ScrollingPanel();
output = new JTextArea( 6, 30 );
c.setLayout( new BorderLayout() );
c.add( new JScrollPane( scrollArea ), BorderLayout.CENTER );
textpane = new JScrollPane( output );
c.add( textpane, BorderLayout.SOUTH );

try {
url = "jdbc:odbc:AddressBook";
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
connect = DriverManager.getConnection( url );
output.append( "Connection successful\n" );
}
catch ( ClassNotFoundException cnfex ) {
cnfex.printStackTrace();
output.append( "Connection unsuccessful\n" +
cnfex.toString() );
}
catch ( SQLException sqlex ) {
sqlex.printStackTrace();
output.append( "Connection unsuccessful\n" +
sqlex.toString() );
}
catch ( Exception ex ) {
ex.printStackTrace();
output.append( ex.toString() );
}

controls = new ControlPanel( connect, scrollArea, output);


c.add( controls, BorderLayout.NORTH );
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

37
Acesso a Banco de Dados

setSize( 500, 500 );


setVisible(true);
}

public static void main( String args[] ) {


AddressBook app = new AddressBook();
}
}

package com.targettrust.java.capitulo07;

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

public class AddRecord implements ActionListener {


private ScrollingPanel fields;
private JTextArea output;
private Connection connection;

public AddRecord( Connection c, ScrollingPanel f, JTextArea o ) {


connection = c;
fields = f;
output = o;
}

public void actionPerformed( ActionEvent e ) {


try {
Statement statement = connection.createStatement();

if ( !fields.last.getText().equals( "" ) &&


!fields.first.getText().equals( "" ) ) {
String query = "INSERT INTO addresses (" +
"firstname, lastname, address, city, " +
"stateorprovince, postalcode, country, " +
"emailaddress, homephone, faxnumber" +
") VALUES ('" +
fields.first.getText() + "', '" +
fields.last.getText() + "', '" +
fields.address.getText() + "', '" +
fields.city.getText() + "', '" +
fields.state.getText() + "', '" +
fields.zip.getText() + "', '" +
fields.country.getText() + "', '" +
fields.email.getText() + "', '" +
fields.home.getText() + "', '" +
fields.fax.getText() + "')";

output.append( "\nSending query: " +


connection.nativeSQL( query ) + "\n" );
int result = statement.executeUpdate( query );

if ( result == 1 ) output.append( "\nInsertion


successful\n" );
else {
output.append( "\nInsertion failed\n" );
fields.first.setText( "" );
fields.last.setText( "" );
38
Acesso a Banco de Dados

fields.address.setText( "" );
fields.city.setText( "" );
fields.state.setText( "" );
fields.zip.setText( "" );
fields.country.setText( "" );
fields.email.setText( "" );
fields.home.setText( "" );
fields.fax.setText( "" );
}
}
else output.append( "\nEnter at least first and last name
then press Add\n" );
statement.close();
}
catch ( SQLException sqlex ) {
sqlex.printStackTrace();
output.append( sqlex.toString() );
}
}
}

Código 7-3: Conectando com a ponte JDBC-ODBC

39
Acesso a Banco de Dados

package com.targettrust.java.capitulo07;

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

public class FindRecord implements ActionListener {


private ScrollingPanel fields;
private JTextArea output;
private Connection connection;

public FindRecord( Connection c, ScrollingPanel f, JTextArea o ) {


connection = c;
fields = f;
output = o;
}
public void actionPerformed( ActionEvent e ) {
try {
if ( !fields.last.getText().equals( "" ) ) {
Statement statement = connection.createStatement();
String query = "SELECT * FROM addresses " + "WHERE
lastname = '" + fields.last.getText() + "'";
output.append( "\nSending query: " +
connection.nativeSQL( query ) + "\n" );
ResultSet rs = statement.executeQuery( query );
display( rs );
output.append( "\nQuery successful\n" );
statement.close();
}
else fields.last.setText( "Enter last name here then press
Find" );
}
catch ( SQLException sqlex ) {
sqlex.printStackTrace();
output.append( sqlex.toString() );
}
}
public void display( ResultSet rs ) {
try {
if(rs.next()) {

fields.id.setText( String.valueOf( rs.getInt( 1 ) ) );


fields.first.setText( rs.getString( 2 ) );
fields.last.setText( rs.getString( 3 ) );
fields.address.setText( rs.getString( 4 ) );
fields.city.setText( rs.getString( 5 ) );
fields.state.setText( rs.getString( 6 ) );
fields.zip.setText( rs.getString( 7 ) );
fields.country.setText( rs.getString( 8 ) );
fields.email.setText( rs.getString( 9 ) );
fields.home.setText( rs.getString( 10 ) );
fields.fax.setText( rs.getString( 11 ) );
}
else output.append( "\nNo record found\n" );
}
catch ( SQLException sqlex ) {
sqlex.printStackTrace();
output.append( sqlex.toString() );
}
}
40
Acesso a Banco de Dados

package com.targettrust.java.capitulo07;

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

public class UpdateRecord implements ActionListener {


private ScrollingPanel fields;
private JTextArea output;
private Connection connection;

public UpdateRecord( Connection c, ScrollingPanel f, JTextArea o ) {


connection = c;
fields = f;
output = o;
}

public void actionPerformed( ActionEvent e ) {


try {
Statement statement = connection.createStatement();

if ( !fields.id.getText().equals( "" ) ) {
String query = "UPDATE addresses SET " +
"firstname='" + fields.first.getText() +
"', lastname='" + fields.last.getText() +
"', address='" + fields.address.getText() +
"', city='" + fields.city.getText() +
"', stateorprovince='" +
fields.state.getText() +
"', postalcode='" + fields.zip.getText() +
"', country='" + fields.country.getText() +
"', emailaddress='" +
fields.email.getText() +
"', homephone='" + fields.home.getText() +
"', faxnumber='" + fields.fax.getText() +
"' WHERE id=" + fields.id.getText();

output.append( "\nSending query: " +


connection.nativeSQL( query ) + "\n" );

int result = statement.executeUpdate( query );

if ( result == 1 ) output.append( "\nUpdate


successful\n" );
else {
output.append( "\nUpdate failed\n" );

41
Acesso a Banco de Dados

fields.first.setText( "" );
fields.last.setText( "" );
fields.address.setText( "" );
fields.city.setText( "" );
fields.state.setText( "" );
fields.zip.setText( "" );
fields.country.setText( "" );
fields.email.setText( "" );
fields.home.setText( "" );
fields.fax.setText( "" );
}

statement.close();
}
else output.append( "\nYou may only update an " +
"existing record. Use Find to " +
"locate the record, then " +
"modify the information and " +
"press Update.\n" );
}
catch ( SQLException sqlex ) {
sqlex.printStackTrace();
output.append( sqlex.toString() );
}
}
}

package com.targettrust.java.capitulo07;

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

public class Help implements ActionListener {


private JTextArea output;

public Help( JTextArea o ) {


output = o;
}
public void actionPerformed( ActionEvent e ) {
output.append( "\nClick Find to locate a record.\n" +
"Click Add to insert a new record.\n" +
"Click Update to update " +
"the information in a record.\n" +
"Click Clear to empty" +
" the textfields.\n" );
}
}

42
Acesso a Banco de Dados

package com.targettrust.java.capitulo07;

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

public class ControlPanel extends JPanel {


private JButton findName, addName,updateName, clear, help;

public ControlPanel( Connection c, ScrollingPanel s, JTextArea t ) {


setLayout( new GridLayout( 1, 5 ) );

findName = new JButton( "Find" );

findName.addActionListener( new FindRecord( c, s, t ) );


add( findName );

addName = new JButton( "Add" );


addName.addActionListener( new AddRecord( c, s, t ) );
add( addName );

updateName = new JButton( "Update" );


updateName.addActionListener( new UpdateRecord( c, s, t ) );
add( updateName );

clear = new JButton( "Clear" );


clear.addActionListener( new ClearFields( s ) );
add( clear );

help = new JButton( "Help" );


help.addActionListener( new Help( t ) );
add( help );
}
}

package com.targettrust.java.capitulo07;

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

public class ScrollingPanel extends JPanel {


private JPanel labelPanel, fieldsPanel;
private String labels[] = {
"ID number:", "First name:", "Last name:",
"Address:", "City:", "State/Province:",
"PostalCode:", "Country:", "Email:",
"Home phone:", "Fax Number:"
};
JTextField id, first, last, address, city, state, zip, country,
email, home, fax;

public ScrollingPanel() {
labelPanel = new JPanel();
labelPanel.setLayout( new GridLayout( labels.length, 1 ) );

for ( int i = 0; i < labels.length; i++ ) {


labelPanel.add( new JLabel( labels[ i ]) );
43
Acesso a Banco de Dados

fieldsPanel = new JPanel();


fieldsPanel.setLayout( new GridLayout( labels.length, 1 ) );

id = new JTextField( 20 );
id.setEditable( false );
fieldsPanel.add( id );

first = new JTextField( 20 );


fieldsPanel.add( first );

last = new JTextField( 20 );


fieldsPanel.add( last );

address = new JTextField( 20 );


fieldsPanel.add( address );

city = new JTextField( 20 );


fieldsPanel.add( city );

state = new JTextField( 20 );


fieldsPanel.add( state );

zip = new JTextField( 20 );


fieldsPanel.add( zip );

country = new JTextField( 20 );


fieldsPanel.add( country );

email = new JTextField( 20 );


fieldsPanel.add( email );

home = new JTextField( 20 );


fieldsPanel.add( home );

fax = new JTextField( 20 );


fieldsPanel.add( fax );

setLayout( new GridLayout( 1, 2 ) );

add( labelPanel );
add( fieldsPanel );
}
}

44
Acesso a Banco de Dados

package com.targettrust.java.capitulo07;

import java.awt.*;
import java.awt.event.*;

public class ClearFields implements ActionListener {


private ScrollingPanel fields;

public ClearFields( ScrollingPanel f ) {


fields = f;
}
public void actionPerformed( ActionEvent e ) {
fields.id.setText( "" );
fields.first.setText( "" );
fields.last.setText( "" );
fields.address.setText( "" );
fields.city.setText( "" );
fields.state.setText( "" );
fields.zip.setText( "" );
fields.country.setText( "" );
fields.email.setText( "" );
fields.home.setText( "" );
fields.fax.setText( "" );
}
}

A classe AddressBook utiliza um objeto ControlPanel e um objeto


ScrollingPanel para a GUI do programa. Estabelecemos a conexão de banco de
dados passando para getConnection o String URL para JDBC. Classes
separadas são definidas para tratar eventos de cada um dos cinco botões na
interface com o usuário.

A classe AddRecord adiciona um novo registro ao banco de dados em


resposta ao botão <Add> na GUI. O construtor do AddRecord) aceita três
argumentos - uma Connection, um ScrollingPanel e uma JTextArea que serve
como uma área de saída para mensagens exibidas por esse programa.

No método actionPerformed criamos um objeto Statement para manipular


o banco da dados.

Testamos se exitem dados nos campos de text. Se esses campos de texto


não contiverem dados, nenhum registro será adicionado ao banco de dados.
Construímos a String de SQL INSERT INTO que será utilizado para adicionar
registro ao banco de dados.

45
Acesso a Banco de Dados

46
Acesso a Banco de Dados

Cada nome de coluna a ser atualizado é especificado em uma lista


separada por vírgulas entre parênteses. O valor para cada coluna é
especificado depois da palavra-chave VALUES de SQL em outra lista separada
por vírgulas entre parênteses.

Utilizamos o método Statement executeUpdate para atualizar o banco de


dados com o novo registro. O método retorna um int indicando o sucesso ou
fracasso da operação de atualização que é testado. Se a atualização for mal
sucedida, todos os campos de texto serão limpos.

A classe FindRecord pesquisa no banco de dados um registro especifico


em resposta ao botão <Find> na GUI. Testamos.

Chamamos o método display e passamos o ResultSet retornado pela


chamada a executeQuery.

O primeiro registro é obtido chamando o método next. Obtemos o número


de registro do objeto ResultSet rs chamando getInt. Determinamos se o
número de registro é diferente de zero. Se for, os campos de texto serão
preenchidos com dados do registro. Exibimos o String do primeiro nome
retomado pelo método getString de Resultset, O argumento 2 referencia o
número de coluna (os números de coluna iniciam a patir de 1) no registro.
Instruções semelhantes são executadas para cada campo de texto. Quando
essa operação é completada, a GUI exibe o primeiro registro do Resultset.

A classe UpdateRecord atualiza um registro de banco de dados existente.


Criamos a consulta String query de SQL UPDATE. Enviamos a consulta para o
banco de dados chamando o método executeUpdate.

A classe ClearFields é responsável por limpar os campos de texto em


resposta ao botão <Clear> na GUI e a classe Help exibe instruções sobre como
utilizar o programa na janela de console na pane inferior da tela.

47
Acesso a Banco de Dados

Processamento de Transações

Se o banco de dados suporta o processamento de transações, as


alterações feitas no banco de dados podem ser desfeitas. Java fornece
processamento de transações via métodos da interface Connection.

O método setAutoCommit especifica se cada instrução individual de SQL


deve ser realizada e ser comprometida individualmente (um argumento true)
ou se várias instruções de SQL devem ser agrupadas como uma transação (um
argumento false).

Se o argumento para setAutoCommit for false, o Statement que executa


as instruções de SQL deve ser terminado com uma chamada para o método
commit de Connection (para “comprometer” - “efetuar” - as alterações no
banco de dados) ou método rollback (para retomar o banco de dados para seu
estado anterior ao início da transação). A interface Connection também
fornece o método getAutoCommit para determinar o estado de autoCommit.

48
Acesso a Banco de Dados

Exercícios

1. Neste capítulo vimos como podemos trabalhar com banco de dados em


aplicações java. Agora você irá implementar na aplicação do curso estas
técnicas estudadas no capítulo 07. Primeiro implemente um código que
possa validar o usuário e senha da sua tela de login do sistema. Em
seguida você deverá implementar classes que permitam salvar os dados
da aplicação em um banco de dados.

Realize este exercício de acordo com as instruções do seu instrutor.

49

You might also like