• Nenhum resultado encontrado

APOSTILA DE ESTRUTURA DE DADOS I

N/A
N/A
Protected

Academic year: 2021

Share "APOSTILA DE ESTRUTURA DE DADOS I"

Copied!
63
0
0

Texto

(1)

ESCOLA ESTADUAL DE ENSINO PROFISSIONAL Dr. SOLON TAVARES

ESTRUTURA DE DADOS I PROFESSOR

Engenheiro ALEXANDRE DIEFENTHÄLER Criada em 2012/1

(2)

2 Collections ... 1 2.1 List ... 2 2.1.2 ArrayList ... 4 3 Swing ... 5 3.1 Listeners ... 5 3.2 Hierarquização ... 6 3.3 Encapsulamento ... 6 3.4 Classificação ... 7 3.5 Modularização ... 8 3.6 Relacionamento ... 8 4 Conceitos básicos... 9 4.1 Objeto ... 9 4.2 Classe ... 9 4.3 Colaboração ... 10 4.3.1 Generalização/Especialização ... 10 4.4 Polimorfismo ... 11 5 UML ... 12

6 Diagramas de caso de uso ... 14

7 Diagrama de Classes ... 17 7.1 Identificando Classes ... 17 7.2 Relacionamentos ... 18 7.2.1 Dependência... 18 7.2.2 Herança ... 19 Exercício 1... 19

8 Linguagem de programação JAVA ... 20

8.1 Principais objetivos da tecnologia java ... 21

8.2 A Java Virtual Machine... 22

8.3 O garbage collection ... 22

(3)

8.5.3 Compilando e executando o código ... 24

9 Introdução a linguagem de programação JAVA ... 26

9.1 JREs e JDKs ... 26

9.2 Atributos ... 27

9.2.1 Booleanos ... 27

9.2.2 Caracteres ... 28

9.2.3 Inteiros ... 28

9.2.4 Número em ponto flutuante ... 28

9.3 Operadores Aritméticos... 28 9.4 Atribuição composta ... 29 9.5 Incremento e decremento... 29 Exercício 2... 29 9.6 Relacionais... 30 9.7 Lógicos ... 30 9.8 Estruturas de controle... 30

9.8.1 Estruturas de controle if... 30

9.8.2 Estrutura de seleção switch... 32

9.8.3 Estruturas de repetição ... 32 9.9 Modificadores de acesso ... 33 Exercício 3... 37 9.10 Classes wrappers ... 39 9.11 Herança... 40 9.12 Polimorfismo ... 44 10 Referências bibliográficas ... 48

(4)

1 INTRODUÇÃO

Na Ciência da computação, uma estrutura de dados é um modo particular de armazenamento e organização de dados em um computador, de modo que possam ser usados eficientemente.[1]

Diferentes tipos de estrutura de dados são adequados a diferentes tipos de aplicações e algumas são altamente especializadas, destinando-se a algumas tarefas específicas. Por exemplo, as B-TREEs são particularmente indicadas para a implementação de bases de dados , enquanto que a implementação de compiladores, geralmente, requer o uso de tabela de dispersão para a busca de identificadores. [1]

Estruturas de dados e algoritmos são temas fundamentais da ciência da computação, sendo utilizados nas mais diversas áreas do conhecimento e com os mais diferentes propósitos de aplicação. Sabe-se que algoritmos manipulam dados. Quando estes dados estão organizados (dispostos) de forma coerente, se caracteriza uma forma, uma estrutura de dados. A organização e os métodos para manipular essa estrutura é que lhe confere singularidade. [1]

As estruturas de dados são chamadas tipos de dados compostos que se dividem em homogêneos (vetores e matrizes) e heterogêneos (registros). As estruturas homogêneas são conjuntos de dados formados pelo mesmo tipo de dado primitivo. As estruturas heterogêneas são conjuntos de dados formados por tipos de dados primitivos diferentes (campos do registro) em uma mesma estrutura. A escolha de uma estrutura de dados apropriada pode tornar um problema complicado em outro de solução, relativamente, simples. O estudo das estruturas de dados está em constante desenvolvimento (assim como o de algoritmos), mas, apesar disso, existem certas estruturas clássicas que se comportam como padrões. [1]

As filas são estruturas baseadas no princípio FIFO (first in, first out), em que os elementos que foram inseridos no início são os primeiros a serem removidos. Uma fila possui duas funções básicas: ENQUEUE, que adiciona um elemento ao final da fila, e DEQUEUE, que remove o elemento no início da fila. A operação DEQUEUE só pode ser aplicada se a fila não estiver vazia, causando um erro de underflow ou fila vazia se esta operação for realizada nesta situação. [1]

As pilhas são estruturas baseadas no princípio LIFO (last in, first out), na qual os dados que foram inseridos por último na pilha serão os primeiros a serem removidos. Existem duas funções que se aplicam a todas as pilhas: PUSH, que insere um dado no topo da pilha, e POP, que remove o item no topo da pilha. [1]

Uma Lista é uma estrutura de dados linear. Uma lista ligada, também chamada de encadeada, é linear e dinâmica, composta por nós que apontam para o próximo elemento da lista, com exceção do último, que não aponta para ninguém. Para compor uma lista encadeada, basta guardar seu primeiro elemento. [1]

Árvore, no contexto da programação e ciência da computação, é uma estrutura de dados que herda as características das topologias em árvore. Conceitualmente diferente das listas encadeadas, em que os dados se encontram numa sequência, nas árvores os dados estão dispostos de forma hierárquica. [7]

A Árvore é composta por 1(um) Elemento principal chamado Raiz, que possui ligações para outros Elementos, que são denominados de Ramos ou filhos. Estes ramos levam a outros elementos que também possuem outros ramos. O elemento que não possui ramos é conhecido como Folha e/ou Nó-terminal. [7]

(5)

em aplicativos com interfaces gráficas próprias da linguagem de programação Java, que utiliza um framework chamado swing. Os aplicativos serão desenvolvidos com a IDE (Interface de Desenvolvimento) netbeans, mas o uso de outra IDE, como o Eclipse é de livre escolha.

Swing é um widget toolkit para uso com o Java. Ele é compatível com o Abstract Window Toolkit (AWT), mas trabalha de uma maneira totalmente diferente. A API Swing procura renderizar\desenhar por conta própria todos os componentes, ao invés de delegar essa tarefa ao sistema operacional, como a maioria das outras APIs de interface gráfica trabalham. [2]

Por ser uma API de mais alto nível, ou seja, mais abstração, menor aproximação das APIs do sistema operacional, ela tem bem menos performace que outras APIs gráficas e consome mais memória RAM em geral. Porém, ela é bem mais completa, e os programas que usam Swing têm uma aparência muito parecida, independente do Sistema Operacional utilizado. [2]

JDBC, ou Java Data Base Connectivity (Conectividade Java com Banco de Dados), é um conjunto de interfaces e classes em Java que tem como objetivo padronizar o modo com que um aplicativo qualquer se conecte com banco de dados. É inspirado no padrão Microsoft de acesso a banco de dados, ODBC (Open DataBase Connectivity), porém tem a vantagem de ser multi-plataforma. Além da independência da plataforma, o Java também visa obter independência de banco de dados, conforme será verificado mais adiante. Isto significa que ao se trocar de banco de dados, espera-se pouca alteração na aplicação, aumentando o reuso de um aplicativo. [8]

(6)

2 COLLECTIONS

No segundo módulo foram apresentados vetores unidimensionais e bidirecionais (matrizes), criando classes e métodos para inserir, pesquisar e excluir itens nessas estruturas. No terceiro módulo serão apresentadas algumas coleções Java que implementam todas essas operações de maneira mais fácil.

Com as coleções, os programadores utilizam estruturas de dados existentes sem se preocupar com a maneira que elas são implementadas. Uma coleção é uma estrutura de dados que pode armazenar referências a outros objetos. As interfaces de estruturas de coleções declaram as operações a serem realizadas genericamente em vários tipos de coleções. [5]

