POO – AULA 08 Objetivos da aula Reforçar conceitos sobre arrays unidimensionais e multidimensionais Passar arrays como argumentos de métodos Entender o conceito de coleções e aprender a usar a classe Arrays Aprender a criar pacotes de classes Introduzir o conceito de interfaces gráficas (GUI) Apresentar componentes Swing Recordando... Em aulas passadas, vimos como declarar, instanciar e iniciar arrays de uma ou mais dimensões, de diferentes formas. Recorde algumas delas: Formas alternativas de fazer int c[ ]=new int int c[ ]; [10]; c = new int[10]; float [ ] a, b; float a [ ]; float b [ ]; int k[ ] = {2, 4, k[0]=2; k[1]=4; 6, 8, 10}; k[2]=6; k[3]=8; k[4]=10; int m [ ] [ ] = int m [ ] [ ]; {{1,3,5}{7,9,0}}; m=new int [2][3]; m[0]={1,3,5}; m[1]={7,9,0}; int n [ ] [ ]; n = new int [2] [ ]; n[0]=new int[3]; n[1]=new int[5]; O que está sendo feito Instanciar um array Instanciar dois arrays Instanciar e iniciar um array com valores Instanciar e iniciar com valores um array bidimensional (matriz) Instanciar um array bidimensional c/ linhas de tamanhos diferentes Passando arrays como argumentos de métodos Para passar um array como argumento para um método, especifique o nome do array sem colchetes. Por ex., para uma array declarado como: int valor[] = new int[10]; A chamada de um método trataValor que recebesse esse array, seria: objeto.trataValores(valor); 1 Já a declaração do método com o argumento formal, teria a forma: public void trataValores(int a[]){ // códigos if (a[0] == 10) { ... } else { ... } } Caso desejássemos passar apenas um elemento do array, faríamos: trataValor(valor[4]); //passa o quinto elemento Neste caso, o método deveria ser declarado como: void trataValor(int b){ if (b == 10) { ... } else { ... } } Em muitas linguagens de programação, existem duas maneiras de passar argumentos em chamadas de métodos: passagem por valor e passagem por referência. Ao contrário dessas linguagens, O Java não permite escolher passar por valor ou por referência – todos os argumentos são passados por valor. Uma chamada de método pode passar dois tipos de valores para um método: as cópias de valores primitivos, int por exemplo, e as cópias de referências para objetos , inclusive referências a arrays. Objetos não podem ser passados para os métodos. Quando um método modifica um parâmetro do tipo primitivo, as alterações no parâmetro não têm nenhum efeito no valor original do argumento no método chamador. Isto também é verdadeiro para os parâmetros de tipo por referência. Se o método chamado modificar um parâmetro de tipo por referência atribuindo a ele a referência a outro objeto, o parâmetro referenciará o novo objeto, mas a referência armazenada na variável do chamador ainda referencia o objeto original. Coleções 2 Podemos armazenar vários objetos ou valores de tipos primitivos em um array e manipular este array como sendo uma única entidade. Um array pode ser encapsulado em uma classe, possibilitando a criação de métodos específicos de manipulação do array encapsulado. Apesar da flexibilidade que pode ser obtida com o encapsulamento de um array em uma classe, algumas necessidades úteis não podem ser implementadas de forma trivial ou eficiente. Como, por exemplo: . o tamanho do array não pode ser modificado depois do array criado; . um array somente pode conter elementos de um único tipo, exceto se considerarmos os mecanismos de herança e polimorfismo; . algumas operações não podem ser realizadas de maneira simples em array como inserir e excluir um determinado elemento. A linguagem Java possui classes e interfaces que poupam trabalho e oferecem mecanismos para agrupar e processar objetos em conjuntos, denominados genericamente como coleções. Muitas dessas classes implementam estruturas de dados complexas, mas cujo uso é transparente para o programador. Todas essas classes fazem parte do pacote java.util. Resumindo, uma coleção é uma estrutura de dados, na realidade um objeto, que pode armazenar referências a outros objetos. Normalmente as coleções contêm referências a objetos que são todos do mesmo tipo. As interfaces de estrutura das coleções declaram as operações a serem realizadas nessas coleções: Collection, Set, List, Map, Queue, .... Classe Arrays A classe Arrays fornece métodos static de alto nível para manipular arrays, como sort para ordenar o array, binarySearch para pesquisar o array ordenado, equals para comparar arrays e fill para colocar valores no array. O aplicativo a seguir mostra a utilização de alguns desses métodos: import java.util.Arrays; // Classe Arrays import java.util.Scanner; // Classe Scanner public class UsandoArrays { private int intArray[] = { 1, 2, 3, 4, 5, 6 }; private double doubleArray[] = {8.4,9.3,0.2,7.9,3.4}; private int intArrayCheio[], intArrayCopia[]; public UsandoArrays(){ //construtor intArrayCheio = new int[10]; intArrayCopia = new int[intArray.length]; Arrays.fill (intArrayCheio, 7);// preenche com 7s 3 Arrays.sort (doubleArray); // ordena doubleArray System.arraycopy (intArray, 0, intArrayCopia, 0, intArray.length ); } public void mostraArrays() { System.out.print( "doubleArray ordenado: " ); for (double doubleValue : doubleArray) System.out.printf ("%.1f; ", doubleValue); System.out.print( "\nintArray: " ); for ( int intValue : intArray ) System.out.printf( "%d ", intValue ); System.out.print( "\nintArrayCheio: "); for ( int intValue : intArrayCheio ) System.out.printf( "%d ", intValue ); System.out.print( "\nintArrayCopia: " ); for ( int intValue : intArrayCopia ) System.out.printf( "%d ", intValue ); System.out.println( "\n" ); } public int pesquisaInt( int value ){ return Arrays.binarySearch(intArray, value ); } public void mostraIgualdade(){ boolean b = Arrays.equals(intArray, intArrayCopia); System.out.printf("intArray %s intArrayCopia\n", ( b ? "==" : "!=" )); b = Arrays.equals( intArray, intArrayCheio ); System.out.printf( "intArray %s intArrayCheio\n", ( b ? "==" : "!=" ) ); } public static void main( String args[] ) { UsandoArrays meuArray = new UsandoArrays(); meuArray.mostraArrays(); meuArray.mostraIgualdade(); Scanner entrada = new Scanner( System.in ); System.out.printf("\nEntre com valor a procurar: "); int val = entrada.nextInt(); int location = meuArray.pesquisaInt(val); String lixo = entrada.nextLine() ; if ( location >= 0 ) System.out.printf( "Valor %d encontrado na posicao %d do 4 intArray\n", val, location ); else System.out.printf( "Valor %d nao foi encontrado em intArray\n",val); } } Criando Pacotes Aplicações e projetos complexos necessitam de organização das classes que utilizam, de forma que fique claro a qual aplicação ou projeto as classes pertencem. Esta necessidade de organização é mais aparente quando se deseja compartilhar classes ou instalá-las em outro computador. Java provê um mecanismo de agrupamento de classes em pacotes – packages – com o qual podemos criar grupos de classes relacionadas. Para a criação desses pacotes, basta uma declaração de pertinência ao pacote em cada classe e a organização das classes em um diretório. Para criar uma pacote basta, portanto, criar um diretório e colocar lá os códigos-fonte das classes que desejamos que façam parte desse pacote. Como exemplo, vamos considerar as classes Data, Hora e, ainda, a classe DataHora que encapsula uma data e uma hora. Para aglutinar essas classes em um pacote, primeiramente devemos criar um diretório DataHora e, a seguir, armazenar as classes dentro desse diretório. Cada classe do pacote deve ter, no seu início, a palavra-chave package seguida do nome do diretório (pacote) ao qual a classe pertence. Veja para a classe Data: package DataHora; // indica o pacote da classe public class Data { byte dia; // acessibilidade default é package byte mes; // acessibilidade default é package short ano; // acessibilidade default é package public Data(byte d, byte m, short a){ dia = d; mes = m; ano = a; } public String toString(){ return dia + "/" + mes + "/" + ano; } } A seguir listamos a classe Hora que encapsula os dados de uma hora: package DataHora; // indica o pacote da classe public class Hora { byte hora; // acessibilidade default é package byte minuto; // acessibilidade default é package byte segundo; // acessibilidade default é package 5 public Hora(byte h, byte m, byte s){ hora = h; minuto = m; segundo = s; } public String toString(){ return hora + ":" + minuto + ":" + segundo; } } A terceira classe do pacote DataHora é a classe de nome DataHora: package DataHora; public class DataHora { private Data novaData; private Hora novaHora; public DataHora(byte d, byte mes, short a, byte h, byte min, byte s){ novaData = new Data(d, mes, a); novaHora = new Hora(h, min, s); } public String toString(){ String resulta = novaHora.hora + ":" + novaHora.minuto + ":" + novaHora.segundo; resulta += " de " + novaData.dia + " de "; switch (novaData.mes){ case 1: resulta += "Janeiro"; break; case 2: resulta += "Fevereiro"; break; case 3: resulta += "Março"; break; case 4: resulta += "Abril"; break; case 5: resulta += "Maio"; break; case 6: resulta += "Junho"; break; case 7: resulta += "Julho"; break; case 8: resulta += "Agosto"; break; case 9: resulta += "Setembro"; break; case 10: resulta += "Outubro"; break; case 11: resulta += "Novembro"; break; case 12: resulta += "Dezembro"; break; } resulta += " de " + novaData.ano; return resulta; } } Note que a classe DataHora acima, faz referência a atributos das classes 6 Data e Hora (hora, dia,etc.), que possuem acessibilidade default (package). As classes Data, Hora e DataHora pertencem ao pacote DataHora. A classe de teste DemoDataHora utiliza as classes Data, Hora e DataHora, mas não faz parte do pacote DataHora (coloque-a em outro diretório). Veja: import DataHora.Hora; import DataHora.Data; import DataHora.DataHora; public class DemoDataHora { public static void main (String args[]){ Hora meiodia=new Hora ((byte)12,(byte)00,(byte)00); Data hoje=new Data ((byte)24,(byte)10,(short)2006); DataHora agora=new DataHora ((byte)24,(byte)10, (short)2006,(byte)19,(byte)50,(byte)00); System.out.println (meiodia); System.out.println (hoje); System.out.println (agora); } } Usando interfaces gráficas Até agora nossas aplicações utilizaram uma janela de texto (console) para entrada e saída de dados. A maioria dos aplicativos que utilizamos no diaa-dia, entretanto, utiliza janelas com diversos recursos gráficos para interagir com o usuário, como campos de edição, botões e outros objetos gráficos que compõem o que se chama uma Interface Gráfica (GUI). Uma GUI é construída a partir de componentes, também chamados de controles ou widgets (window gadgets) em outras linguagens. Um componente GUI é um objeto com o qual o usuário interage via mouse, teclado ou outro formulário de entrada. Exemplos de GUI são as janelas de aplicativos como o Internet Explorer, Word, etc,... Entrada e saída com JOptionPane A classe JOptionPane do Java (pacote javax.swing) fornece caixas de diálogos pré-empacotadas tanto para entrada como para saída. Esses diálogos são exibidos invocando métodos JOptionPane static. A classe a seguir é um aplicativo de adição que utiliza dois diálogos de entrada para obter inteiros do usuário e um diálogo de mensagem para exibir a soma desses inteiros. 7 import javax.swing.JOptionPane; public class Adicao{ // Adição de inteiros public static void main( String args[] ){ String strNumero1 = JOptionPane.showInputDialog("Entre com um número" ); String strNumero2 = JOptionPane.showInputDialog("Entre outro número"); int numero1 = Integer.parseInt(strNumero1); int numero2 = Integer.parseInt(strNumero2); int soma = numero1 + numero2; //soma os números JOptionPane.showMessageDialog(null, "A soma é : " + soma, "Soma de dois inteiros", JOptionPane.PLAIN_MESSAGE ); } // fim do main } // fim da classe O método showInputDialog da classe JOptionPane exibe um diálogo de entrada apresentando o argumento String para o usuário. Esse método devolve o String digitado na caixa de texto para o programa. Ao contrário da classe Scanner que pode “captar” valores de vários tipos através de seus métodos, o método showInputDialog só permite “captar” informações do tipo String. Se usuário clicar no botão Cancel, o método retorna null. Se o usuário digitar uma informação não convertível para o tipo int, ou mesmo não digitar caracter algum, e clicar no botão OK, ocorrerá um erro em tempo de execução que, futuramente, veremos como tratar. O aplicativo também utilizou o método showMessageDialog da classe JOptionPane para exibir uma mensagem que contém a soma dos dois números. O primeiro argumento informa a posição da caixa de diálogo na tela, no caso null indica que a caixa deve ficar no centro da tela. O segundo argumento é a mensagem a exibir, neste caso o resultado de uma concatenação. O terceiro argumento é um String que deve aparecer na barra de título da caixa de diálogo. O quarto argumento é o tipo de diálogo: ERROR_MESSAGE Apresenta um ícone vermelho com X. INFORMATION_MESSAGE Apresenta um ícone azul com i. WARNING_MESSAGE Apresenta um ícone amarelo com !. QUESTION_MESSAGE Apresenta um ícone verde com ?. PLAIN_MESSAGE Só a mensagem, sem ícone. Componentes Swing 8 A maioria dos aplicativos GUI exige interfaces mais elaboradas e personalizadas. Os componentes Swing são escritos, manipulados e exibidos em Java e fazem parte das Java Foundation Classes (JFC), que são bibliotecas para desenvolvimento de GUI para múltiplas plataformas. Abaixo, uma lista de componentes Swing GUI do pacote Javax.swing: JLabel Exibe texto não editável. JTextField Permite a digitação de um texto de entrada. JButton Gera um evento ao clicar nele com o mouse. JCheckBox Especifica opções que podem ser selecionadas. JList Lista de itens que permite seleção simples ou Múltipla. JComboBox Lista de opções com possibilidade de digitação na caixa. JPanel Área para organizar componentes ou desenho de imagens. Antes do conjunto Swing, introduzido no J2SE 1.2, as GUI eram construídas com componentes AWT ( Abstract Window Toolkit) do pacote java.awt. Estes componentes são exibidos de forma diferente em cada plataforma: Windows, Macintosh, ... A maneira como o usuário interage com um componente AWT particular também difere entre as plataformas. Juntas, a aparência e a maneira como o usuário interage com o aplicativo são conhecidas como a aparência e comportamento do aplicativo. Componentes Swing permitem especificar uniformemente a aparência e o comportamento para um aplicativo em todas as plataformas ou utilizar a aparência e o comportamento personalizados de cada plataforma. Entretanto, alguns componentes Swing requerem interação direta com o sistema local de janelas, o que pode restringir sua aparência e funcionalidade, sendo chamados de componentes Swing pesados. A maioria dos componentes Swing, entretanto, não são afetados pelos sistemas de janelas das plataformas e são componentes Swing leves. O diagrama UML ao lado, mostra a hierarquia da herança de classes a partir das quais os componentes Swing leves herdam seus atributos e comportamento comuns. Object Component Container JComponent A classe Object é a superclasse de toda a hierarquia de classes do Java. 9 A classe Component (pacote java.awt) declara muitos dos atributos e comportamentos comuns aos componentes GUI em pacotes java.awt e javax.swing. A classe Container organiza e exibe outros objetos Container, assim como objetos Component, em tela. Qualquer objeto que é um Container pode ser utilizado para organizar outros objetos Component em uma GUI. Como um Container é um Component, é possível anexar Containers a outros Containers para ajudar na organização de uma GUI. A classe JComponent (pacote javax.swing) é a superclasse de todos os componentes leves Swing e declara seus atributos e comportamentos comuns. Como JComponent é uma subclasse de Container, todos os componentes Swing leves também são Containers. Criando aplicações GUI O aplicativo a seguir introduz um framework, como é chamada, normalmente, a estrutura básica de uma interface. A maioria das janelas que são criadas são instâncias da classe JFrame ou um subclasse dela. JFrame fornece os atributos e comportamentos básicos de uma janela – barra de título e botões de minimizar, maximizar e fechar a janela. Em geral, uma aplicação GUI consiste de, pelo menos, duas classes: uma subclasse de JFrame e uma classe de aplicativo em que o método main cria e exibe a janela principal do aplicativo. Uma interface típica com o usuário contém muitos componentes, o que poderia criar dificuldades para identificar o propósito de cada componente, a menos que sejam fornecidas informações que declaram o propósito de cada um deles. Para isso é usado um controle da classe JLabel, que é uma subclasse de JComponent. Um JLabel exibe uma única linha de texto de leitura, uma imagem, ou um texto com imagem. A aplicação a seguir mostra vários recursos do componente JLabel e apresenta um exemplo de framework dado pelo gerenciador de layout FlowLayout. O Java tem vários gerenciadores de layout. Será utilizada uma instância da classe JFrame para exibir uma janela que contém 3 JLabel. Ao construir uma GUI, cada componente deve ser anexado a um container. No caso deste aplicativo, uma janela criada com um JFrame. Geralmente pode ser especificada a posição de cada componente, o que é conhecido como especificar o layout dos componentes GUI. Nas próximas aulas estudaremos outros gerenciadores de layout do Java. No FlowLayout, os componentes GUI são colocados em um container da esquerda para a direita, na ordem em que são anexados ao container pelo programa. Quando não houver mais espaço, eles continuam a aparecer10 da esquerda para a direita na próxima linha. Se o container for redimensionado, os componentes são reorganizados na nova largura do container, possivelmente com mais ou menos linhas de componentes. setLayout(new FlowLayout()); A instrução acima, o método setLayout, herdado indiretamente da classe Container, especifica que o layout da janela será um FlowLayout. No caso é criado um objeto FlowLayout e passada sua referência como argumento para setLayout. import java.awt.FlowLayout; // gerenciador de layout import javax.swing.JFrame; // janela básica import javax.swing.JLabel; // exibe textos e imagens import javax.swing.Icon; // para manipular imagens import javax.swing.ImageIcon; // carrega imagens import javax.swing.SwingConstants; //constantes do Swing public class UsaLabel extends JFrame{ private JLabel label1; // JLabel apenas com texto private JLabel label2; // JLabel com texto e ícone private JLabel label3; // texto e ícone adicionados public UsaLabel(){ super("Testando Labels");// frame básico c/ título setLayout(new FlowLayout()); // layout do frame label1 = new JLabel("Label simples com texto" ); label1.setToolTipText("Este é o label1"); add(label1); // adiciona label1 ao JFrame Icon bug = new ImageIcon(getClass().getResource( "bug1.gif")); // string, Icon e alinhamento label2 = new JLabel("Label com ícone à esquerda", bug,SwingConstants.LEFT); label2.setToolTipText("Este é o label2"); add(label2); // adiciona label2 ao JFrame label3 = new JLabel(); // JLabel sem argumentos label3.setText("Label com ícone acima" ); //texto label3.setIcon(bug); // adiciona o ícone label3.setHorizontalTextPosition( SwingConstants.CENTER); label3.setVerticalTextPosition( SwingConstants.BOTTOM); label3.setToolTipText("Este é o label3" ); add(label3); // adiciona label3 ao JFrame } // fim do construtor UsaLabel } // fim da classe 11 A classe TestaLabel, cria um objeto da classe LabelFrame e especifica a operação de fechamento padrão da janela (simplesmente a oculta). O método setDefaultCloseOperation da classe UsandoLabel, herdado de JFrame, com a constante JFrame.EXIT_ON_CLOSE como argumento, indica que o aplicativo termina quando a janela for fechada pelo usuário. import javax.swing.JFrame; public class TestaLabel{ public static void main( String args[] ) { UsaLabel janela = new UsaLabel(); janela.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); janela.setSize(275,180);// larg.x alt. do frame janela.setVisible( true ); // exibe frame } // fim de main } // fim da classe Desafio 1. Aumente a largura do Frame para compreender o funcionamento do estilo FlowLayout. 2. Procure informações sobre classes e métodos usados no docs do JDK. 3. Tente adicionar objetos JTextField e JButton à janela criada explorando suas particularidades. 12