A interface collection é a interface-raíz de coleções a partir da qual as interfaces Set, Queue e List são derivadas. A interface Set define uma coleção que não contém duplicatas. A interface Queue define uma coleção que representa uma fila de espera. [5]

A interface collection contém operações de volume (isto é, operações realizadas na coleção inteira) para adicionar, limpar, comparar e manter objetos (ou elementos) em uma coleção. Uma

collection também pode ser convertida em uma array. Além disso, a interface collection fornece um

método que retorna um objeto Iterator, que permite a um programa, percorrer a coleção e remover elementos da coleção durante a sua iteração. [5]

2.1 List

Uma List (às vezes, chamada de seqüência) é uma coleção ordenada que pode conter elementos duplicados. Como arrays, índices de List são baseados em zero (isto é, o índice do primeiro elemento é zero). Além dos métodos herdados de collections, List fornece métodos para manipular elementos e seus índices, manipular o intervalo especificado de elementos, procurar elementos e obter um ListIterator para acessar os elementos. [5]

2.1.1 ArrayList

A interface List é implementada por várias classes, incluídas as classes ArrayList, LinkedList e

Vector. [5]

O comportamento e as capacidades da classe ArrayList são semelhantes àquelas da classe Vector. A principal diferença entre Vector e ArrayList é que os objetos da classe Vector são sincronizados por padrão, enquanto que os objetos da classe ArrayList não são. [5]

Nos exemplos dessa apostila será utilizada, com mais freqüência, a classe ArrayList, mas o leitor pode se sentir livre para pesquisar todo o pontecial que as coleções Java podem oferecer, com suas vantagens e desvantagens. Há diversos livros e apostilas na internet que disponibilizam um vasto material de pesquisa dessas coleções.

A classe ArrayList possui um vetor que é populado através de métodos específicos, facilitando o uso de um vetor como objeto de armazenamento de outros objetos. O exemplo abaixo mostra como deve ser instanciado um objeto da classe ArrayList:

public class TesteArrayList{

public static void main(String[] args){

ArrayList arrayList = new ArrayList();

arrayList.add(1); arrayList.add(2); }}

(7)

que adiciona, através do método add(Object e), qualquer valor primitivo (1,2,3...) ou mesmo um objeto qualquer. Para utilizar a classe ArrayList, será necessário fazer a seguinte importação:

java.util.ArrayList. Independente da IDE que estiver usando (Netbeans ou Eclipse), essa importação será

sugerida, mas cuidado com as sugestões, pois mais de uma importação de pacote pode ser oferecida, e a correta, nesse caso, é java.util.ArrayList.

A classe ArrayList ainda possui um overload do método add(Object e). O método do exemplo anterior recebe apenas um parâmeto, enquanto o outro método recebe, além do mesmo parâmetro, o índice da posição que se quer que o item seja colocado no arrayList. Veja o exemplo modificado:

public class TesteArrayList{

public static void main(String[] args){

ArrayList arrayList = new ArrayList(); arrayList.add(1);

arrayList.add(2);

arrayList.add(2, “Nome”); arrayList.add(3, “sobreNome”); arrayList.add(5, “teste”);ERRO! }}

Nesse exemplo há um aviso de “ERRO!”. Você saberia dizer por que essa linha de código provocaria uma exceção chamada java.lang.IndexOutOfBoundsException?

Outro método importante da classe ArrayList é o addAll(Collection c). Como o próprio nome em inglês sugere, o “All” permite adicionar uma coleção inteira em um ArrayList, o que é muito útil quando se quer fazer uma cópia. Exemplo:

public class TesteArrayList{

public static void main(String[] args){ ArrayList arrayList = new ArrayList(); arrayList.add(1);

arrayList.add(2);

arrayList.add(2, "Nome"); arrayList.add(3, "sobreNome");

ArrayList arrayListCopia = new ArrayList();

arrayListCopia.addAll(arrayList);

}}

Em todos os exemplos, o objeto da classe ArrayList armazenou dois inteiros primitivos e dois objetos da classe String. Isso é possível porque os parâmetros dos métodos add são da classe Object, portanto, o ArrayList pode armazenar todos os tipos da linguagem de programação Java.

Uma vez armazenados os objetos no objeto da classe ArrayList, pode ser necessário listá-los. Para isso, será necessário percorrer o objeto arrayList. A forma mais simples é utilizando um laço for, mas outros tipos de laços podem ser usados. Exemplo:

public class TesteArrayList{

public static void main(String[] args){ ArrayList arrayList = new ArrayList(); arrayList.add(1);

arrayList.add(2);

(8)

arrayList.add(3, "sobreNome");

for(int i=0; i<arrayList.size(); i++){ Object tmp = arrayList.get(i);

System.out.println("Você armazenou:"+tmp); }

}}

No escopo (parte do código que fica entre as chaves) do método for foi instanciado um objeto da classe Object chamado de “tmp”. Esse objeto conterá, a cada loop, um objeto retornado do arryList indicado pelo índice ‘i’, que começa com zero e é incrementado até que seja atingido o número de objetos armazenado no arrayList, retornado pelo método size().

Outra variação do laço for é o chamado enhanced for. Exemplo:

public class TesteArrayList{

public static void main(String[] args){ ArrayList arrayList = new ArrayList(); arrayList.add(1); arrayList.add(2); arrayList.add(2, "Nome"); arrayList.add(3, "sobreNome"); for(Object tmp : arrayList){ System.out.println("Você armazenou: "+tmp); } }}

No laço enhanced for não é necessário o uso do índice ‘i’ ou do método size() do

arrayList. A cada loop, o próximo item contido no arrayList é passado à variável temporária

tmp. Com essa abordagem, o código fica mais fácil de entender.

No entanto, a melhor maneira para percorrer uma coleção é utilizar o seu objeto iterator, que ganha em velocidade e desempenho. Para se obter um objeto iterator da coleção, deve-se invocar o método iterator() da coleção que estiver usando. Exemplo:

public class TesteArrayList{

public static void main(String[] args){ ArrayList arrayList = new ArrayList(); arrayList.add(1);

arrayList.add(2);

arrayList.add(2, "Nome"); arrayList.add(3, "sobreNome"); Iterator iterar = arrayList.iterator(); while(iterar.hasNext()){

Object tmp = iterar.next();

System.out.println("Você digitou: "+tmp); }

}}

Um objeto da classe Iterator não é instanciado da maneira comvencional, utilizando new, mas é obtido através do método iterator() de uma coleção. O objeto Iterator possui dois métodos muito importantes: o hasNext() e o next(). O primeiro retorna true para o caso de ainda haver itens na coleção e false se não há mais itens na coleção. Um laço while é comumente utilizado. O método next() retorna o objeto armazenado na coleção.

(9)

Para um exemplo prático com ArrayList, utilizando uma interface gráfica, será apresentado o framework swing, criando um novo projeto na IDE netbeans chamado cadastro simples. Nesse projeto, são criados dois pacotes: interfaces e javabeans. No pacote interfaces é criada uma classe chamada Cadastro, enquanto que, no pacote javabeans, outra classe chamada

Pessoa. A estrutura no netbeans deve ficar como na figura 1.

Figura 1: estrutura do projeto.

A classe Pessoa será o javabean ( ou bean, apenas) que conterá os dados pessoais de uma pessoa, por exemplo. As IDEs são conhecidas por agilizar o trabalho do desenvolvedor ao criar os beans de forma rápida e padronizada. Para isso, são criados dois atributos na classe

Pessoa chamados de nome e idade. Procure na barra de menus o menu “refatorar” e dê um

clique. Nas opções, procure por “Encapsular campos” e dê um clique. Uma janela como a da figura 2 deve aparecer.

Figura 2: janela para gerar os métodos gettes e setters.

Na janela sobreposta aparecerão os atributos criados e caixas de seleção para escolher os métodos getters e setters necessários. Nesse exemplo, serão necessários todos, portanto, na parte superior, à direita, clique em “selecionar tudo”. Para finalizar, clique em “refatorar.” Verificando

(10)

o código da classe, é possível ver que os métodos foram criados automaticamente. O bean está pronto!

A classe Cadastro será a parte gráfica que irá proporcionar interação com o usuário. Uma janela básica com swing pode ser construída de várias maneiras, mas todas as possibilidades utilizam a classe chamada JFrame. Essa classe cria o que representa a parte externa da janela (quadro ou frame) e o espaço interno, que será ocupado por um objeto de outra classe. Todos os componentes do swing têm a letra ‘J’ na frente, mas o swing ainda faz uso de algumas classes do AWT, que não tem o ‘J’.

Nos exemplos dessa apostila, as classes que serão as janelas do sistema herdarão JFrame. A janela básica é apresentada na figura 3.

Figura 3: janela básica criada com JFrame.

O código que corresponde à janela acima é apresendato abaixo:

public class Cadastro extends JFrame {

public Cadastro(){

}

public static void main(String[] args){

Cadastro cadastro = new Cadastro(); } }

O código acima, ao ser executado, não cria uma janela, pois estão faltando itens de configuração básicos da janela como tamanho, posicionamento, etc. Os métodos de configuração de uma janela são muitos, mas os apresentados no código a seguir já são suficientes. Esses métodos são invocados no construtor da classe.

public class Cadastro extends JFrame { public Cadastro(){

this.setLayout(null);

this.setSize(300, 300);

(11)

this.setExtendedState(JFrame.MAXIMIZED_BOTH);

this.setVisible(true);

}

public static void main (String[] args){

new Cadastro();

}}

Com a invocação desses métodos no costrutor, a janela da figura 3 é criada ao executar a classe Cadastro. O método setLayout(null) define o layout de como os componentes serão dispostos na janela. É possível usar os gerenciadores de layout que existem no swing e serão vistos mais adiante, mas para esse exemplo, o parâmetro é null, indicando que a página será definida por posicionamento absoluto.

O segundo método, setSize(300, 300), define o tamanho da janela, como se define um quadrado ou retângulo. O método setLocationRelativeTo(null) define o posicionamento da janela no monitor como no topo à esquerda, abaixo à esquerda, no topo à direita, etc. Passando null como parâmetro, a janela aparecerá no centro da tela do monitor.

O método setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) é utilizado para, quando o usuário fechar a janela clicando no ‘x’ no canto superior, à direita, a execução de

Cadastro (principal) e todo o aplicativo seja “fechado”. É necessário passar como parâmetro

uma constante da classe JFrame chamada de JFrame.EXIT_ON_CLOSE.

O penúltimo método é setExtendedState(JFrame.MAXIMIZED_BOTH) que indica que a janela deve ocupar toda a tela do monitor. O método setSize(300, 300) é ignorado então, valendo apenas se o usuário optar por diminuir a janela no “restaurar abaixo”, no canto superior, à direita. Por fim, o último método que é muito importante, o setVisible(true), que faz com que a janela seja, efetivamente, exibida, passando como parâmetro o booleano true.

Essa configuração é suficiente para que seja possível criar uma janela padrão para qualquer aplicação. Assim, sempre que precisar criar uma janela, pode tomar esse exemplo como modelo.

Trabalhar com o posicionamento absoluto dos componentes oferece mais liberdade ao desenvolvedor para criar aplicativos personalizados e muitos podem se acostumar com essa prática, mas a manutenção e o desenvolvimento rápido podem ser prejudicados. Nesse exemplo, o método setLayout(null) permite criar a janela dessa forma.

Tentando desenvolver boas práticas à formação do aluno, mas sem dificultar o aprendizado inicial, optou-se pelo posicionamento absoluto na criação da primeira janela, como pôde ser visto na figura 3. Nesse caso, é possível colocar os componentes diretamente no objeto do JFrame (uma prática muito pouco utilizada) ou instanciar um objeto da classe Container de JFrame e, então, nesse colocar os componentes. No entanto, para uma melhor organização, é possível colocar os componentes em objetos da classe JPanel e, então, esses objetos serem adicionados ao objeto da classe Container. Verifique o código abaixo e identifique, em vermelho, o objeto da classe Container, o primeiro atributo do aplicativo.

(12)

public class Cadastro extends JFrame {

private Container telaPrincipal;

public Cadastro(){

this. telaCentral = this.getContentPane();

this.setLayout(null); this.setSize(300, 300); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setExtendedState(JFrame.MAXIMIZED_BOTH); this.setVisible(true); }

public static void main (String[] args){

new Cadastro();

}}

Bons desenvolvedores que programam em orientação a objetos sabem que, como explicado antes, em um javabeans deve-se sempre criar getter e setters. Como estamos desenvolvendo uma janela para o aplicativo, deduzimos que não é um javabeans. Portanto, fica a dúvida: devemos criar getters e setters para o atributo telaPrincial? A resposta é sim ou não. Utilizar getters e setters, nesse caso, tornaria o programa corerente com as boas práticas de programação, mas também, conforme o número de atributos cresce em uma aplicação desktop, a utilização de getters e setters pode deixar o código “carregado” e difícil de entender. Assim, optamos por referênciar diretamente o atributo dentro dos métodos da classe Cadastro. Lembre-se que a palavra reLembre-servada (que não pode Lembre-ser usada para outra coisa) this é implícita no código. Ou seja: escrever da forma this.telaCentral ou apenas telaCentral não tem diferença. Nos exemplos dessa apostila optou-se utilizar o this explicitamente para um melhor entendimento.

Note que o objeto telaCentral não é instanciado com a palavra new, mas com um método da própria classe JFrame chamado this.getContentPane() ou apenas getContentPane(). Com o

objeto telaPrincipal é possível, por exemplo, definir a cor de fundo. Veja o código abaixo e o resultado na figura 4, e compare com a figura 3.

public class Cadastro extends JFrame {

private Container telaPrincipal;

public Cadastro(){

this. telaCentral = this.getContentPane(); this.telaPrincipal.setBackground(Color.WHITE); this.setLayout(null); this.setSize(300, 300); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setExtendedState(JFrame.MAXIMIZED_BOTH); this.setVisible(true); }

(13)

new Cadastro();

}}

Figura 4: janela com fundo branco.

O próximo passo é criar os JPanels que serão adicionados ao container (telaPrincipal). Para isso, no mesmo pacote chamado interfaces, vamos criar outra classe chamada

IncluirCadastro. Essa classe não herdará JFrame, mas JPanel.

public class IncluirCadastro extends JPanel{

private JLabel nome;

private JLabel idade;

public IncluirCadastro(){

this.nome = new JLabel("Nome");

this.idade = new JLabel("idade");

this.nome.setBounds(10, 10, 50, 20); this.idade.setBounds(10, 50, 50, 20); this.add(nome); this.add(idade); this.setBounds(10, 10, 200, 200); this.setBackground(Color.RED); this.setLayout(null); this.setVisible(true); }}

A classe JPanel é similar a JFrame, porém mais simples. Estudando o código acima, é possível verificar que existem alguns métodos que existem também para JFrame, como

setLayout. Não há objeto da classe Container em IncluirCadastro, sendo os componentes

adiconados diretamente ao JPanel IncluirCadastro. Os componetes são da classe JLabel (ou rótulos) que são palavras que aparecerão na tela. O posicionamento absoluto é criado com o método setBounds(x, y, largura, altura). Intuitivamente, percebe-se que o posicionamento absoluto utiliza as coordenadas ‘x’ e ‘y’ do plano cartesiano. Por fim, os componentes são adicionados no JPanel criado, IncluirCadastro.

(14)

O projeto cadastroSimples tem, agora, duas classes para interagir com o usuário:

Cadastro que é um JFrame, e IncluirCadastro que é um JPanel. Como incluir um JPanel do

tipo IncluirCadastro em um JFrame Cadatro? Verifique o código abaixo:

public class Cadastro extends JFrame { private Container telaPrincipal;

private IncluirCadastro incluirCadastro;

public Cadastro(){

telaCentral = this.getContentPane(); telaPrincipal.setBackground(Color.WHITE);

incluirCadastro = new IncluirCadastro(); telaPrincipal.add(incluirCadastro); setLayout(null); setSize(300, 300); setLocationRelativeTo(null); .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setExtendedState(JFrame.MAXIMIZED_BOTH); setVisible(true); }

public static void main (String[] args){

new Cadastro();

}}

Para variar os exemplos, perceba que a palavra this foi removida do código não alterando em nada a sua execução, pois ela é implícita. O resultado da execução é apresentado na figura 5.

Figura 5: tela Cadastro com o painel IncluirCadastro.

No aplicativo de exemplo, foram instanciados apenas os labels (ou rótulos), mas nenhum campo para que o usuário possa digitar seu nome e sua idade. Esses campos são instanciados como objetos da classe JTextfield, também instanciados na classe IncluirCadastro. Veja o código abaixo:

(15)

public class IncluirCadastro extends JPanel{

private JLabel nome;

private JLabel idade;

private JTextField tnome;

private JTextField tidade;

public IncluirCadastro(){

this.nome = new JLabel("Nome");

this.idade = new JLabel("idade");

this.tnome = new JTextField();

this.tidade = new JTextField();

this.nome.setBounds(10, 10, 50, 20); this.idade.setBounds(10, 50, 50, 20); this.tnome.setBounds(50, 10, 200, 20); this.tidade.setBounds(50, 50, 50, 20); this.add(nome); this.add(idade); this.add(tnome); this.add(tidade); this.setBounds(10, 10, 300, 200); this.setBackground(Color.RED); this.setLayout(null); this.setVisible(true); }}

Dois campos foram instanciados para que o usuário possa digitar o nome e a idade, chamados, respectivamente de tnome e tidade, destacados em vermelho no código acima. O resultado, na tela, é apresentado na figura 6.

(16)

Por fim, o componente que está faltando é o botão “cadastrar”. Esse botão é instanciado como um objeto da classe JButton. Verifique o código de IncluirCadastro com esse componente.

public class IncluirCadastro extends JPanel{

private JLabel nome;

private JLabel idade;

private JTextField tnome;

private JTextField tidade;

private JButton cadastrar;

public IncluirCadastro(){

this.nome = new JLabel("Nome");

this.idade = new JLabel("idade");

this.tnome = new JTextField();

this.tidade = new JTextField();

this.cadastrar = new JButton("cadastrar");

this.nome.setBounds(10, 10, 50, 20); this.idade.setBounds(10, 50, 50, 20); this.tnome.setBounds(50, 10, 200, 20); this.tidade.setBounds(50, 50, 50, 20); cadastrar.setBounds(100, 100, 100, 20); this.add(nome); this.add(idade); this.add(tnome); this.add(tidade); this.add(cadastrar); this.setBounds(10, 10, 300, 200); this.setBackground(Color.RED); this.setLayout(null); this.setVisible(true); }}

(17)

Figura 7: botão cadastrar incluído no painel.

3.1 Listeners

Listener (ou ouvinte, em tradução livre) é uma interface que define métodos que, ao

clicar em um dos componentes, acionam uma ação específica para tratar um evento, como em um clique um botão, a mudança de valor de um campo em um componente JTextField, etc.

A ação a ser executada é implementada pelo próprio desenvolvedor conforme as exigências do aplicativo que está sendo construído. No exemplo proposto até aqui, quando um usuário digitar um nome e uma idade, espera-se que esses dados sejam armazenados em um

ArrayList. Mas a questão é que, ao criar o botão e clicar nele, nada ocorrerá, pois o botão não

adicionou nenhum listener.

Em vários livros, apostilas e exemplos na internet existem três formas possíveis de se implementar um listener para cada um dos componentes. Uma delas são as classes privadas, também chamadas de handlers, onde classes são criadas dentro de classes! Veja o exemplo do código da classe IncluirCadastro com uma classe privada.

public class IncluirCadastro extends JPanel{

public IncluirCadastro(){

}

private class JButtonHandler implements ActionListener{

@Override

public void actionPerformed(ActionEvent e) {

throw new UnsupportedOperationException("Not supported yet.");}}}

No exemplo não foram mais repetidas todas as linhas de código que já existem nos exemplos anteriores porque nada muda. Assim, serão apresentadas apenas as partes relativas aos

listeners. A classe privada foi chamada de JButtonHandler e implementa a interface mais

utilizada como listener em Java swing, chamada ActionListener. Por fim, essa interface exige a implementação do método actionPerformed, que é o método que será utilizado pelo desenvolvedor para implementar as ações, quando o usuário disparar um evento.

(18)

A linha de código throw new UnsupportedOperationException("Not supported yet.") serve apenas para

informar que nenhuma ação foi implementada pelo desenvolvedor, podendo ser apagada depois. Na assinatura do método actionPerformed há um parâmetro da classe ActionEvent chamado ‘e’ (é possível trocar o nome desse parâmetro), que traz informações de um evento, por exemplo, o clique em um botão. Dessa forma, por uma classe privada, o listener para o botão cadastrar da classe IncluirCadastro está pronto para ser implementado, como mostra o exemplo.

public class IncluirCadastro extends JPanel{

public IncluirCadastro(){

cadastrar.addActionListener(new JButtonHandler());

}

private class JButtonHandler implements ActionListener{

@Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

JOptionPane.showMessageDialog(null, "Você clicou no botão cadastrar!", "Sucesso!", JOptionPane.PLAIN_MESSAGE);

}

}}}

Lembrando novamente, todas as linhas de código precisam estar presentes como nos exemplos anteriores que, por uma questão de espaço na apostila, apenas as partes novas são apresentadas.

Perceba que no corpo do método actionPerformed foi colocado um if para testar qual evento foi disparado e capturado pelo objeto da classe ActionEvent, que traz todos os componentes que foram adicionados ao listener JButtonHandler. Como adicionar um listener (ou handler) ao componente? Observe a linha cadastrar.addActionListener(new JButtonHandler()); e verá

que o botão cadastrar adiciona a si, o handler JButtonHandler, passando como parâmetro um objeto da classe JButtonHandler sem nenhuma referência, afinal, esse objeto não será usado para mais nada.

Para verificar qual componente foi disparado pelo usuário, o objeto ActionEvent, nesse caso chamado de ‘e’, utiliza o método equals passando como parâmetro o objeto que se quer testar, o botão cadastrar. Se confirmado que o botão cadastrar foi o evento disparado, todo o método retorna true para aquele if, permitindo que o desenvolvedor implemente alguma ação para o usuário.

A ação implementada no corpo do método actionPerformed é uma janela da classe

JOptionPane, que permite, entre outras coisas, enviar mensagens à janela para o usuário. O

método estático dessa classe, entre muitos, que foi utilizado é o showMessageDialog que tem quatro parâmetros: null, string, string, ícone. O primeiro parâmetro, null, informa ao método

showMessageDialog que a janela deve ficar no centro do monitor. O segundo parâmetro coloca

na janela a mensagem para o usuário. O terceiro coloca uma mensagem na barra azul da janela e, por fim, o último parâmetro é uma constante em da classe JOptionPane que seleciona um ícone para aparecer ao lado da mensagem para o usuário. Nesse caso, é um ícone de que a operação ocorreu com sucesso. Veja o resultado na figura 8.

(19)

Figura 8: janela com o listener (ou handler) implementado.

A segunda forma de implementar um listener para um componente é utilizando as chamadas classes anônimas. Essas classes são passadas pelo construtor do método

addActionListener do componente. O resultado é igual ao obtido na figura 8, mas ao contrário da

forma utilizando as classes privadas, não é necessário utilizar um if, pois como a classe anônima foi passada como parâmetro, ela atende apenas o componente que a adicionou. O código, dessa forma, tende a ficar mais “limpo”, mas a desvantagem é que, para cada componente, deverá se criar uma classe anônima, como mostra o código abaixo.

public class IncluirCadastro extends JPanel{

public IncluirCadastro(){

cadastrar.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {

JOptionPane.showMessageDialog(null, "Você

clicou no botão cadastrar!", "Sucesso!", JOptionPane.PLAIN_MESSAGE);

}});

}}}}

A terceira e última maneira de implementar um listener é fazer a própria classe implementar a interface do listener. Assim, a classe será obrigada a implementar o método

actionPerformed para seus componentes. A classe IncluirCadastro ficaria como apresentado no

código abaixo.

public class IncluirCadastro extends JPanel implements ActionListener {

public IncluirCadastro(){

cadastrar.addActionListener(this);

}

@Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

JOptionPane.showMessageDialog(null, "Você clicou no

botão cadastrar!", "Sucesso!", JOptionPane.PLAIN_MESSAGE);

(20)

}

}}}

Essa será a forma que os exemplos da apostila irão apresentar as implementações dos

listeners, mas o aluno pode ficar a vontade para utilizar a que se sentiu mais confortável para

implementar os seus trabalhos.

A diferença com as duas anteriores está no método addActionListener que passa como parâmetro, a palavra this que, nesse caso, é obrigatória. Ela é necessária para adicionar o objeto dessa classe, IncluirCadastro, ao listener ActionListener. O método actionPerformed é implementado como em classes privadas, com a utilização de ifs se houver mais componentes.

3.2 Utilizando ArrayList

Agora que o básico foi apresentado para a construção de uma janela, o próximo passo é usar a Collection ArrayList para armazenar o que o usuário digitar nos campos. Para isso, é preciso capturar o que foi digitado nos campos assim que o usuário clicar no botão cadastrar, o que foi implementado como nos exemplos anteriores no método actionPerformed. O exemplo do código mostra apenas o escopo do método actionPerformed.

@Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

String nome = tnome.getText();

String idade = tidade.getText();

}}

No código é possivel perceber em vermelho, que os campos tnome e tidade possuem um método em comum, entre outros, que será muito utlizado: getText(). Intuitivamente, sabe-se que esse método retorna uma string, que é aquilo que o usuário do aplicativo digitou nos campos. Mesmo quando o usuário não digitar nada, o método getText() irá retornar algo, nesse caso, vazio.

Outro ponto importante é quanto ao nome das variáveis. Retornando aos exemplos anteriores, note que a variável nome, que é uma String, tem o mesmo nome (ou identificador de referência) que o atributo nome, que é um JLabel! Por que não ocorre um erro? Isso tem a ver com o chamado escopo das variáveis, onde a variável String nome existe apenas entre as chaves do método actionPerformed e não fora dele! Portanto, a classe IncluirCadastro não “enxerga” essa variável e não causa conflito com o atributo JLabel nome. Mas ao tentar criar uma variável

JLabel nome ou idade no escopo do método actionPerformed ocorrerá um erro, pois já existem

atributos com esses identificadores que valem em toda a classe IncluirCadastro e todo o seu escopo, pois a classe também tem chaves.

É possível fazer um teste utilizando o JOptionPane dos exemplos anteriores como mostra o código a seguir.

@Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

(21)

JOptionPane.showMessageDialog(null, "Você digitou: "+nome+" e "+idade, "Sucesso!", JOptionPane.PLAIN_MESSAGE);

}}

As variáveis do método actionPerformed são concatenadas à mensagem que é passada como parâmetro (ou argumento) do método showMessageDialog de JOptionPane. Assim, depois de digitar algo nos campos e clicar em cadastrar, aparecerá uma caixa de mensagem na tela principal mostrando o que foi digitado. Veja o resultado na figura 9.

Figura 9: capturando o conteúdo dos campos.

Concluído o teste e confirmado que o conteúdo dos campos está sendo capturado corretamente, é possível passar ao último passo e armazenar no ArrayList, o que o usuário digitou. Para isso, é criado um novo atributo chamado dadosPessoais que é um objeto da classe

ArrayList. É nele que serão armazenados os dados digitados pelo usuário, como mostra o código,

que considera, também, apenas o escopo do método actionPerformed.

@Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

String nome = tnome.getText();

String idade = tidade.getText();

if(dadosPessoais == null){

dadosPessoais = new ArrayList();

}

dadosPessoais.add(nome);

dadosPessoais.add(idade);

JOptionPane.showMessageDialog(null, "Dados

armazenados", "Sucesso!", JOptionPane.PLAIN_MESSAGE); }}

No código, observe as partes em vermelho. O primeiro if indica que, se o ArrayList

dadosPessoais for igual a null, ninguém armazenou nenhum dado ainda! Portanto, se a execução

atingir esse ponto do código, é hora de instanciar o ArrayList dadosPessoais para poder armazenar objetos nele. Se a execução voltar a essa parte do código, novamente, para colocar

(22)

mais dados no mesmo ArryList, o escopo do if não será executado, pois dadosPessoais não será mais null. Em seguida, os dados são armazenados em dadosPessoais pelos método add(). Por fim, a mensagem no JOptionPane foi modificada para melhor entendimento do usuário.

No entando, imagine a situação em que se deseja armazenar dois cadastros: Ingrid de 30 anos e Alexandre de 36 anos. Seriam ocupadas, em dadosPessoais, as posições 0, 1, 2 e 3. Como saber que 30 anos correspondem à Ingrid e não a Alexandre, ou vice-versa? E se houvessem mais dados? Como relacioná-los, corretamente, a cada cadastro?

Uma solução “elegante” em programação é a utilização de javabeans (ou beans, apenas). No início desse capítulo, foi criado o bean Pessoa, que está no pacote javaBeans. Objetos dessa classe contêm dois atributos correspondentes com os campos que o usuário irá digitar: nome e idade, onde o primeiro é um objeto String e o segundo, um tipo primitivo int. A ordem, então, seria capturar os valores digitados pelo usuário, instanciar um objeto do bean Pessoa, “setar” os atributos correspondentes com aqueles valores e, por fim, adicionar ao objeto ArrayList. Veja o código.

@Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

String nome = tnome.getText();

String idade = tidade.getText();

if(dadosPessoais == null){

dadosPessoais = new ArrayList();

}

Pessoa pessoa = new Pessoa();

pessoa.setNome(nome);

int age = Integer.parseInt(idade);

pessoa.setIdade(age);

dadosPessoais.add(pessoa);

JOptionPane.showMessageDialog(null, "Dados

armazenados", "Sucesso!", JOptionPane.PLAIN_MESSAGE);

} }

No trecho de código em vermelho estão implementados os passos descritos anteriormente, com a utilização do método estático da classe Integer, parseInt(), que recebe como parâmetro um objeto String, a qual tentará converter para um número inteiro. O mesmo método existe para as classes Short, Float, Long e Double e são as chamadas classes wrappers. Qualquer dúvida, veja na apostila de 2º módulo, sub-capítulo 9.10, página 39. Também há material disponível em livros e sites da internet.

(23)

campos que o usuário usará para digitar os valores sempre retornarão objetos do tipo String, mas no bean Pessoa, o método setIdade que é utilizado para definir um valor para o atributo idade tem, como parâmetro, um inteiro. Daí a necessidade de se converter o String digitado em número.

Depois do valor digitado no campo idade ter sido convertido para um inteiro, ele é passado como parâmetro para o método setIdade, assim como nome é passado para o método

setNome. Por fim, o objeto instanciado da classe Pessoa, chamado pessoa, é armazenado no ArrayList. Dessa forma, é possível armazenar, de forma ordeira, tantos registros quanto forem

necessários, com cada objeto com seus dados correspondentes. Manter os dados corretamente em uma estrutura de armazenamento, seja ela qual for, é chamado de consistência de dados, um termo muito utilizado em banco de dados.

Mas há um problema de implementação. O ArrayList dadosPessoais existe apenas na classe IncluirCadastro. E se forem acrescentadas mais classes como pesquisarCadastro,

alterarCadastro e excluirCadastro? Como essas classes poderão acessar o mesmo ArrayList dadosPessoais? Existem muitas maneiras de resolver esse problema, e a apresentada para esse

exemplo é utilizando a passagem de parâmetros por referência pelos contrutores dessas classes. Assim, o ArrayList dadosPessoais será instanciado, inicialmente, não em incluirCadastro, mas na classe principal do exemplo, chamada Cadastro. Quando a classe Cadastro instanciar um objeto da classe incluirCadastro ou qualquer outra, o objeto será enviado pelo seu construtor. Veja exemplo da classe Cadastro.

public class Cadastro extends JFrame {

private Container telaPrincipal;

private IncluirCadastro incluirCadastro;

private ArrayList dadosPessoais;

public Cadastro(){

telaPrincipal = this.getContentPane();

telaPrincipal.setBackground(Color.WHITE);

dadosPessoais = new ArrayList();

incluirCadastro = new IncluirCadastro(dadosPessoais);

telaPrincipal.add(incluirCadastro); setLayout(null); setSize(300, 300); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setExtendedState(JFrame.MAXIMIZED_BOTH); setVisible(true); }

public static void main(String[] args){

Cadastro teste = new Cadastro();

(24)

Verifique no código acima, na parte em vermelho, que o construtor da classe

incluirCadastro está recebendo como parâmetro um objeto da classe ArrayList, também

chamado de dadosPessoais (mas chame do que quiser, não importa!). Lembrando que a variável (ou referência) para o objeto ArrayList é um endereço na memória, o construtor da classe

incluirCadastro precisa ser preparado para receber esse parâmetro, o que não ocorreu nos

exemplos até aqui. Assim, o código modificado do contrutor dessa classe é apresentado a seguir.

public IncluirCadastro(ArrayList dadosPessoais){

this.dadosPessoais = dadosPessoais;

this.nome = new JLabel("Nome");

this.idade = new JLabel("idade");

this.tnome = new JTextField();

this.tidade = new JTextField();

this.nome.setBounds(10, 10, 50, 20);

this.idade.setBounds(10, 50, 50, 20);

this.cadastrar = new JButton("cadastrar");

this.tnome.setBounds(50, 10, 200, 20); this.tidade.setBounds(50, 50, 50, 20); cadastrar.setBounds(100, 100, 100, 20); cadastrar.addActionListener(this); this.add(nome); this.add(idade); this.add(tnome); this.add(tidade); this.add(cadastrar); this.setBounds(10, 10, 300, 200); this.setBackground(Color.RED); this.setLayout(null); this.setVisible(true); }

A única modificação que foi feita no construtor da classe incluirCadastro é o que está em vermelho, onde a primeira ocorrência é a criação de um parâmetro para receber um objeto da classe ArrayList. Assim, sempre que um objeto de incluirCadastro for instanciado, será necessário enviar, pelo seu construtor, um objeto da classe ArrayList. Portanto, as classes

Cadastro e incluirCadastro “apontam” para o mesmo objeto na memória, pois ambos tem a

mesma referência. Assim, as modificações que um fizer nessa posição de memória será percebida pelos dois.

O método do listener na classe incluirCadastro também será modificado, mas nesse caso, ficará mais simples, pois não será necessário o trecho de código que apresentava um if para testar se o objeto ArrayList ainda não tinha sido instanciado. Como é a classe principal (Cadastro) que instancia esse objeto, está garantido que o ArrayList já existe na memória. Veja o código do método do listener, actionPerformed.

(25)

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(cadastrar)){

String nome = tnome.getText();

String idade = tidade.getText();

Pessoa pessoa = new Pessoa();

pessoa.setNome(nome);

int age = Integer.parseInt(idade);

pessoa.setIdade(age);

this.dadosPessoais.add(pessoa);

JOptionPane.showMessageDialog(null, "Dados

armazenados", "Sucesso!", JOptionPane.PLAIN_MESSAGE);

}}

Para dar continuidade ao exemplo, observe a figura 10 e tente implementar o código correspondente.

Figura 10: tela de pesquisa cadastro por nome.

3.3 Pesquisa em um ArrayList

Depois que a tela da figura 10 estiver implementada, será apresentado apenas, o desenvolvimento do método actionPerformed da classe PesquisaCadastro. Lembrando que o

ArrayList dadosPessoais armazena objetos da classe Pessoa, como procurar por nome um entre

tantos objetos que podem estar contidos no ArrayList? As soluções já foram apresentadas no sub-capítulo 2.1.1, portanto, o aluno pode escolher a que mais se sente confortável para implementar essa pesquisa. Para esse exemplo, será usado um objeto da classe Iterator. Veja o código implementado no escopo do método actionPerformed.

@Override

public void actionPerformed(ActionEvent e) { if(e.getSource().equals(pesquisar)){

Iterator iterar = this.dadosPessoais.iterator(); while(iterar.hasNext()){

(26)

if(pessoa.getNome().equalsIgnoreCase(this.tnome.getText())){

break;

}

}

}}

No código acima, o primeiro if possui a mesma lógica que na classe IncluirCadastro, que é testar se o botão pesquisar foi pressionado. Se houver apenas um componente como o botão pesquisar, o if não é necessário, pois o único componente que pode gerar um evento é o próprio botão pesquisar, mas para manter o padrão de desenvolvimento e garantir a manutenção do aplicativo que, futuramente, pode adicionar mais componentes, utiliza-se o if como antes.

No escopo do if é obtido o objeto iterator do ArrayList dadosPessoais. Esse Iterator, como visto no sub-capítulo 2.1.1, tem a capacidade de iterar (ir de um em um) no ArrayList. É considerada uma das formas mais eficientes e rápidas de percorrer os itens de uma coleção, portanto, prefira usá-lo sempre.

No laço de repetição while, é verificado se há elementos no objeto Iterator, nesse exemplo chamado de iterar. Sempre que houver um próximo item, o método hasNext() retornará o booleano true, caso contrário, retornará false e o laço de repetição para. Considerando que há um elemento para uma próxima iteração, a execução do programa entra no escopo do laço while e outro método do objeto Iterator, next(), retorna o próximo objeto armazendo no ArrayList

dadosPesssoais, que é um objeto da classe Pessoa.

No segundo if é, efetivamente, testado o nome contido no objeto Pessoa que foi obtido da iteração, e é efetuado um teste com o nome digitado pelo usuário com o método

equalsIgnoreCase() que, diferente do equals(), testa se o que foi digitado é igual ao que está

armazenado no objeto Pessoa, ignorando minúsculas e maiúsculas. Se forem iguais, o método

equalsIgnoreCase() retorna o booleano true e entra no escopo do if, caso contrário (false), não.

No escopo do if está o comando break, que finaliza as iterações, pois o objeto cujo nome é pesquisado foi encontrado.

Para testar se o botão pesquisar está gerando o evento corretamente, é possível colocar, antes do comando break, um JOptionPane. Execute o aplicativo e armazene o seu nome e idade. Depois, coloque seu nome no campo de pesquisa e clique no botão pesquisar e veja se a janela

showMessagDialog de JOptionPane aparece. Se positivo, pode continuar com a implementação,

(27)

Figura 11: teste do botão pesquisar.

Confirmado que o botão pesquisar está gerando o evento corretamente, a ideia do aplicativo é, depois de encontrar os dados, colocá-los na tela, nesse caso, nome e idade. Como os dados são apenas pesquisados, não será permitida, nesse JPanel, a alteração dos dados encontrados. Portanto, o exemplo utiliza simples JLabels para apresentar os dados encontrados. Veja o código de exemplo.

public class PesquisarCadastro extends JPanel implements ActionListener {

private JLabel nome;

private JLabel dNome;

private JLabel dIdade;

private JLabel mensagem;

private JTextField tnome;

private JButton pesquisar;

private ArrayList dadosPessoais;

public PesquisarCadastro(ArrayList dadosPessoais){

this.dadosPessoais = dadosPessoais;

this.nome = new JLabel("Nome");

this.tnome = new JTextField();

this.pesquisar = new JButton("pesquisar");

this.dNome = new JLabel();

this.dIdade = new JLabel();

this.mensagem = new JLabel("Nenhum item pesquisado.");

this.nome.setBounds(10, 10, 50, 20); this.tnome.setBounds(50, 10, 200, 20); this.pesquisar.setBounds(100, 50, 100, 20); this.pesquisar.addActionListener(this); this.dNome.setBounds(100, 150, 100, 20); this.dIdade.setBounds(100, 180, 100, 20); this.mensagem.setBounds(90, 90, 200, 20);

(28)

this.add(nome); this.add(tnome); this.add(pesquisar); this.add(mensagem); this.add(dNome); this.add(dIdade); this.setBounds(10, 230, 300, 450); this.setBackground(Color.YELLOW); this.setLayout(null); this.setVisible(true); } @Override

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(pesquisar)){

boolean controle;

Iterator iterar = this.dadosPessoais.iterator();

while(iterar.hasNext()){

Pessoa pessoa = (Pessoa) iterar.next();

if(pessoa.getNome().equalsIgnoreCase(this.tnome.getText())){

this.mensagem.setText("Os dados encontrados são:");

this.dNome.setText("Nome: "+pessoa.getNome()); this.dIdade.setText("Idade: "+Integer.toString(pessoa.getIdade())); this.repaint(); break; } } } }}

Das quatro operações básicas que um aplicativo deve ser capaz de efetuar, duas já foram implementadas: incluir e pesquisar. A terceira seria excluir um cadastro. Para isso, é construido outro painel chamado, oportunamente, de ExcluirCadastro. Para que seja possível excluir um cadastro é necessário, antes, encontrá-lo. Assim, com uma pequena diferença, o painel

ExcluirCadastro é igual ao PesquisarCadastro. A diferença fica com por conta dos seguintes

métodos no costrutor da classe ExcluirCadastro:

this.setBounds(330, 430, 670, 250); this.setBackground(Color.MAGENTA);

O método setBounds() difere da classe PesquisarCadastro porque é necessário posicioná-lo em uma parte diferente, do contrário, não seria possível vê-posicioná-lo na tela. Para auxiliar ainda mais o posicionamento do novo painel na tela principal, a cor escolhida foi magenta, como é

(29)

como na figura 12.

Figura 12: painel excluircadastro.

Para verificar se o método actionPerformed() da nova classe ExcluirCadastro está funcionando, cadastre seu nome e depois faça uma pesquisa. O método deve encontrar o nome cadastrado, exatamente como o PesquisaCadastro fazia, já que é uma cópia.

No entanto, a classe ExcluirCadastro não tem como função principal a pesquisa, mas excluir um cadastro da ArrayList dadosPessoais. Assim, o método do listener copiado da classe

PesquisarCadastro precisa ter acrescentado a parte que exclui o cadastro encontrado de

dadosPessoais.

public void actionPerformed(ActionEvent e) {

if(e.getSource().equals(pesquisar)){

Iterator iterar = this.dadosPessoais.iterator();

while(iterar.hasNext()){

Pessoa pessoa = (Pessoa) iterar.next();

if(pessoa.getNome().equalsIgnoreCase(this.tnome.getText())){

this.mensagem.setText("Os dados encontrados são:");

this.dNome.setText("Nome: "+pessoa.getNome());

this.dIdade.setText("Idade: "+Integer.toString(pessoa.getIdade()));

this.repaint();

int opcao = JOptionPane.showConfirmDialog(null, "Tem certeza que deseja

excluir o cadastro de "+pessoa.getNome()+"?", "EXCLUIR", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

if(opcao == JOptionPane.YES_OPTION){ this.dadosPessoais.remove(pessoa);

JOptionPane.showMessageDialog(null, "Dados excluídos com sucesso!", "EXCLUIR", JOptionPane.PLAIN_MESSAGE);

}

break; }}}}

(30)

O código anterior apresenta, em vermelho, a implementação acrescentada ao método

actionPerformed() da classe ExcluirCadastro que, efetivamente, após encontrar o cadastro que

se deseja excluir, o exclui. Um novo método estático da classe JOptionPane é apresentado no código, o showConfirmDialog, que possui um parâmetro a mais do estudado até aqui, o

showMessageDialog(). É o quarto parâmetro chamado JOptionPane.YES_NO_OPTION que

coloca na janela de diálogo dois botões básicos, indicados em inglês: “yes” e “no”. O “yes” é representado por um número inteiro assim como o “no”, mas aos desenvolvedores ambos são apresentados como constantes chamadas, respectivamente, de JOptionPane.YES_OPTION e

JOptionPane.NO_OPTION. A primeira constante é utilizada no if para verificar se o usuário

clicou no botão “yes”, excluindo do ArrayList dadosPessoais o registro, como apresentado no escopo do if. O método de dadosPessoais que permite remover um objeto é chamado de

remove(), que aceita como parâmetro o objeto que se deseja excluir. Por fim, outra JOptionPane

é utilizada para avisar o usuário que o regitro está excluído. Para testar se está funcionando, efetue uma pesquisa e, como resultado, o objeto excluído não pode mais ser encontrado.

Por fim, a última operação básica é a alteração de um cadastro, a qual também é necessária uma pesquisa. Essa classe será chamada de AlteraCadastro. Diferente de

ExcluirCadastro que é igual apenas a PesquisarCadastro, AlterarCadastro é uma junção de IncluiCadastro e PesquisaCadastro, pois deverá disponibilizar ao usuário campos com os dados

pesquisados para que possam ser editados. Veja a figura 13.

Figura 14: painel AlteraCadastro.

Além dos campos para alterações, será disponibilizado um botão para efetuar a edição no

ArrayList dadosPessoais. O código que corresponde ao painel para edição, apresentado na figura

em verde, segue a seguir.

public class AlteraCadastro extends JPanel implements ActionListener { private JLabel nome;

private JTextField tnome; private JLabel eNome; private JLabel eIdade; private JTextField etNome;

(31)

private JButton editar;

private JButton pesquisar; private JLabel mensagem; private Pessoa pessoa;

private ArrayList dadosPessoais;

public AlteraCadastro(ArrayList dadosPessoais) {

this.dadosPessoais = dadosPessoais;

this.nome = new JLabel("Nome");

this.tnome = new JTextField();

this.pesquisar = new JButton("pesquisar"); this.editar = new JButton("Editar");

this.eNome = new JLabel("Nome"); this.eIdade = new JLabel("Idade");

this.mensagem = new JLabel("Nenhum item pesquisado.");

this.etNome = new JTextField();

this.etIdade = new JTextField();

this.nome.setBounds(10, 10, 50, 20); this.tnome.setBounds(50, 10, 200, 20); this.pesquisar.setBounds(100, 50, 100, 20); this.pesquisar.addActionListener(this); this.editar.setBounds(150, 220, 80, 20); this.editar.addActionListener(this); this.eNome.setBounds(100, 150, 100, 20); this.eIdade.setBounds(100, 180, 100, 20); this.etNome.setBounds(150, 150, 200, 20); this.etIdade.setBounds(150, 180, 50, 20); this.mensagem.setBounds(90, 90, 200, 20); this.add(nome); this.add(tnome); this.add(pesquisar); this.add(editar); this.add(mensagem); this.add(eNome); this.add(eIdade); this.add(etNome); this.add(etIdade); this.setBounds(330, 160, 670, 250); this.setBackground(Color.GREEN);

(32)

this.setLayout(null);

this.setVisible(true);

}

@Override

public void actionPerformed(ActionEvent e) { if (e.getSource().equals(pesquisar)) {

boolean controle;

Iterator iterar = this.dadosPessoais.iterator();

while (iterar.hasNext()) {

this.pessoa = (Pessoa) iterar.next();

if (this.pessoa.getNome().equalsIgnoreCase(this.tnome.getText())) {

this.mensagem.setText("Os dados encontrados são:");

this.etNome.setText(this.pessoa.getNome()); this.etIdade.setText(Integer.toString(this.pessoa.getIdade())); this.repaint(); break; } } } else if (e.getSource().equals(editar)) {

int opcao = JOptionPane.showConfirmDialog(null, "Tem certeza que deseja editar o cadastro de " + pessoa.getNome() + "?", "EDITAR", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

if (opcao == JOptionPane.YES_OPTION) { Pessoa pessoaEditar = new Pessoa();

pessoaEditar.setNome(this.etNome.getText());

pessoaEditar.setIdade(Integer.parseInt(this.etIdade.getText())); dadosPessoais.remove(this.pessoa);

this.pessoa = null;

dadosPessoais.add(pessoaEditar);

JOptionPane.showMessageDialog(null, "Dados editados com sucesso!", "EDITAR", JOptionPane.PLAIN_MESSAGE);

}

}}}

O código é parecido com ExcluirCadastro, mas algumas modificações foram necessárias, como o objeto da classe Pessoa, chamado pessoa, que passou de variável local no método

actionPerformed para um atributo de classe, como é possível ver no início do código. Isso

porque, depois de ser efetuada a pesquisa, é necessário manter o objeto encontrado para editá-lo. Se pessoa continuasse como uma variável local no primeiro if do método actionPerformed, ela existiria apenas ali, no escopo daquele if, não sendo visível para outra parte do código. Com essa modificação, o segundo if, que corresponde a ação do botão editar, pode “enxergar” o objeto encontrado da pesquisa e editá-lo.

(33)

JLabel que mostravam o nome e a idade do objeto encontrado, passaram a objetos da classe JTextField para que, assim, o usuário possa editar esses valores. Mas os objetos da classe JLabel

não foram retirados do código, eles foram reutilizados para nomear esses campos na tela, sendo chamados, agora, de eNome e eIdade. O ‘e’ corresponde a “editar”. Os objetos de JTextField são chamados de etNome e etIdade. O “et” corresponde a “editar texto”. Os nomes, aqui apresentados, são apenas opções encontradas pelo professor para ilustrar o exemplo, ficando o aluno a vontade para escolher os nomes que quiser.

Estude o código do construtor da classe AlterarCadastro e verifique que os objetos citados foram inseridos da mesma maneira que nos demais exemplos, com setBounds(), etc.

Um ponto importante é o botão editar, pois é ele que irá, efetivamente, após uma pesquisa, editar os valores que o usuário escreveu nos campos. Assim, a classe AlterarCadastro possui, agora, dois botões, pois já apresentava o botão pesquisar, cujo evento corresponde ao primeiro if do método actionPerformed. No método referido existe outra verificação com o else

if(), que então testa se o botão editar foi pressionado. Se afirmativo, a operação de edição

ocorrerá.

No if interno do else if() ocorre a criação de um objeto chamado pessoaEditar. É esse objeto que receberá os dados modificados pelo usuário, depois que digitar nos campos e pressionar o botão editar. É esse o objeto que deverá ser armazenado no ArrayList

dadosPessoais. O objeto anterior que foi pesquisado, chamado pessoa (agora um atributo, como

explicado antes), deverá ser removido do ArrayList, caso contrário, haverá dois registros para o mesmo cadastro: um não modificado e outro modificado. Assim, antes de adicionar o objeto

pessoaEditar, é preciso remover o objeto pessoa de dadosPessoais. Estude o código e encontre

onde ocorre esse procedimento. 3.4 Opções de layout

No exemplo dessa apostila os JPanels tiveram os fundos coloridos para facilitar o seu posicionamento na janela principal, mas é possível não usar um layout tão “poluído”, passando o fundo de cada JPanel para, por exemplo, branco. Também é possível usar uma borda nomeada para cada um deles e os botões podem ser representados por imagens. Nesse caso, é sugerido que seja criado, no projeto, um diretório (não pacote!) e nele sejam armazenadas todas as imagens que serão usadas pelo aplicativo. A estrutura no projeto ficaria como mostra a figura 15.

Figura 15: estrutura do projeto com um diretório de imagens.

(34)

Figura 16: layout de IncluirCadastro modificado.

Estude o código da classe IncluirCadastro onde essas modificações foram feitas, e faça as mesmas modificações para os outros painéis, obtendo o layout da figura 17.

public class IncluirCadastro extends JPanel implements ActionListener {

private JLabel nome;

private JLabel idade;

private JTextField tnome;

private JTextField tidade;

private JButton cadastrar;

private ArrayList dadosPessoais;

public IncluirCadastro(ArrayList dadosPessoais) {

this.dadosPessoais = dadosPessoais;

Border bordaPesquisar =

BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Cadastrar..."); this.setBorder(bordaPesquisar);

this.nome = new JLabel("Nome"); this.idade = new JLabel("idade");

this.tnome = new JTextField();

this.tidade = new JTextField(); this.nome.setBounds(10, 30, 50, 20); this.idade.setBounds(10, 70, 50, 20);

ImageIcon botaoImg = new ImageIcon("src/imagens/botao.png"); this.cadastrar = new JButton(botaoImg);

this.cadastrar.setBorderPainted(false); this.cadastrar.setBackground(Color.WHITE);

this.tnome.setBounds(50, 30, 200, 20); this.tidade.setBounds(50, 70, 50, 20); cadastrar.setBounds(100, 100, 50, 40);

(35)

this.add(nome); this.add(idade); this.add(tnome); this.add(tidade); this.add(cadastrar); this.setBounds(10, 10, 300, 200); this.setBackground(Color.WHITE); this.setLayout(null); this.setVisible(true); } @Override

public void actionPerformed(ActionEvent e) { if (e.getSource().equals(cadastrar)) {

String nome = tnome.getText();

String idade = tidade.getText();

Pessoa pessoa = new Pessoa();

pessoa.setNome(nome);

int age = Integer.parseInt(idade);

pessoa.setIdade(age);

this.dadosPessoais.add(pessoa);

JOptionPane.showMessageDialog(null, "Dados armazenados", "Sucesso!", JOptionPane.PLAIN_MESSAGE);

} }}

Referências

Documentos relacionados

Desde logo, a nossa compreensão e interpretação da importância funcional e ritual das lamentações públicas das carpideiras e dos carpideiros egípcios é sublinhada pelo

duplamente encadeada com este valor caso o mesmo ainda não exista na lista, em ordem CRESCENTE, ou seja, sempre entre um nó contendo um valor menor e outro contendo um valor

 São TADs representados através de listas sequenciais.. (fixas) ou encadeadas (dinâmicas), em que a seguinte regra deve

função recursiva, mais recursos de memória são necessários para executar o programa, o que pode torná-lo lento ou. computacionalmente

 Caminho simples que contém todas as arestas do grafo (e,. consequentemente, todos os

Neste tipo de situações, os valores da propriedade cuisine da classe Restaurant deixam de ser apenas “valores” sem semântica a apresentar (possivelmente) numa caixa

Em relação aos compostos obtidos com o ácido p-nitrobenzóico, apenas um se apresentou como dímero, o térbio em DMF, apresentando de forma atípica, quatro ligações do íon

Therefore, the aim of this study was to identify the species of Colletotrichum associated with chayote anthracnose in different production poles of Brazil, based on DNA sequence