Aparência e deformação
Transcrição
Aparência e deformação
FAC-FITO FACULDADE DE CIÊNCIAS DA FUNDAÇÃO INSTITUTO TECNOLÓGICO DE OSASCO CESAR AUGUSTO BENTO DO NASCIMENTO EVERTON BARBOSA GOMES APARÊNCIA E DEFORMAÇÃO EM INTERFACES GRÁFICAS Osasco 2005 CESAR AUGUSTO BENTO DO NASCIMENTO EVERTON BARBOSA GOMES APARÊNCIA E DEFORMAÇÃO EM INTERFACES GRÁFICAS Trabalho de Conclusão de Curso apresentado à Faculdade de Ciências da Fundação Instituto Tecnológico de Osasco, para a obtenção do título de Bacharel em Ciência da Computação. Orientador: Prof. Ms. João Alexandre Magri Osasco 2005 2 A nossos pais. 3 Agradecimentos Agradecemos ao nosso orientador, o Prof. Ms. João Alexandre Magri pela paciência e pelos valiosos conselhos ao longo do desenvolvimento desse trabalho. Agradecemos à Profª. Ms. Sandra Henriques, coordenadora do Trabalho de Conclusão de Curso, que se esforçou para tentar trazer um pouco de luz a todos os formandos de 2005. Agradecemos aos nossos pais por todo apoio ao longo das nossas vidas. Agradecemos também à amiga e companheira de graduação Marília Marques pelo apoio fornecido durante o desenvolvimento desse trabalho, que mais de uma vez nos emprestou o livro de Engenharia de Software de Roger Pressman. Cesar Nascimento. Everton Barbosa Gomes. 4 Faça as coisas simples. Mas não faça só as simples (Albert Einstein). 5 Resumo Em 23 de Maio de 1995 (DEITEL; DEITEL, 2002), a plataforma Java foi disponibilizada para uso geral e a partir desse ano, ela começou uma “silenciosa” revolução rumo à portabilidade total. Hoje, dez anos depois, a portabilidade total ainda não foi alcançada, tanto é que hoje existem diferentes “distribuições” Java, cada uma para um propósito especifico. Entretanto a plataforma Java teve o seu mérito quanto a trazer uma melhor portabilidade para as aplicações (principalmente para a internet naquilo que diz respeito às aplicações que hoje existem pela rede). No que diz respeito ao desenvolvimento de interfaces gráficas, Java nos introduziu um conceito inovador para a portabilidade de telas – o conceito de Layout Managers, ou Gerenciadores de Leiaute. Eles permitem construir telas consistentes e, de certo ponto de vista, até mesmo indeformáveis e, portanto, portáveis entre as diversas plataformas gráficas. Infelizmente, Java ainda não dispõe de um Gerenciador de Leiaute de propósito geral, que possa ser usado para se desenvolver qualquer interface gráfica. Cada Gerenciador de Leiaute que a plataforma Java disponibiliza tem suas próprias particularidades, cada um funcionando de uma maneira, exigindo muitas vezes que o desenvolvedor aplique uma combinação de Gerenciadores de Leiaute para poder obter a interface gráfica desejada. O propósito deste trabalho é apresentar um Gerenciador de Leiaute que seja de propósito geral e que possa por si só ser capaz de oferecer aos desenvolvedores todos os recursos necessários para a construção de qualquer interface gráfica. Palavras-chave: Java. Gerenciadores de Leiaute. Interface Gráfica. Tela. Componentes 6 Abstract On the late May of 1995 (DEITEL;DEITEL, 2002), the Java platform is finally released and from then on, this platform started a “quiet revolution” heading to total portability between platforms. Today, ten years later, the total portability is still not possible, a clear evidence of this is the existence of different Java “distributions”, each one fits a specific purpose. However, the Java platform had its importance about bringing a better portability for applications, especially about the ones running on the internet today. Java has introduced us to a new concept of GUI (Graphical User Interface) development – the Layout Managers. When using Layout Managers is possible to build GUI’s that will always keep the same appearance and portable between different graphic platforms. Unfortunately there is not a Layout Manager for general purposes yet, there is not a Layout Manager for building any GUI. Each pre defined Layout Manager of the Java platform has its own features and a determined behavior what, many times, leads developers to use combinations of more than one Layout Manager in order to get the expected GUI. The purpose of this work is to show how a Layout Manager of free purpose may work and show how this Layout Manager will be able to provide developers all the resources for building any GUI. Keywords: Java. Layout Managers. Graphical User Interface. Screen. Components. 7 Sumário Parte 1 – Introdução.................................................................................................................. 11 1.2 – Plataformas...................................................................................................................12 1.2.1 – Plataforma Física.................................................................................................. 12 1.2.2 – Plataforma Lógica................................................................................................. 13 1.3 – Revisão.........................................................................................................................13 1.3.1 – Estrutura das Interfaces Gráficas.......................................................................... 13 1.3.2 – Classes e Interfaces............................................................................................... 15 1.4 – Motivação dos Gerenciadores de Leiaute.................................................................... 15 1.5 – Alterações em Interfaces Gráficas............................................................................... 16 Parte 2 – Abordagens possíveis ............................................................................................... 18 2.1 – Introdução.................................................................................................................... 18 2.2 – Posicionamento-Dimensionamento Absoluto..............................................................18 2.3 – Gerenciadores de Leiaute pré-definidos...................................................................... 22 2.3.1 – Gerenciador de Leiaute de Fluxo.......................................................................... 23 2.3.2 – Gerenciador de Leiaute de Grade......................................................................... 25 2.3.3 – Gerenciador de Leiaute de Borda......................................................................... 27 2.3.4 – Gerenciador de Leiaute de Caixa.......................................................................... 30 2.3.5 – Gerenciador de Leiaute do tipo Cartão................................................................. 33 2.3.6 – Gerenciador de Leiaute de Grade Dinâmico.........................................................35 2.3.7 – Gerenciador de Leiaute do tipo Mola................................................................... 41 Parte 3 – Problema ................................................................................................................... 45 3.1 – Descrição......................................................................................................................45 Parte 4 – Solução ......................................................................................................................47 4.1 – Análise de mercado...................................................................................................... 47 4.1.2 – Cafeteira................................................................................................................ 47 4.1.3 – Projeto Matisse......................................................................................................50 4.2 – O TransparenLayout.................................................................................................... 51 4.2.1 – Levantamento de Requisitos................................................................................. 52 4.2.2 – Diagrama de Casos de Uso................................................................................... 54 4.2.3 – Documentação dos Casos de Uso......................................................................... 54 4.3 – Diagrama de Classes.................................................................................................... 58 4.4 – Diagramas de Seqüência.............................................................................................. 59 4.4.1 – Diagrama de Seqüência #1 – Manter Componente...............................................59 4.4.2 – Diagrama de Seqüência #2 – Redimensionar Interface........................................ 60 4.4.3 – Diagrama de Seqüência #3 – Alterar Resolução do Monitor............................... 61 4.4.4 – Diagrama de Seqüência #4 – Ajustar Componente.............................................. 63 4.5 – Implementação............................................................................................................. 64 Parte 5 – Conclusão...................................................................................................................72 5.1 – Testes........................................................................................................................... 72 5.2 – Teste de unidade...........................................................................................................72 5.3 – Teste de integração.......................................................................................................78 5.4 – Métricas........................................................................................................................79 5.5 – Resultados ................................................................................................................... 80 5.5.1 – RFE & Java.net..................................................................................................... 85 Parte 6 – Referências Bibliográficas......................................................................................... 87 Parte 7 - Apêndice..................................................................................................................... 89 Package net.java.dev.transparentlayout ............................................................................... 89 net.java.dev.transparentlayout Class TransparentLayout.......................................................................................................89 originalComponentOrientation......................................................................................... 91 originalComponentBounds............................................................................................... 91 8 TransparentLayout............................................................................................................ 93 TransparentLayout............................................................................................................ 93 getOriginalComponentOrientation................................................................................... 93 setOriginalComponentOrientation.................................................................................... 94 getOriginalComponentBounds......................................................................................... 94 setOriginalComponentBounds..........................................................................................94 addLayoutComponent.......................................................................................................95 addLayoutComponent.......................................................................................................95 removeLayoutComponent.................................................................................................95 getLayoutAlignmentX...................................................................................................... 96 getLayoutAlignmentY...................................................................................................... 96 maximumLayoutSize........................................................................................................ 96 preferredLayoutSize..........................................................................................................96 minimumLayoutSize.........................................................................................................97 invalidateLayout............................................................................................................... 97 layoutContainer.................................................................................................................97 toString..............................................................................................................................98 Lista de Figuras1 Figura 1 – Programa demonstrando Posicionamento-Dimensionamento Absoluto1............... 20 Figura 2 – Programa demonstrando Posicionamento-Dimensionamento Absoluto2............... 21 Figura 3 – Programa Ex. do Leiaute de Fluxo1........................................................................ 24 Figura 4 – Programa Ex. do Leiaute de Fluxo2........................................................................ 24 Figura 5 – Programa Ex. do Leiaute de Fluxo3..................................................................... 24 Figura 6 – Programa Ex. do Leiaute de Fluxo4........................................................................ 24 Figura 7 – Programa Ex. do Leiaute de Grade1........................................................................26 Figura 8 – Programa Ex. do Leiaute de Grade2........................................................................26 Figura 9 – Programa Ex. do Leiaute de Grade3........................................................................26 Figura 10 – Programa Ex. do Leiaute de Grade4......................................................................26 Figura 11 – Programa Ex. do Leiaute de Borda1......................................................................29 Figura 12 – Programa Ex. do Leiaute de Borda2......................................................................29 Figura 13 – Programa Ex. do Leiaute de Borda3......................................................................29 Figura 14 – Programa Ex. do Leiaute de Borda4.....................................................................29 Figura 15 – Progr. Ex. do Leiaute de Caixa1............................................................................31 Figura 16 – Progr. Ex. do Leiaute de Caixa2............................................................................31 Figura 17 – Representação do maço de cartões........................................................................ 33 Figura 18 – Progr. Ex. do Leiaute do tipo Cartão 1.................................................................. 35 Figura 19 – Progr. Ex. do Leiaute do tipo Cartão 2.................................................................. 35 Figura 20 – Progr. Ex. do Leiaute do tipo Cartão 3.................................................................. 35 Figura 21 – Progr. Ex. do Leiaute de Grade Dinâmico1...........................................................40 Figura 22 – Progr. Ex. do Leiaute de Grade Dinâmico2...........................................................40 Figura 23 – Progr. Ex. do Leiaute de Grade Dinâmico3...........................................................40 Figura 24 – Progr. Ex. do Leiaute de Grade Dinâmico4...........................................................40 Figura 25 – Progr. Ex. do Leiaute do tipo Mola1..................................................................... 44 Figura 26 – Progr. Ex. do Leiaute do tipo Mola2..................................................................... 44 As figuras que mostram os programas Java desse trabalho, foram geradas usando o Ambiente Integrado de Desenvolvimento NetBeans versão 4.1. As figuras que mostram os diagramas UML desse trabalho foram geradas usando a ferramenta CASE Enterprise Architect versão 5. 1 9 Figura 27 – Cafeteira, sua interface e um exemplo...................................................................48 Figura 28 – O código da classe, gerado pelo Cafeteira.............................................................49 Figura 29 – Código da Janela, gerado pelo Cafeteira............................................................... 50 Figura 30 – Diagrama de Casos de Uso do TransparentLayout............................................... 54 Figura 31 – Diagrama de Classes do TransparentLayout......................................................... 58 Figura 32 – Diagrama de Seqüência #1 – Manter Componente............................................... 59 Figura 33 – Diagrama de Seqüência #2 – Redimensionar Interface.........................................61 Figura 34 – Diagrama de Seqüência #3 – Alterar Resolução do Monitor................................ 62 Figura 35 – Diagrama de Seqüência #4 – Ajustar Componente............................................... 63 Figura 36 – Interface do exemplo em seu tamanho original.....................................................76 Figura 37 – Interface do exemplo aumentada........................................................................... 77 Figura 38 – Integração com o NetBeans1................................................................................. 78 Figura 39 – Integração com o NetBeans2................................................................................. 79 Figura 40 – Interface do exemplo em seu tamanho original.....................................................84 Figura 41 – Interface do exemplo aumentada........................................................................... 84 Lista de Programas Listagem 1 – Código demonstrando Posicionamento-Dimensionamento Absoluto................ 19 Listagem 2 – Código demonstrando o Gerenciador de Leiaute de Fluxo.................................24 Listagem 3 – Código demonstrando o Gerenciador de Leiaute de Grade................................ 25 Listagem 4 – Código demonstrando o Gerenciador de Leiaute de Borda................................ 29 Listagem 5 – Código demonstrando o Gerenciador de Leiaute de Caixa.................................31 Listagem 6 – Código demonstrando o Gerenciador de Leiaute de Grade Dinâmico............... 40 Listagem 7 – Código demonstrando o Gerenciador de Leiaute de Mola..................................43 Listagem 8 – Implementação do TransparentLayout................................................................71 Listagem 9 – Exemplo usando a solução.................................................................................. 76 Listagem 10 – Comparativo final..............................................................................................84 Lista de Tabelas Tabela 1 – Valores do Gerenciador de Leiaute de Grade Dinâmico.........................................38 Tabela 2 – Métricas para Gerenciadores de Leiaute pré-definidos...........................................80 Tabela 3 – Métricas para o TransparentLayout........................................................................ 80 10 Parte 1 – Introdução A plataforma Java trouxe um novo patamar de portabilidade ao possibilitar que uma mesma aplicação seja executada em diferentes plataformas físicas. No que diz respeito ao desenvolvimento de interfaces gráficas, Java introduziu um novo conceito – o dos Gerenciadores de Leiaute2 (Layout Managers). Tais gerenciadores são componentes de software (representados em Java por classes que implementam a interface LayoutManager ou LayoutManager2) que permitem que a tela mantenha sempre o aspecto desejado. A consistência, entretanto, é conseguida à custa de uma elevada complexidade. Isso acontece quando se usa Java em sua forma mais “pura”, ou seja, sem ferramentas de Desenvolvimento Integrado – adaptado de (KUZNETSOV, 2005). Quando se recorre a tais ferramentas, consegue-se amenizar o problema da complexidade, mas não eliminá-lo. Mesmo nesse caso, a ferramenta ainda exige que o desenvolvedor tenha domínio sobre os Gerenciadores Leiaute. Na média, portanto, a produtividade é a mesma em ambos os cenários. O presente trabalho tem como objetivo introduzir um novo Gerenciador de Leiaute para Java (e desenvolvido em Java), um gerenciador simples de se usar, que sozinho seja capaz de gerenciar os componentes de uma interface gráfica e mantê-los sempre com uma aparência uniforme e que tenha como resultado um programa com menos linhas de código e que por conseqüência utilizará menos memória principal do computador. O texto é apresentado em sete partes: • Parte 1 – Introdução: nessa parte é apresentado o objetivo do trabalho e também os conceitos necessários para o desenvolvimento e entendimento do mesmo. Nessa parte a plataforma Java é abordada através de um resumo de suas principais características e recursos, com ênfase aos seus recursos para o desenvolvimento de interfaces gráficas. • Parte 2 – Abordagens possíveis: são apresentadas as duas abordagens possíveis para o desenvolvimento de telas na plataforma Java: o uso de Gerenciadores 2 Desse ponto em diante do trabalho será usado o termo adaptado para a Língua Portuguesa. 11 Leiaute ou o uso de Posicionamento-Dimensionamento Absoluto (freepositioning). • Parte 3 – Problema: a terceira parte destina-se a mostrar a dificuldade existente atualmente no desenvolvimento de telas consistentes em Java. • Parte 4 – Solução: um novo Gerenciador de Leiaute – o TransparentLayout – é apresentado com o objetivo de facilitar o desenvolvimento de interfaces gráficas em Java. • Parte 5 – Conclusão: são apresentados os testes e resultados atingidos com a solução desenvolvida. • Parte 6 – Referências Bibliográficas: são apresentadas as obras que serviram como referência para o desenvolvimento do trabalho. • Parte 7 – Apêndice: no apêndice do trabalho, é mostrada a documentação Java (Javadoc) que foi gerada para a solução desenvolvida. 1.2 – Plataformas 1.2.1 – Plataforma Física Da reunião do hardware de uma máquina com o sistema operacional correspondente surge o conceito denominado plataforma física. Durante muito tempo, a falta de portabilidade não foi problema, pois os sistemas eram homogêneos e havia pouca integração. Num mundo cada vez mais conectado, entretanto, o hardware dos computadores, antes monolítico, está se tornando mais e mais distribuído. A necessidade de controlar essa nova arquitetura de máquinas trouxe consigo o desafio de desenvolver softwares que pudessem ser utilizados em vários lugares, ou seja, softwares portáveis. 12 Arquiteturas distribuídas são tipicamente heterogêneas. Nelas, cada tipo de máquina possui as suas peculiaridades, o que exige, a princípio, um software diferente para cada tipo existente. 1.2.2 – Plataforma Lógica Usar um software diferente para cada plataforma física é algo impraticável. Para amenizar o problema, foram criadas as plataformas lógicas, uma camada intermediária de software que traduz as peculiaridades de cada plataforma para uma especificação comum (máquina virtual), permitindo que todos se entendam. O TCP/IP, o protocolo padrão da Internet, é certamente a plataforma lógica mais usada do mundo. Ao permitir que diversas plataformas físicas trocassem dados entre si, esse protocolo facilitou a adoção da Internet. O TCP/IP, entretanto, não é uma linguagem de programação, mas apenas um protocolo de comunicação. A tecnologia Java foi uma das plataformas lógicas pioneiras. Através da especificação de uma máquina virtual, ela permitiu que um mesmo programa fosse executado em várias plataformas físicas. Mérito dos bytecodes, o código genérico falado pelo interpretador Java. 1.3 – Revisão Antes de lidar com os Gerenciadores de Leiaute, de Java, vamos solidificar os conceitos básicos de forma a poder posteriormente edificar o trabalho sobre uma base segura. 1.3.1 – Estrutura das Interfaces Gráficas Na terminologia Java, componentes (instâncias da classe Component do pacote java.awt) são objetos que possuem interface gráfica. Os componentes não têm vida própria e, portanto, para serem exibidos precisam ser adicionados a outro componente (o contêiner, objeto da classe Container), geralmente um painel (objeto da classe Panel). 13 Janelas são componentes que oferecem espaço para os outros componentes pintarem a si próprios na tela. Contêineres, por sua vez, são componentes cuja única função é conter outros componentes. O tipo de contêiner mais usado são os painéis. Toda janela possui um painel dentro do qual devem ser adicionados os componentes a serem exibidos por ela. Gerenciadores de Leiaute são objetos projetados para automatizar o posicionamento e dimensionamento dos componentes dentro de seu contêiner. Além de automatizar o posicionamento e o dimensionamento dos componentes, alguns Gerenciadores Leiaute, efetuam também ajustes para se adaptarem ao modo de leitura local. Em países orientais, por exemplo, onde a leitura é feita da direita para a esquerda, esses gerenciadores mais elaborados permitem que o preenchimento da tela seja feito no sentido apropriado em vez de no sentido tradicional (da esquerda para a direita). Em Java, adaptação de um programa às características locais chama-se Internacionalização. Nestas condições pode-se concluir que se espera que um Gerenciador de Leiaute tenha suporte aos seguintes recursos: • Posicionar os componentes dentro do contêiner; • Dimensionar os componentes dentro do contêiner; • Adaptar a tela ao modo de leitura local; Em Java, os Gerenciadores de Leiaute são objetos que implementam uma das seguintes interfaces: java.awt.LayoutManager ou java.awt.LayoutManager2. O sentido do fluxo dos componentes em um contêiner é definido pela propriedade (atributo) ComponentOrientation, que pode assumir os seguintes valores: • ComponentOrientation.LEFT_TO_RIGHT (Da esquerda para a direita): os componentes serão dispostos da esquerda para a direita. • ComponentOrientation.RIGHT_TO_LEFT (Da direita para a esquerda) : os componentes serão dispostos da direita para a esquerda. 14 A partir da subseção 2.4, serão mostrados também, exemplos que ilustram o uso dos dois valores possíveis para a propriedade ComponentOrientation em cada Gerenciador de Leiaute. 1.3.2 – Classes e Interfaces Uma classe corresponde a uma descrição de um conjunto de objetos que tem características comuns. Ela é composta por atributos ou variáveis de instância (dados) e métodos. Portanto ela pode descrever dados e programas. Os objetos são instanciados (criados) a partir das classes. No caso das classes do tipo interface tem-se os atributos do tipo e/ou a especificação dos métodos, porém eles não estão codificados. A codificação destes métodos é necessariamente feita nas subclasses que herdam os atributos e/ou métodos da classe do tipo interface. Nestas condições os objetos instanciados a partir das subclasses que implementam os métodos das classes do tipo interface Implementar uma interface significa codificar todos os seus métodos em uma subclasse. Para se criar um Gerenciador de Leiaute é necessário definir uma subclasse e implementar nela os métodos requeridos pela interface correspondente. 1.4 – Motivação dos Gerenciadores de Leiaute Estando a execução dos programas garantida nos mais diversos ambientes, resta-nos agora uma pergunta: e a aparência dos elementos que formam a interface gráfica? Além das diferenças de comandos existentes entre as plataformas, há ainda as diferenças de ordem gráfica. Na verdade, dentro de uma mesma plataforma, basta alterar a resolução de vídeo e a aparência dos programas se altera ao invés de apenas ser exibida com maior resolução (mais pontos por polegada quadrada), o que seria o ideal. 15 Não adianta, portanto, permitir que um mesmo software seja executado em vários lugares, se, ao sair de sua plataforma nativa, ele aparecer com um aspecto visual diferente. Em uma outra plataforma, a deformação, poderia fatalmente chegar a tal ponto que impediria a utilização da aplicação. Logo, ao impedir o uso de um mesmo código em várias plataformas, esse problema acabaria comprometendo a própria portabilidade das plataformas lógicas. O conceito de máquina virtual traz portabilidade para os programas, mas ele por si só não impede a alteração dos elementos da interface gráfica. Em suma, embora eles permitam que um mesmo código seja executado em várias plataformas lógicas, não há qualquer garantia sobre como será a aparência do programa. Essa limitação certamente pode comprometer o aproveitamento da tecnologia. 1.5 – Alterações em Interfaces Gráficas Uma interface gráfica é composta por componentes, também chamados controles. Gerenciadores de Leiaute são objetos cuja tarefa é automatizar o reposicionamento e o redimensionamento dos componentes/controles de forma a manter a tela consistente. O aspecto original de uma interface gráfica pode ser alterado principalmente pelas seguintes causas: • Resolução de vídeo Em uma mesma plataforma, a quantidade de pontos por polegada quadrada pode variar de placa gráfica e monitor; • Tipo da plataforma Sistemas operacionais diferentes efetuam a pintura da tela de maneiras diferentes; • Tipo de dispositivo O código necessário para desenhar uma tela num dispositivo móvel é diferente do código equivalente numa estação de trabalho de alto desempenho. 16 A missão dos Gerenciadores de Leiaute é separar a camada lógica do desenho da camada física, permitindo, assim, que um mesmo código produza, a mesma tela onde quer que ele seja executado. 17 Parte 2 – Abordagens possíveis 2.1 – Introdução Montar interfaces gráficas, como qualquer outra parte do software, pode ser uma tarefa complexa. Hoje, existem softwares que automatizam grande parte das tarefas, inclusive a criação de novos programas. Independentemente da ferramenta utilizada, entretanto, há apenas duas maneiras possíveis de se montar telas: da maneira tradicional, que faz uso de PosicionamentoDimensionamento Absoluto ou usando Gerenciadores de Leiaute. 2.2 – Posicionamento-Dimensionamento Absoluto A maneira tradicional de se montar telas se resume a duas etapas: 1. Adicionar os componentes na tela; 2. Posicionar os componentes, ou seja, especificar as coordenadas (linha e coluna) em que cada componente deve aparecer na tela; 3. Dimensionar os componentes, ou seja, definir o tamanho (largura e altura) que cada um deles deve assumir na tela em sua respectiva posição. A montagem tradicional é simples e direta, mas não garante a portabilidade (em termos de alteração visual) da tela produzida. A Listagem 1 mostra um programa que ilustra o uso de Posicionamento-Dimensionamento Absoluto. As figuras 1 e 2 mostram o resultado gerado pelo uso desta técnica. 18 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.awt.*; import javax.swing.*; public class ExemploSemLeiaute extends JApplet { public void init() { setLayout(null); Component c1 = new JLabel("Rótulo aqui "), c2 = new JTextField("Campo de texto aqui "), c3 = new JButton("Botão aqui "); add(c1); add(c2); add(c3); } // Posicionamento e dimensionamento absolutos // bounds = (x + y + largura + altura) c1.setBounds(50, 50, 100, 50); c2.setBounds(250, 50, 100, 50); c3.setBounds(145, 150, 105, 50); public static void main(String[] args) { JFrame browser = new JFrame("Exemplo sem Gerenciador de Leiaute"); JApplet applet = new ExemploSemLeiaute(); // Altera o modo de leitura applet.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); browser.add(applet); applet.init(); browser.pack(); browser.setBounds(200, 150, 400, 300); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); } } Listagem 1 – Código demonstrando Posicionamento-Dimensionamento Absoluto A Figura 1 mostra o resultado gerado pela Listagem 1. A Figura 2 mostra o mesmo programa após sua janela ter sido redimensionada – apenas a janela sofreu o aumento, os componentes dentro dela permaneceram em suas posições originais. 19 Figura 1 – Programa demonstrando Posicionamento-Dimensionamento Absoluto1 20 Figura 2 – Programa demonstrando Posicionamento-Dimensionamento Absoluto2 21 2.3 – Gerenciadores de Leiaute pré-definidos A montagem de telas com Gerenciadores de Leiaute exige passos adicionais (e mais complexos) se compararmos com a técnica de Posicionamento-Dimensionamento Absoluto. São eles: 1. Definir (e apenas definir) a posição de cada componente; 2. Definir o tamanho dos componentes; 3. Descobrir qual o Gerenciador de Leiaute (ou combinação deles) que produza o posicionamento e dimensionamento definidos anteriormente; 4. Adicionar na tela o painel (ou combinação de painéis) correspondente ao(s) gerenciador(es) necessário(s); 5. Configurar o gerenciador de leiaute de cada painel; 6. Adicionar os componentes na tela (na verdade, ao painel apropriado e no momento apropriado, dependendo do gerenciador de leiaute usado). A plataforma Java disponibiliza sete Gerenciadores de Leiaute pré-definidos. Cada um deles gerencia os componentes da interface gráfica segundo um leiaute (disposição). Daí vêm seus nomes: • FlowLayout (Gerenciador de Leiaute de Fluxo) • GridLayout (Gerenciador de Leiaute de Grade) • BorderLayout (Gerenciador de Leiaute de Borda) • BoxLayout (Gerenciador de Leiaute de Caixa) • CardLayout (Gerenciador de Leiaute do tipo Cartão) • GridBagLayout (Gerenciador de Leiaute de Grade Dinâmico) • SpringLayout (Gerenciador de Leiaute do tipo Mola) Nas próximas subseções os Gerenciadores de Leiaute pré-definidos da plataforma Java serão abordados a partir de uma adaptação de (SUN1, 2005). Será mostrado um exemplo de cada Gerenciador de Leiaute, exemplificando como cada um deles age sobre os componentes que gerenciam. 22 Os exemplos apresentados ao longo desse trabalho aparecem na forma de programas que podem ser executados independentemente (aplicativos stand-alone) ou na forma de miniaplicativos. Mini-aplicativos (ou applets) são programas que são executados dentro de um navegador. 2.3.1 – Gerenciador de Leiaute de Fluxo Um Gerenciador de Leiaute de Fluxo dispõe os componentes num fluxo direcional, muito parecido com as palavras em um texto. Um Gerenciador de Leiaute de Fluxo são tipicamente usados para controlar botões em um painel. Eles dispõem os botões horizontalmente até que não caibam mais botões na mesma linha. O alinhamento é determinado pelo atributo align. Os valores possíveis são: • LEFT (Esquerda) • RIGHT (Direita) • CENTER (Centro) • LEADING (Início) • TRAILING (Fim) Na Listagem 2 tem-se o código de um programa que utiliza o Gerenciador de Leiaute de Fluxo. 1 2 import java.awt.*; 3 import javax.swing.*; 4 5 public class ExemploLeiauteDeFluxo extends JApplet { 6 7 public void init() { 8 setLayout(new FlowLayout()); 9 10 JButton button1, button2, button3; 11 12 button1 = new JButton("Ok"); 13 button2 = new JButton("Abrir"); 14 button3 = new JButton("Fechar"); 15 add(button1); 16 add(button2); 17 add(button3); 18 } 19 23 20 public static void main(String[] args) 21 { 22 JFrame browser = new JFrame("Exemplo do Leiaute de Fluxo"); 23 JApplet applet = new ExemploLeiauteDeFluxo(); 24 // Altera o modo de leitura 25 applet.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 26 27 browser.add(applet); 28 applet.init(); 29 browser.pack(); 30 browser.setBounds(200, 150, 400, 300); 31 browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 32 browser.setVisible(true); 33 } 34 } 35 Listagem 2 – Código demonstrando o Gerenciador de Leiaute de Fluxo As Figuras 3 e 4 mostram, respectivamente, o programa da Listagem 2, em seu tamanho original e depois de ter sido redimensionado. As figuras 5 e 6 mostram o mesmo programa nas mesmas situações, porém agora utilizando a propriedade ComponentOrientation com o valor RIGHT_TO_LEFT. Figura 3 – Programa Ex. do Leiaute de Fluxo1 Figura 5 – Programa Ex. do Leiaute de Fluxo3 Figura 4 – Programa Ex. do Leiaute de Fluxo2 Figura 6 – Programa Ex. do Leiaute de Fluxo4 Um Gerenciador de Leiaute de Fluxo deixa cada componente assumir seu tamanho natural (preferido ou preferred size). 24 2.3.2 – Gerenciador de Leiaute de Grade Gerenciadores de Leiaute de Grade são aqueles que dispõem os elementos da interface gráfica numa grelha. O contêiner é dividido em retângulos de mesmo tamanho e um componente é colocado em cada retângulo. A Listagem 3 mostra um programa em Java que dispõe seis botões em três linhas e duas colunas usando o Gerenciador de Leiaute de Grade: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.awt.*; import javax.swing.*; public class ExemploLeiauteDeGrade extends JApplet { public void init() { setLayout(new GridLayout(3,2)); add(new JButton("1")); add(new JButton("2")); add(new JButton("3")); add(new JButton("4")); add(new JButton("5")); add(new JButton("6")); } public static void main(String[] args) { JFrame browser = new JFrame("Exemplo do Leiaute de Grade"); JApplet applet = new ExemploLeiauteDeGrade(); // Altera o modo de leitura applet.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); browser.add(applet); applet.init(); browser.pack(); browser.setBounds(200, 150, 400, 300); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); } } Listagem 3 – Código demonstrando o Gerenciador de Leiaute de Grade Se a propriedade ComponentOrientation do contêiner é LEFT_TO_RIGHT, a listagem 3 produz a saída mostrada na figura 7. A figura 8 mostra o programa da figura 7 com sua interface gráfica redimensionada. Se essa propriedade ComponentOrientation é RIGHT_TO_LEFT então a listagem 3 produz a saída mostrada na figura 9. A figura 10 mostra a saída da figura 9 redimensionada. Comparando a saída produzida pela figura 1 e pela figura 3 podemos concluir a o valor da propriedade ComponentOrientation não afeta a interface gráfica. 25 Figura 7 – Programa Ex. do Leiaute de Grade1 Figura 8 – Programa Ex. do Leiaute de Grade2 Figura 9 – Programa Ex. do Leiaute de Grade3 Figura 10 – Programa Ex. do Leiaute de Grade4 Quando ambos os números de linhas e o número de colunas tiverem sido ajustados para valores diferentes de zero, ou por um construtor ou através dos métodos setRows e setColumns, o número de colunas especificado é ignorado. Em vez disso, o número de colunas é determinado a partir do número especificado de linhas e o número total de componentes no gerenciador de leiaute (quantidade de colunas = quantidade de componentes / quantidade de linhas). Então, se, por exemplo, três linhas e duas colunas tiverem sido especificadas e nove componentes são adicionados ao gerenciador de leiaute, eles serão exibidos como três linhas de três colunas. Especificar o número de colunas afeta o gerenciador de leiaute somente quando o número de linhas é ajustado para zero. 26 2.3.3 – Gerenciador de Leiaute de Borda Um Gerenciador de Leiaute de Borda formata o contêiner, posicionando e dimensionando seus componentes para caber em cinco regiões: norte, sul, leste, oeste e centro. Cada região pode conter apenas um componente e é identificada pela constante correspondente: NORTH, SOUTH, EAST, WEST e CENTER. Ao adicionar um componente ao gerenciador, devemos associá-lo a uma dessas coordenadas. Como uma conveniência, o Gerenciador de Leiaute de Borda interpreta a falta de uma especificação textual o mesmo que a constante CENTER. Além disso, o gerenciador de borda suporta as constantes de posicionamento relativo, PAGE_START, PAGE_END, LINE_START e LINE_END. Num contêiner cuja ComponentOrientation é ajustada para ComponentOrientation.LEFT_TO_RIGHT, essas constantes mapeiam para NORTH, SOUTH, WEST e EAST, respectivamente. Para compatibilidade com versões anteriores, o gerenciador de borda também inclui as constantes de posicionamento relativo BEFORE_FIRST_LINE, AFTER_LAST_LINE, BEFORE_LINE_BEGINS e AFTER_LINE_ENDS. Elas são equivalentes à PAGE_START, PAGE_END, LINE_START e LINE_END respectivamente. Para consistência com as constantes de posicionamento relativo usadas por outros componentes, as últimas constantes são preferidas. Misturar constantes de posicionamento absolutas e relativas pode conduzir a resultados imprevisíveis. Se você usa ambos os tipos, as constantes relativas terão precedência. Se, por exemplo, você adicionar componentes usando as constantes NORTH e PAGE_START num contêiner cujo sentido é LEFT_TO_RIGHT, somente a PAGE_START será considerada. NOTA: Atualmente, Gerenciador de Leiaute de Borda não suporta orientações verticais. O ajuste isVertical na propriedade ComponentOrientation no contêiner não é respeitado. 27 Os componentes são dispostos de acordo com seus tamanhos preferidos e as restrições de tamanho do componente. Os componentes NORTH e SOUTH podem ser estendidos horizontalmente; os componentes EAST e WEST podem ser estendidos verticalmente; o componente CENTER pode crescer tanto horizontalmente como verticalmente para preencher qualquer espaço deixado livre. Desde a versão 1.4 de Java, as bordas podem ser especificadas de maneira dinâmica através das constantes: • BorderLayout.PAGE_START; • BorderLayout.LINE_START; • BorderLayout.CENTER; • BorderLayout.LINE_END; • BorderLayout.PAGE_END. O uso de tais novas opções é preferível, pois elas oferecem suporte à internacionalização. Enquanto no antigo padrão para idiomas a borda oeste, por exemplo, sempre aparecia à esquerda da tela, no novo esquema a borda correspondente (LINE_START) pode aparecer em outro lugar. Em países onde a leitura é feita da esquerda para a direita, a borda LINE_START aparece à esquerda e nos demais ela aparece à direita. A Listagem 4 implementa um programa Java com cinco botões. Esse programa faz uso do Gerenciador de Leiaute de Borda. 1 2 import java.awt.*; 3 import javax.swing.*; 4 5 public class ExemploLeiauteDeBorda extends JApplet { 6 7 public void init() { 8 setLayout(new BorderLayout()); 9 add(new JButton("Início da página"), BorderLayout.PAGE_START); 10 add(new JButton("Início da linha"), BorderLayout.LINE_START); 11 add(new JButton("Centro"), BorderLayout.CENTER); 12 add(new JButton("Fim da linha"), BorderLayout.LINE_END); 13 add(new JButton("Fim da página"), BorderLayout.PAGE_END); 14 } 15 16 public static void main(String[] args) 17 { 18 JFrame browser = new JFrame("Exemplo do Leiaute de Borda"); 19 JApplet applet = new ExemploLeiauteDeBorda(); 20 // Altera o modo de leitura 21 applet.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 22 23 browser.add(applet); 28 24 25 26 27 28 29 } 30 } 31 applet.init(); browser.pack(); browser.setBounds(200, 150, 400, 300); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); Listagem 4 – Código demonstrando o Gerenciador de Leiaute de Borda Figura 11 – Programa Ex. do Leiaute de Borda1 Figura 12 – Programa Ex. do Leiaute de Borda2 Figura 13 – Programa Ex. do Leiaute de Borda3 Figura 14 – Programa Ex. do Leiaute de Borda4 29 2.3.4 – Gerenciador de Leiaute de Caixa Um Gerenciador de Leiaute de Caixa permite que vários componentes sejam dispostos verticalmente ou horizontalmente. Os componentes não irão mudar de linha então, por exemplo, um arranjo vertical de componentes permanecerá disposto verticalmente quando a janela é redimensionada. Por padrão todo espaço extra é posicionado após os componentes. Para distribuir uniformemente o espaço extra oriundo do redimensionamento de uma janela usa-se um recurso chamado de cola (glue). Cola é um componente invisível cuja única função é atrair o espaço extra para uma posição específica na tela. A cola acumula o espaço livre na região da tela onde é inserida. Combinar vários painéis com diferentes combinações de horizontal e vertical (mais os recursos de cola) gera um efeito similar ao Gerenciador de Leiaute de Borda. A listagem 5 mostra a implementação de um programa Java que utiliza o Gerenciador de Leiaute de Caixa. 1 2 import java.awt.*; 3 import javax.swing.*; 4 5 public class ExemploLeiauteDeCaixa extends JApplet { 6 7 public void init() { 8 9 JPanel p1 = new JPanel(null), 10 p2 = new JPanel(null), 11 p3 = new JPanel(null); 12 13 JButton[] b = new JButton[6]; 14 for (int i=0; i < b.length; i++) 15 { 16 b[i] = new JButton("C" + (i+1)); 17 b[i].setAlignmentX(Component.CENTER_ALIGNMENT); 18 } 19 20 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 21 p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); 22 p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS)); 23 24 p1.setBorder(BorderFactory.createTitledBorder("P1")); 25 p2.setBorder(BorderFactory.createTitledBorder("P2")); 26 p3.setBorder(BorderFactory.createTitledBorder("P3")); 27 28 p2.add(Box.createGlue()); 29 p2.add(b[0]); 30 p2.add(Box.createGlue()); 31 p2.add(b[1]); 32 p2.add(Box.createGlue()); 33 p2.add(b[2]); 30 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 } 68 p2.add(Box.createGlue()); p3.add(Box.createGlue()); p3.add(b[3]); p3.add(Box.createGlue()); p3.add(b[4]); p3.add(Box.createGlue()); p3.add(b[5]); p3.add(Box.createGlue()); p1.add(Box.createGlue()); p1.add(p2); p1.add(Box.createGlue()); p1.add(p3); p1.add(Box.createGlue()); add(p1); } public static void main(String[] args) { JFrame browser = new JFrame("Exemplo do Leiaute de Caixa"); JApplet applet = new ExemploLeiauteDeCaixa(); // Altera o modo de leitura applet.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); } browser.add(applet); applet.init(); browser.pack(); browser.setLocation(300, 250); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); Listagem 5 – Código demonstrando o Gerenciador de Leiaute de Caixa Figura 15 – Progr. Ex. do Leiaute de Caixa1 Figura 16 – Progr. Ex. do Leiaute de Caixa2 A figura 15 mostra um programa Java que possui dois painéis dispostos horizontalmente, cada qual contendo 3 componentes dispostos verticalmente e que usa a propriedade ComponentOrientation com o valor LEFT_TO_RIGHT. A figura 16 mostra esse mesmo programa, porém com sua interface redimensionada. Para o exemplo acima não haveria mudança caso o valor da propriedade ComponentOrientation fosse RIGHT_TO_LEFT. Isso aconteceu pelo fato do exemplo utilizar 31 painéis agrupados ao invés de simplesmente dispor os componentes dentro de um único painel. O Gerenciador de Leiaute de Caixa é construído com um parâmetro de eixo que especifica o tipo de formato que será feito. Há quatro opções: • X_AXIS – Componentes são dispostos horizontalmente da esquerda para a direita; • Y_AXIS – Componentes são dispostos verticalmente de cima para baixo; • LINE_AXIS – Componentes são dispostos como palavras numa linha (assim como o Gerenciador de Fluxo), baseado na propriedade ComponentOrientation do contêiner. Se ela é horizontal, então os componentes são dispostos horizontalmente, caso contrário eles são alinhados verticalmente. Para direções verticais, se o sentido do contêiner é da esquerda para a direita então os componentes são dispostos da esquerda para a direita, caso contrário eles são dispostos da direita para a esquerda. Para direções verticais os componentes são sempre dispostos de cima para baixo; • PAGE_AXIS – Componentes são dispostos como linhas de texto numa página, baseado na propriedade componentOrientation do contêiner. Se ela é horizontal então os componentes são dispostos verticalmente, caso contrário eles são dispostos horizontalmente. Para direções horizontais, se o sentido de preenchimento do contêiner é da esquerda para a direita, então os componentes são dispostos da esquerda para a direita, caso contrário eles são alinhados da direita para a esquerda. Para direções verticais, os componentes são sempre dispostos de cima para baixo. Para todas as direções, os componentes são dispostos na mesma ordem que eles foram adicionados ao contêiner. O Gerenciador de Leiaute de Caixa tenta dispor os componentes seguindo as suas larguras (para formato horizontal) ou alturas (para formato vertical) preferidas. Para um formato horizontal, se nem todos os componentes são da mesma altura, o gerenciador tenta 32 fazer todos os componentes tão altos quanto o componente mais alto. Se isso não é possível para um componente específico, então o gerenciador alinha o tal componente verticalmente, de acordo com o alinhamento Y do componente. Por padrão, um componente tem seu alinhamento Y de 0,5, o que significa que o centro vertical do componente deve ter a mesma coordenada Y dos centros verticais dos outros componentes com alinhamento Y igual a 0,5. Da mesma maneira, para um formato vertical, o Gerenciador de Leiaute de Caixa tenta fazer todos os componentes na coluna tão largos quanto o componente mais largo. Se isso não é possível, ele os alinha horizontalmente de acordo com seus alinhamentos X. Para formato PAGE_AXIS, o alinhamento horizontal é feito baseado na extremidade inicial do componente. Em outras palavras, um valor de alinhamento X de 0,0 significa a extremidade esquerda de um componente se a propriedade ComponentOrientation do contêiner é da esquerda para a direita e, caso contrário, a extremidade direita do componente. Em vez de usarem o Gerenciador de Leiaute de Caixa diretamente, muitos programas usam a classe Box (pacote javax.swing). Objetos da classe Box são contêineres que usam um Gerenciador de Leiaute de Caixa. Ela também fornece métodos úteis para ajudar você a usar bem o Gerenciador de Leiaute de Caixa. Adicionar componentes a várias caixas aninhadas é um modo poderoso para obter a disposição desejada. 2.3.5 – Gerenciador de Leiaute do tipo Cartão Um Gerenciador de Leiaute do tipo Cartão trata cada componente no contêiner como se fosse um cartão. Somente um cartão é visível por vez e o contêiner funciona como um maço de cartões. O primeiro componente adicionado ao Gerenciador de Leiaute do tipo Cartão é o componente visível quando o contêiner é exibido pela primeira vez. Figura 17 – Representação do maço de cartões A ordem dos cartões é determinada pela própria ordem interna dos componentes do contêiner. O gerenciador de cartão define um conjunto de métodos que permitem a um aplicativo navegar através dos cartões seqüencialmente, ou mostrar um cartão específico. O 33 método addLayoutComponent pode ser usado para associar um identificador textual a certo cartão para acesso rápido e aleatório. A Listagem 6 mostra um programa Java que utiliza o Gerenciador de Leiaute do tipo Cartão mostrando uma figura em cada um dos seus cartões. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ExemploLeiauteDeCartao extends JApplet { public void init() { final CardLayout cardLayout = new CardLayout(); final JPanel centerPanel = new JPanel(cardLayout), southPanel = new JPanel(); Icon[] steps = { new ImageIcon("images/duke1.jpg", "Antes" ), new ImageIcon("images/duke2.jpg", "Durante"), new ImageIcon("images/duke3.jpg", "Depois" ) }; String message; for (Icon next : steps) { centerPanel.add( new JLabel(next, JLabel.CENTER), next.toString()); } String[] buttonsName = {"|< Primeiro", "< Anterior" , "Próximo >" , "Último >|"} ; ActionListener l = new ActionListener() { public void actionPerformed(ActionEvent ev) { String command = ev.getActionCommand(); if (command.equals("|< Primeiro")) cardLayout.first(centerPanel); else if (command.equals("< Anterior")) cardLayout.previous(centerPanel); else if (command.equals("Próximo >")) cardLayout.next(centerPanel); else if (command.equals("Último >|")) cardLayout.last(centerPanel); } }; JButton button; for (String next : buttonsName) { button = new JButton(next); button.addActionListener(l); southPanel.add(button); } setLayout(new BorderLayout()); add(centerPanel, BorderLayout.CENTER); add(southPanel, BorderLayout.SOUTH); } public static void main(String[] args) { JFrame browser = new JFrame("Exemplo do Leiaute de Cartão"); JApplet applet = new ExemploLeiauteDeCartao(); // Altera o modo de leitura applet.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); 34 69 70 71 72 73 74 75 } 76 } browser.add(applet); applet.init(); browser.pack(); browser.setBounds(150, 150, 500, 300); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); Figura 18 – Progr. Ex. do Leiaute do tipo Cartão 1 Figura 19 – Progr. Ex. do Leiaute do tipo Cartão 2 Figura 20 – Progr. Ex. do Leiaute do tipo Cartão 3 Nesse caso o valor da propriedade ComponentOrientation não afetará a interface gráfica do programa, pois o Gerenciador de Leiaute do tipo Cartão não utiliza o mesmo método de disposição horizontal como os outros Gerenciadores de Leiaute. 2.3.6 – Gerenciador de Leiaute de Grade Dinâmico Gerenciador de Leiaute de Grade Dinâmico são aqueles que alinham os componentes verticalmente e horizontalmente, sem exigir que os componentes sejam do mesmo tamanho. Cada Gerenciador de Leiaute de Grade Dinâmico mantém uma grade retangular dinâmica de células, com cada componente ocupando uma ou mais células, chamada sua área de exibição. Cada componente gerenciado por um Gerenciador de Leiaute de Grade Dinâmico é associado com uma instância da classe GridBagConstraints. O objeto de restrições especifica onde uma área de exibição de componente deve ser localizada na grade e como o componente deve ser posicionado dentro de sua área de exibição. Além do objeto de restrições, o Gerenciador de Leiaute de Grade Dinâmico também considera os tamanhos mínimo e preferido de cada componente de forma a determinar o tamanho do componente. A direção geral da grade depende da propriedade ComponentOrientation do contêiner. Para direções horizontais da esquerda para a direita, a coordenada (0,0) da grade está no canto superior esquerdo do contêiner com x crescendo para a direita e y crescendo para baixo. Para direções horizontais da direita para a esquerda, a coordenada (0,0) da grade 35 está no canto superior direito do contêiner com x crescendo para a esquerda e y crescendo para baixo. Para usar efetivamente um Gerenciador de Leiaute de Grade Dinâmico, você deve ajustar um ou mais dos objetos restrições que são associados com seus componentes. Você ajusta um objeto de restrições configurando uma ou mais de suas variáveis de instância: • GridBagConstraints.gridx; • GridBagConstraints.gridy. Ambos definem uma célula contendo o canto inicial da área de exibição do componente, onde a célula localizada na origem da grade tem endereço gridx = 0, gridy = 0. Para formato horizontal da esquerda para a direita, o canto inicial do componente é seu canto superior esquerdo. Para formato horizontal da direita para a esquerda, o canto inicial do componente é seu canto direito. Use GridBagConstraints.RELATIVE (o valor inicial) para especificar que o componente seja posicionado imediatamente depois (ao longo do eixo x para gridx ou do eixo y para gridy) do último componente adicionado ao contêiner. • GridBagConstraints.gridwidth; • GridBagConstraints.gridheight. Definem o número de células numa linha (para gridwith) ou coluna (para gridheight) na área de exibição do componente. O valor inicial é 1. Use GridBagConstraints.REMAINDER para especificar que a área de exibição do componente será de gridx até a última célula na linha (para gridwidth) ou de gridy até a última célula na coluna (para gridheight). Use GridBagConstraints.RELATIVE para especificar que a área de exibição do componente será de gridx até a antepenúltima célula na sua linha (para gridwidth) ou de gridy até a penúltima célula na sua coluna (para gridheight). • GridBagConstraints.fill; Usada quando a área de exibição do componente é maior que o tamanho exigido pelo componente para determinar se (e como) redimensionar o componente. Valores possíveis para essa restrição são: GridBagConstraints.NONE (o padrão), 36 GridBagConstraints.HORIZONTAL (torna o componente largo o suficiente para preencher sua área de exibição horizontalmente, mas não muda sua altura), GridBagConstraints.VERTICAL (torna o componente alto o suficiente para preencher sua área de exibição verticalmente, mas não muda sua largura) e GridBagConstraints.BOTH (faz o componente preencher sua área de exibição totalmente). • GridBagConstraints.ipadx; • GridBagConstraints.ipady. Definem o enchimento interno do componente dentro do gerenciador, ou seja, quanto adicionar ao tamanho mínimo do componente. A largura do componente será pelo menos sua largura mínima mais ipadx pixels. De maneira similar, a altura do componente será pelo menos a altura mínima mais ipady pixels. • GridBagConstraints.insets; Define o enchimento externo do componente, isto é, a quantidade mínima de espaço entre o componente e as extremidades de sua área de exibição. • GridBagConstraints.anchor; Usada quando o componente é menor que sua área de exibição para determinar onde (dentro da área de exibição) posicionar o componente. Há dois tipos de valores possíveis: relativos e absolutos. Valores relativos são interpretados de acordo com a propriedade ComponentOrientation do contêiner enquanto valores absolutos não são. Os valores válidos são: 37 • Valores absolutos GridBagConstraints.NORTH • Valores relativos GridBagConstraints.PAGE_START • GridBagConstraints.SOUTH • GridBagConstraints.PAGE_END • GridBagConstraints.WEST • GridBagConstraints.LINE_START • GridBagConstraints.EAST • GridBagConstraints.LINE_END • GridBagConstraints.NORTHWEST • GridBagConstraints.NORTHEAST • GridBagConstraints.SOUTHWEST • GridBagConstraints.SOUTHEAST • GridBagConstraints.CENTER (o padrão) Tabela 1 – Valores do Gerenciador de Leiaute de Grade Dinâmico • GridBagConstraints.weightx; • GridBagConstraints.weighty. Usados para determinar como distribuir espaço, o que é importante para especificar o comportamento durante redimensionamentos. Se um peso não for especificado para pelo menos um componente numa linha (weightx) e coluna (weighty), todos os componentes aglutinar-se-ão no centro do contêiner. Isso ocorre, pois, quando o peso é zero (o padrão), o Gerenciador de Leiaute de Grade Dinâmico coloca qualquer espaço extra entre sua grade de células e as extremidades do contêiner. A Listagem 5 mostra o código de um programa Java que possui dez componentes gerenciados pelo Gerenciador de Leiaute de Gerenciador de Grade Dinâmico. 1 2 import java.awt.*; 3 import javax.swing.*; 4 5 public class ExemploLeiauteDeGradeDinamico extends JApplet { 6 7 public void init() { 8 GridBagLayout gbLayout = new GridBagLayout(); 9 GridBagConstraints constraints = new GridBagConstraints(); 10 11 setLayout(gbLayout); 12 13 JButton b1 = new JButton("Botão 1"), 14 b2 = new JButton("Botão 2"), 15 b3 = new JButton("Botão 3"), 16 b4 = new JButton("Botão 4"), 38 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 } b5 b6 b7 b8 b9 b10 = = = = = = new new new new new new JButton("Botão JButton("Botão JButton("Botão JButton("Botão JButton("Botão JButton("Botão 5"), 6"), 7"), 8"), 9"), 10"); constraints.weightx = 1; constraints.weighty = 1; constraints.fill = GridBagConstraints.BOTH; gbLayout.setConstraints(b1, constraints); add(b1); gbLayout.setConstraints(b2, constraints); add(b2); gbLayout.setConstraints(b3, constraints); add(b3); // nova linha constraints.gridwidth = GridBagConstraints.REMAINDER; gbLayout.setConstraints(b4, constraints); add(b4); gbLayout.setConstraints(b5, constraints); add(b5); // retorna ao padrão constraints.gridwidth = GridBagConstraints.RELATIVE; gbLayout.setConstraints(b6, constraints); add(b6); // nova linha constraints.gridwidth = GridBagConstraints.REMAINDER; gbLayout.setConstraints(b7, constraints); add(b7); // retorna ao padrão constraints.gridwidth = GridBagConstraints.RELATIVE; // ocupa duas células na vertical constraints.gridheight = 2; gbLayout.setConstraints(b8, constraints); add(b8); // retorna ao padrão constraints.gridheight = 1; // nova linha constraints.gridwidth = GridBagConstraints.REMAINDER; gbLayout.setConstraints(b9, constraints); add(b9); gbLayout.setConstraints(b10, constraints); add(b10); } public static void main(String[] args) { JFrame browser = new JFrame("Exemplo do Leiaute de Grade Dinâmico"); JApplet applet = new ExemploLeiauteDeGradeDinamico(); // Altera o modo de leitura applet.applyComponentOrientation( ComponentOrientation.LEFT_TO_RIGHT); browser.add(applet); applet.init(); browser.pack(); browser.setBounds(200, 150, 400, 300); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); } 39 94 Listagem 6 – Código demonstrando o Gerenciador de Leiaute de Grade Dinâmico A figura 21 mostra um programa com dez botões gerenciados por um Gerenciador de Leiaute de Grade Dinâmico que possui a propriedade ComponentOrientation com o valor de LEFT_TO_RIGHT. A figura 22 mostra o mesmo programa com sua interface redimensionada. A figura 23 mostra o programa com sua interface em tamanho original, porém com a propriedade ComponentOrientation valendo RIGTH_TO_LEFT. A figura 24 mostra o programa da figura 23 com sua interface redimensionada. Figura 21 – Progr. Ex. do Leiaute de Grade Dinâmico1 Figura 22 – Progr. Ex. do Leiaute de Grade Dinâmico2 Figura 23 – Progr. Ex. do Leiaute de Grade Dinâmico3 Figura 24 – Progr. Ex. do Leiaute de Grade Dinâmico4 40 Cada um dos dez componentes tem a variável de preenchimento de seu objeto GridBagConstraints associado configurado para GridBagConstraints.BOTH. Além disso, os componentes tiveram as seguintes restrições alteradas: • Botões 1, 2 e 3: weightx = 1,0 • Botão 4: weightx = 1,0, gridwidth = GridBagConstraints.REMAINDER • Botão 5: gridwidth = GridBagConstraints.REMAINDER • Botão 6: gridwidth = GridBagConstraints.RELATIVE • Botão 7: gridwidth = GridBagConstraints.REMAINDER • Botão 8: gridheight = 2, weighty = 1.0 • Botões 9 e 10: gridwidth = GridBagConstraints.REMAINDER 2.3.7 – Gerenciador de Leiaute do tipo Mola O Gerenciador de Leiaute do tipo Mola dispõe os componentes do seu contêiner associado de acordo com um conjunto de restrições. Cada restrição, representada por um objeto mola, controla a distância vertical ou horizontal entre duas extremidades de componente. As extremidades podem ser referentes a qualquer componente do contêiner ou ao próprio contêiner. Por exemplo, a largura permitida de um componente pode ser expressa usando uma restrição que controla a distância entre as extremidades oeste (esquerda) e leste (direita) do componente. As coordenadas y permitidas para um componente podem ser expressas restringindo a distância entre a extremidade norte (topo) do componente e a extremidade norte de seu contêiner. Todo componente de um contêiner controlado por um gerenciador do tipo de mola, assim como o contêiner propriamente dito, tem exatamente um conjunto de restrições associado a ele. Essas restrições são representadas por um objeto SpringLayout.Constraints. 41 A princípio, o Gerenciador de Leiaute do tipo Mola cria restrições que tornam seu componente associado ter os tamanhos mínimo, preferido e máximo retornado pelos métodos: • Component.getMinimumSize() • Component.getPreferredSize() • Component.getMaximumSize() As posições x e y não são inicialmente delimitadas, então até que você os restrinja o componente será posicionado na posição 0,0 relativa à borda do contêiner pai. As restrições do componente podem ser alteradas de vários modos. Pode-se usar um dos métodos putConstraint para estabelecer uma mola conectando as extremidades de dois componentes dentro do mesmo contêiner. Ou pode-se obter o objeto SpringLayout.Constraints apropriado usando getConstraints e então modificando um ou mais de suas molas. Ou pode-se obter uma mola para uma extremidade particular de um componente usando getConstraint e modifica-la. Pode-se também associar seu próprio objeto SpringLayout.Constraints com um componente especificando o objeto restrição quando você adiciona o componente ao contêiner (usando Container.add(Component, Object)). O objeto mola representando cada restrição tem valores mínimo, preferido, máximo e atual. O valor atual da mola é algo entre os valores mínimo e máximo, de acordo com a fórmula dada na descrição do método Spring.sum(Spring, Spring). Quando os valores mínimo, preferido e máximo são os mesmos, o valor atual é sempre igual a eles; esta mola não flexível é chamada de strut. Você pode criar struts usando o método utilitário Spring.constant(int). A classe Spring também oferece métodos utilitários para criar outros tipos de molas, incluindo molas que dependem de outras molas. Num Gerenciador de Leiaute de Mola, a posição de cada extremidade é dependente da posição de uma outra extremidade. Se uma restrição é adicionada várias vezes para criar um novo vínculo para uma extremidade, o vínculo anterior é descartado e a extremidade permanece dependente numa extremidade única. Molas somente devem ser anexadas entre extremidades do contêiner e seus componentes filhos; o comportamento de um gerenciador de mola quando configurado com restrições conectando as extremidades de componentes de contêiner diferentes (internos ou externos) é indefinido. 42 A Listagem 7 mostra um programa Java que implementa um programa que gerencia os componentes de sua interface gráfica fazendo uso do Gerenciador de Leiaute de Mola. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import java.awt.*; import javax.swing.*; public class ExemploLeiauteDeMola extends JApplet { public void init() { SpringLayout sLayout = new SpringLayout(); setLayout(sLayout); JPanel contentPane = (JPanel) this.getContentPane(); JLabel label = new JLabel("Rótulo: "); JTextField field = new JTextField(2); add(label); add(field); // Ajusta linha da caixa de texto // Norte da caixa de texto ficará 15 linhas abaixo //do norte do painel sLayout.putConstraint(SpringLayout.NORTH, field, 15, SpringLayout.NORTH, contentPane); // Ajusta coluna da caixa de texto // Lado direito da caixa de texto ficará 15 colunas // antes do lado direito do painel sLayout.putConstraint(SpringLayout.EAST, field, -15, SpringLayout.EAST, contentPane); // Ajusta linha do rótulo // Norte do rótulo ficará 15 linhas abaixo do norte do painel sLayout.putConstraint(SpringLayout.NORTH, label, 15, SpringLayout.NORTH, contentPane); // Ajusta coluna do rótulo // Lado direito do rótulo ficará 15 colunas antes do lado // esquerdo da caixa de texto sLayout.putConstraint(SpringLayout.EAST, label, -15, SpringLayout.WEST, field); } public static void main(String[] args) { JFrame browser = new JFrame("Exemplo do Leiaute de Mola"); JApplet applet = new ExemploLeiauteDeMola(); // Altera o modo de leitura applet.applyComponentOrientation( ComponentOrientation.LEFT_TO_RIGHT); browser.add(applet); applet.init(); browser.pack(); browser.setBounds(200, 150, 400, 300); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.setVisible(true); } } Listagem 7 – Código demonstrando o Gerenciador de Leiaute de Mola No exemplo acima o valor da propriedade ComponentOrientation não afetará a aparência da interface gráfica do programa. Isso acontece, pois o Gerenciador de Leiaute de Mola utiliza posicionamento relativo para manter os componentes na tela. O resultado gerado pelo programa da Listagem 7, pode ser visto nas figuras 25 e 26, que mostram respectivamente o programa em seu tamanho original e depois de ser redimensionado. 43 Figura 25 – Progr. Ex. do Leiaute do tipo Mola1 Figura 26 – Progr. Ex. do Leiaute do tipo Mola2 A despeito da simplicidade do Gerenciador de Leiaute de Mola, ele pode simular o comportamento da maioria dos outros gerenciadores de leiaute. Para algumas características, como a quebra de linha fornecida pelo Gerenciador de Leiaute de Fluxo, você precisará criar uma subclasse específica da classe Spring. O Gerenciador de Leiaute de Mola também oferece um modo de resolver muitos dos problemas de gerenciamento que não podem ser resolvidos através do aninhamento de Boxes. Isso significa que o gerenciador de mola segue corretamente o contrato estabelecido pela interface LayoutManager2 e então pode ser aninhado com outros gerenciadores de leiaute: uma técnica que pode ser preferível a criar as restrições exigidas pelos outros gerenciadores de leiaute. 44 Parte 3 – Problema 3.1 – Descrição Existem duas abordagens para desenvolvimento de telas: • ignorar completamente a consistência das telas produzidas; • conviver com a baixa produtividade resultante do uso dos Gerenciadores de Leiaute. Usando posicionamento-dimensionamento absoluto, por exemplo, é possível montar interfaces gráficas rapidamente definindo a posição e o tamanho dos componentes, mas os elementos da interface gráfica podem se deformar. Ao redimensionar a tela ou mesmo alterar a resolução do vídeo, ela se deforma. Em Java, é possível diminuir a deformação, mas isso é feito a um custo muito alto de produtividade: • É preciso que o desenvolvedor domine profundamente todos os gerenciadores de leiaute existentes; • É preciso descobrir qual é a combinação de gerenciadores que produz a aparência desejada. Cada interface gráfica exige uma combinação diferente de gerenciadores para manter-se indeformável. Há vários Gerenciadores de Leiaute e cada um possui suas peculiaridades. Conhecer a fundo todos eles é uma tarefa que demanda tempo por parte do desenvolvedor, mas esse é um tempo que só precisa ser gasto uma vez. Descobrir a combinação ideal dos gerenciadores, entretanto, é uma tarefa que demanda tempo toda vez que uma nova tela precisa ser construída. O resultado de tamanha complexidade é o inevitável comprometimento da produtividade. Para fugir dele, a maioria dos desenvolvedores Java acabam, na prática, 45 ignorando os gerenciadores de formato e usando simplesmente o posicionamentodimensionamento absoluto, permitindo, assim, a deformação das telas que produzem. 46 Parte 4 – Solução Para resolver o problema este problema adotou-se a seguinte solução: reunir a objetividade do posicionamento-dimensionamento absoluto e a consistência dos gerenciadores de tela. Esta solução evita o trabalho de definir qual é a combinação de gerenciadores ideal para manter consistente cada tela produzida. 4.1 – Análise de mercado Nessa seção serão apresentadas as principais soluções disponíveis hoje para o problema do desenvolvimento de telas consistentes. 4.1.2 – Cafeteira O Cafeteira (ANSELMO, 2005) é uma ferramenta nacional para a montagem de telas. Escrita inicialmente em Delphi (ANSELMO2, 2005), ela foi portada em 2002 para Java, o que a tornou multiplataforma. Ambientes gráficos para Java em geral consomem muita memória. O Cafeteira, porém, é diferente. Extremamente pequeno (cabe em um único disquete), o programa diferencia-se dos equivalentes por consumir pouca memória principal do computador. Os principais componentes Swing são suportados: JLabel, JTextField, JPasswordField, JButton, JList, JTextArea, JRadioButton, JCheckBox e JComboBox. E, além disso, a ferramenta também gera código para menus horizontais pendurados. A disposição dos componentes na tela é feita de maneira prática ao estilo arrastar-esoltar. Todo código necessário é gerado automaticamente e pode, posteriormente, ser reutilizado em qualquer outra ferramenta de desenvolvimento. O engenho do Cafeteira não usa Gerenciadores de Leiaute. O código gerado por ele baseia-se, portanto, na abordagem do posicionamento-dimensionamento absoluto dos componentes. 47 Figura 27 – Cafeteira, sua interface e um exemplo. O software cumpre excepcionalmente bem o papel a que se propõe – ele facilita bastante o trabalho da montagem de telas e da associação de eventos aos componentes. Entretanto, como o engenho dele não usa Gerenciadores de Leiaute, as interfaces gráficas produzidas são passíveis de deformação. 48 Figura 28 – O código da classe, gerado pelo Cafeteira. 49 Figura 29 – Código da Janela, gerado pelo Cafeteira. 4.1.3 – Projeto Matisse Em Maio de 2005, Gregg Sporar e sua namorada visitaram a Coleção Barnes de arte impressionista e pós-impressionista. Ela contém uma das coleções particulares mais incríveis do mundo. Conferi-la de perto foi uma experiência gratificante para o casal, principalmente pela oportunidade de admirarem as obras de Matisse. Henri Matisse (WIKIPEDIA, 2005) foi um gênio e um artista de talento imensurável. Como um dos fundadores e líderes da arte moderna no século passado, ele foi alguém à frente do seu tempo. Sua pintura tinha um estilo forte, com cores vivas que passavam imediatamente uma mensagem ao observador. 50 De volta da viagem, Gregg, ainda encantado com o que havia visto, resolveu dar à luz um antigo sonho. Ele iniciou um projeto para o desenvolvimento de um novo construtor de telas para o ambiente gráfico NetBeans, o qual batizou de Projeto Matisse (SPORAR, 2005). Uma parte da construção de telas em Java que Gregg nunca gostou é a configuração do Gerenciador de Leiaute. Os ambientes gráficos facilitam o ajuste, mas não o dispensam. O objetivo do Projeto Matisse é eliminar completamente a complexidade e garantir que, no momento da execução, a aparência seja sempre a mesma. Depois do projeto Matisse, será possível construir telas no NetBeans em poucos minutos; toda configuração será feita apenas através do mouse. Não haverá mais a necessidade de se ajustar margens, âncoras, etc. O Matisse resolve o problema dos gerenciadores eliminando a complexidade associada ao uso deles. Ele, entretanto, é apenas um módulo para o IDE NetBeans e, portanto, não poderá ser usado em outras ferramentas gráficas ou mesmo via bloco de notas. 4.2 – O TransparenLayout Pensando em uma solução que reúna o melhor do posicionamento-dimensionamento absoluto com o melhor dos gerenciadores de leiaute e que ainda possa ser usada em qualquer ferramenta3, chegamos à conclusão que devemos criar um novo Gerenciador de Leiaute, um gerenciador que permita aos desenvolvedores o posicionamento-dimensionamento absoluto dos componentes, mas que realize automaticamente todo o processamento necessário para o reposicionamento e o redimensionamento dos componentes. Além das três características principais que se espera de qualquer Gerenciador de Leiaute (posicionar os componentes dentro do contêiner, dimensionar os componentes dentro do contêiner, adaptar a tela ao modo de leitura local), foi adicionado ao TransparentLayout, como um diferencial inovador, o redimensionamento de texto. O texto dos componentes da Da maneira como a solução (TransparentLayout) é apresentada, ela pode ser vista como uma extensão da plataforma Java. Dessa maneira ela pode ser utilizada em qualquer ferramenta, quer essa ferramenta seja um simples editor de texto ou quer seja tal ferramenta um Ambiente de Desenvolvimento Integrado. E para tanto basta que o pacote do TransparenteLayout seja importado. 3 51 tela também será aumentado ou diminuído em proporção igual à alteração sofrida pelo componente que contem o texto. A principal característica do novo gerenciador é a transparência de sua atuação. Por essa razão, portanto, ele foi chamado de TransparentLayout. Com isso, temos o objetivo de facilitar e agilizar o desenvolvimento de telas consistentes em Java. 4.2.1 – Levantamento de Requisitos No trabalho de análise foram identificados os seguintes requisitos: 1. O TransparentLayout deve controlar automaticamente o tamanho dos componentes inseridos no Container à qual o TransparentLayout foi anexado conforme esse Container sofrer redimensionamento, seja pelo usuário final, ou seja, pelo Sistema Operacional; 2. O TransparentLayout deve controlar automaticamente a posição dos componentes inseridos no Container à qual o TransparentLayout foi anexado conforme esse Container sofrer redimensionamento, seja pelo usuário final, ou seja, pelo Sistema Operacional; 3. O TransparentLayout deve redimensionar o tamanho dos textos de todos os componentes do Container que sofrerem redimensionamento, seja pelo usuário final, ou seja, pelo Sistema Operacional; 4. O TransparentLayout deve se adaptar automaticamente ao modo de leitura local do computador que estiver executando o programa que faz uso do TransparentLayout. 5. O TransparentLayout deve agir sob os componentes de um Container de maneira transparente para o desenvolvedor, isso quer dizer que o desenvolvedor não precisará saber como o TransparentLayout faz o redimensionamento e reposicionamento dos componentes. Para o desenvolvedor deve bastar saber 52 como inserir componentes ao Container e como associar o TransparentLayout ao Container. 53 4.2.2 – Diagrama de Casos de Uso Na figura número 30 tem-se o diagrama de casos de uso correspondente ao contexto da solução proposta: Figura 30 – Diagrama de Casos de Uso do TransparentLayout O diagrama acima contempla todas as situações possíveis nas quais pode ser necessário o reajuste dos elementos que formam a tela. 4.2.3 – Documentação dos Casos de Uso Geralmente ao iniciar-se a Documentação de Casos de Uso, a primeira coisa a ser definida são as Regras do Negócio. Entretanto tal definição se encaixa melhor em sistemas da área de S.I. (Sistemas de Informação). Para o presente trabalho foi adotado o termo de Restrições ao invés de Regras do Negócio. 54 4.2.3.1 – Restrições • Restrição 1: Tamanho mínimo dos componentes. Descrição: O tamanho dos componentes não deve ser negativo. • Restrição 2: Posição mínima dos componentes. Descrição: A posição dos componentes não deve ser negativa nem no eixo das abscissas (x) nem no das ordenadas (y). • Restrição 3: Tamanho inicial da tela. Descrição: O estado inicial da tela é definido pelo Desenvolvedor. 4.2.3.2 – Descrição dos Casos de Uso Para a descrição dos Casos de Uso foi utilizada a notação de Formato Expandido. Manter Componente – CSU01 Sumário: Desenvolvedor adiciona componente na tela Ator principal: Desenvolvedor Ator secundário: Nenhum Pré-condições: O componente não faz parte da tela Fluxo principal: 1 – O Desenvolvedor adiciona uma instância de um componente à tela; 2 – O Desenvolvedor define o tamanho horizontal e vertical inicial do componente informando o quanto o componente ocupará no eixo horizontal (abscissas – x) e no eixo vertical (ordenadas – y). 3 – O Desenvolvedor define a posição inicial do componente informando o par ordenado que será a coordenada a partir de onde o componente deverá ser desenhado; Fluxo alternativo: Nenhum Fluxo de exceção: 2.1 – Violação da Restrição 1: o tamanho do componente é negativo. 2.1.1 – O componente não é adicionado à tela. 2.1.2 – Uma exceção é disparada e o processamento é interrompido. 55 3.1 – Violação da Restrição 2: a posição dos componentes é negativa em qualquer um dos eixos. 3.1.1 – O componente não é adicionado à tela. 3.1.2 – Uma exceção é disparada e o processamento é interrompido. Pós-condições: O componente faz parte da tela Redimensionar Interface – CSU02 Sumário: Usuário redimensiona a tela do programa Ator principal: Usuário Ator secundário: Nenhum Pré-condições: O programa possui interface gráfica definida. Fluxo principal: 1 – O Usuário redimensiona a tela do programa seja arrastando manualmente as bordas da janela que contém a interface do programa, ou seja, fazendo uso dos recursos de expansão e diminuição de janelas (ex: maximizar, minimizar, restaurar) oferecidos pelo S.O. (Sistema Operacional). Fluxo alternativo: Nenhum Fluxo de exceção: Nenhum Pós-condições: A tela do programa assume as dimensões de acordo com a ação tomada pelo Usuário. Alterar Resolução do Monitor - CSU03 Sumário: Usuário altera a resolução de vídeo através do S.O. (Sistema Operacional). Ator principal: Usuário Ator secundário: S.O. (Sistema Operacional) Pré-condições: A nova resolução é suportada pelo monitor de vídeo Fluxo principal: 1 – O Usuário requisita a alteração da resolução de vídeo através da opção específica do S.O., informando a ele a nova resolução a ser usada pelo monitor; 2 – O S.O.(Sistema Operacional) altera resolução de vídeo para a nova configuração informada pelo usuário. Fluxo alternativo: Nenhum Fluxo de exceção: 2.1 – A resolução de vídeo informada pelo usuário está acima da capacidade gráfica do monitor; 56 2.2 – O S.O.(Sistema Operacional) restaura a resolução anterior. Pós-condições: A resolução de vídeo é alterada pelo O S.O.(Sistema Operacional). Ajustar Componente – CSU04 Sumário: O Engenho do TransparentLayout ajusta os componentes às novas condições de exibição Ator principal: Nenhum Ator secundário: Nenhum Pré-condições: O Usuário redimensionou a janela que contém a interface do programa seja arrastando as bordas da janela, ou seja, fazendo uso dos recursos de expansão e diminuição de janelas (ex: maximizar, minimizar, restaurar) oferecidos pelo S.O.(Sistema Operacional) ou seja através da alteração da resolução do monitor através da opção específica do S.O.(Sistema Operacional) Fluxo principal: 1 – O Engenho do TransparentLayour calcula proporção entre o valor atual e o inicial da largura da tela; 2 – O Engenho do TransparentLayout escalona valores de x e da largura dos componentes pela proporção encontrada no eixo das abscissas; 3 – O Engenho do TransparentLayout calcula proporção entre o valor atual e o inicial da altura da tela; 4 – Engenho escalona valores de y e da altura dos componentes pela proporção encontrada no eixo das ordenadas. Fluxo alternativo: 2.1 Se modo de leitura é diferente do modo de leitura original 2.1.1 Altera valor de x para “largura da tela vezes largura do componente” Fluxo de exceção: Nenhum Pós-condições: Os componentes assumem tamanho e posição na interface de acordo com a proporção do redimensionamento provocado. 57 4.3 – Diagrama de Classes Por uma questão de riqueza semântica, no Diagrama de Classes a seguir foram adicionados os métodos e atributos mais relevantes das classes da aplicação. Figura 31 – Diagrama de Classes do TransparentLayout Os métodos e atributos serão utilizados na próxima seção nos comentários feitos em cada um dos Diagramas de Seqüência que serão apresentados. 58 4.4 – Diagramas de Seqüência Os diagramas de seqüência são desenvolvidos a partir dos Casos de Uso. Nas seções seguintes são apresentados os diagramas de seqüência desta aplicação. 4.4.1 – Diagrama de Seqüência #1 – Manter Componente Figura 32 – Diagrama de Seqüência #1 – Manter Componente O Desenvolvedor adiciona um componente a tela através do método add() do objeto Container, passando como parâmetros para este método os objetos comp e bounds, que são respectivamente objetos da classe Component e Rectangle. O objeto comp representa o componente em si e o objeto bounds representa, ao mesmo tempo, o tamanho e a posição do componente. 59 Após a chamada do método add(), a Máquina Virtual Java invocará automaticamente o método addLayoutComponent(), que registra no Gerenciador de Leiaute associado ao objeto Container da tela o componente (comp) passado como parâmetro, juntamente com seu tamanho e posição (bounds). O método addLayoutContainer() verifica se o objeto bounds já foi instanciado checando se o valor da sua referência é null. Caso seja verificado que o objeto bounds não instanciado então será instanciado um novo objeto da classe Rectangle e sua referência será atribuída à bounds. Pode acontecer do objeto bounds já ter sido instanciado, porém que seja instância de outra classe que não seja Rectangle. Se isso acontecer então será disparada um exceção do tipo IllegalArgumentException que terminará o processamento emitindo a seguinte mensagem: Cannot add to layout: bounds must be Rectangle, ou seja, Não é possível adicionar ao leiaute: bounds deve ser Rectangle. Caso a referência de bounds seja diferente de null e caso bounds seja uma instância de Rectangle, então o processamento continuará normalmente e o próximo método a ser chamado é setOriginalComponentBounds(), que guarda em uma estrutura de dados do tipo HashTable (Tabela de Hash ou Tabela de dispersão) o valor original do tamanho e posição do componente que está sendo adicionado ao leiaute. Os valores de tamanho e posição serão armazenados somente se não forem negativos, pois se forem, vão disparar uma exceção do tipo IllegalArgumentException. E caso a largura ou a altura do objeto sejam iguais a zero então esses valores serão armazenados na estrutura HashTable com seus valores de tamanho preferidos (preferred size). 4.4.2 – Diagrama de Seqüência #2 – Redimensionar Interface 60 Figura 33 – Diagrama de Seqüência #2 – Redimensionar Interface Quando o Usuário redimensionar a janela do programa que contem sua interface gráfica, o método componentResized() será invocado automaticamente para representar o evento de notificação (SUN2, 2005) de redimensionamento do objeto contêiner. Após a execução do método componentResized(), o método doLayout() é automaticamente invocado (SUN3, 2005) indicando que o Gerenciador de Leiaute associado ao contêiner que sofreu redimensionamento deverá dispor seus componentes de acordo com sua lógica interna. A disposição dos componentes será tratada em seguida pelo método layoutContainer() que é o método central do TransparentLayout, representando seu engenho, responsável por efetuar todo o trabalho de redimensionamento e posicionamento dos componentes que estiverem contidos no contêiner associado ao TransparentLayout. 4.4.3 – Diagrama de Seqüência #3 – Alterar Resolução do Monitor 61 Figura 34 – Diagrama de Seqüência #3 – Alterar Resolução do Monitor Deve-se perceber que o método alterarResoluçãoDoMonitor, bem como os atributos presentes em sua assinatura (altura e largura) são meramente ilustrativos dentro do processo de seqüência de chamadas de métodos para o caso de uso Alterar Resolução do Monitor. A alteração da resolução do monitor está fora do escopo do TransparentLayout, mas mesmo assim necessitamos representar a sucessão dos métodos que disparam os eventos (representados por métodos) para o TransparentLayout executar o reposicionamento e redimensionamento dos componentes presentes na tela. Efetivamente a interação do programa com o TransparentLayout começa a partir do momento em que o método componentResized() é invocado automaticamente para notificar o redimensionamento do contêiner. Após a chamada do método componentResized(), o método doLayout() é invocado, também automaticamente, para indicar que o Gerenciador de Leiaute associado ao contêiner deve dispor seus componentes. Isso é executado pelo método layoutContainer() que é chamado logo após doLayout(). 62 4.4.4 – Diagrama de Seqüência #4 – Ajustar Componente Figura 35 – Diagrama de Seqüência #4 – Ajustar Componente Esse é o diagrama de seqüência correspondente ao engenho do TransparentLayout. Este pequeno diagrama de seqüência aparece em outros dois que o usam (através do estereótipo <<include>>, vide diagrama de casos de uso). Como se pode perceber pela ilustração, todo trabalho referente ao redimensionamento e reposicionamento dos componentes será executado pelo método layoutContainer(). 63 4.5 – Implementação4 O programa Java a seguir foi desenvolvido usando a última versão disponível da plataforma Java (J2SE). A versão em questão é 1.5 ou simplesmente 5 e foi usada em conjunto com o Ambiente de Desenvolvimento Integrado NetBeans 4.1. Apesar de o programa ter sido desenvolvido utilizando-se a versão 5 de Java, este somente faz uso de recursos que se encontram disponíveis desde as primeiras versões de Java. Dessa maneira o TransparentLayout pode ser executado em qualquer versão da máquina virtual Java. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 4 /** * @(#)TransparentLayout.java 1.0rc5 05/11/13 * * Copyright (C) 2005 Dante (Everton B. G.) * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * The GNU Lesser General Public License can be read at: * http://www.gnu.org/copyleft/lesser.html * * Contact the author by either typing a message to evertonbg at gmail.com, or * writing one to Everton Gomes, 156 Liberty St, Osasco, SP 06110-050 BR */ package net.java.dev.transparentlayout; import import import import import import import import import java.awt.LayoutManager2; java.awt.Container; java.awt.Component; java.awt.ComponentOrientation; java.awt.Rectangle; java.awt.Insets; java.awt.Dimension; java.awt.Font; java.awt.AWTError; // AWT 1.1 compatible import java.util.Hashtable; import java.util.Enumeration; /** * <p>A straightforward layout manager for Java AWT/Swing toolkit that infers * the appropriate resizing behavior from the original component bounds, * freeing the developers from the complexities of layout managers.</p> * <p>It implements the LayoutManager2 interface to support a brand new * "Free Design" paradigm.</p> * <p>Set only the original component bounds (x, y, width, height) and * TransparentLayout works for you. </p> * <p>The solution can be used either in command-line tools or * in graphical ones.</p> * * @author Dante (E.B.G.) * * @version 1.0rc5, 11/13/05 * Description: Rewrote to target release 1.1. * * @version 1.0rc4, 11/12/05 * Description: Better nesting support. Vide também o Apêncide no final deste trabalho para a Javadoc do TransparentLayout 64 57 * 58 * @version 1.0rc3, 11/02/05 59 * Description: Improved insets support. 60 * 61 * @version 1.0rc2, 10/29/05 62 * Description: Improved preferred container size support. 63 * 64 * @version 1.0rc1, 10/13/05 65 * Description: Added preferred component size support. 66 * 67 * @version 1.0beta2, 10/11/05 68 * Description: Added preferred container size support. 69 * 70 * @version 1.0beta, 10/09/05 71 * Description: Added font resizing support. 72 * 73 * @version 0.1alpha, 06/28/05 74 * Description: First draft submitted to Sun ( 75 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6292168), 76 * i18n already supported. 77 * 78 * @see java.awt.Rectangle 79 * @see java.awt.ComponentOrientation 80 */ 81 public class TransparentLayout implements LayoutManager2, 82 java.io.Serializable 83 { 84 /** 85 * Target container 86 */ 87 private Container target; 88 89 /** 90 * Original viewable area 91 * 92 * @see #getOriginalViewableArea() 93 */ 94 private Dimension originalViewableArea; 95 96 /** 97 * This field holds a dimension instance 98 * containing the preferred viewable area, so if a JFrame 99 * does not have a dimension associated with 100 * it, then the JFrame will be assigned a 101 * copy of the <code>preferredViewableArea</code> + insets. 102 * 103 * @see #preferredLayoutSize(java.awt.Container) 104 */ 105 private Dimension preferredViewableArea; 106 107 /** 108 * @see #getOriginalComponentOrientation() 109 * @see #setOriginalComponentOrientation(java.awt.ComponentOrientation) 110 */ 111 protected ComponentOrientation originalComponentOrientation; 112 113 /** 114 * This map maintains the association between 115 * a component and its original bounds. 116 * The keys in <code>originalComponentBounds</code> are the components 117 * and the values are the instances of <code>Rectangle</code>. 118 * 119 * @see #getOriginalComponentBounds(java.awt.Component) 120 * @see #setOriginalComponentBounds(java.awt.Component, java.awt.Rectangle) 121 * @see java.awt.Rectangle 122 */ 123 protected Hashtable originalComponentBounds; 124 125 /** 126 * This map maintains the association between 127 * a component and its original font size. 128 * The keys in <code>originalComponentFontSize</code> are the components 129 * and the values are the instances of <code>Integer</code>. 130 */ 131 private Hashtable originalComponentFontSize; 132 133 /** 65 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 * This * * @see * @see */ private field determines if the cached data can be used. #layoutContainer(java.awt.Container) #invalidateLayout(java.awt.Container) boolean validate; /** * Constructs a new <code>TransparentLayout</code> using * a left-to-right orientation. */ public TransparentLayout() { this(ComponentOrientation.LEFT_TO_RIGHT); } /** * Constructs a new <code>TransparentLayout</code>. * * @param originalComponentOrientation the component orientation * corresponding to children bounds. * <p>The argument must be one of the following values:<br> * <ul> * <li> ComponentOrientation.LEFT_TO_RIGHT; or </li> * <li> ComponentOrientation.RIGHT_TO_LEFT.</li> * </ul> * </p> * @see java.awt.ComponentOrientation */ public TransparentLayout(ComponentOrientation originalComponentOrientation) { setOriginalComponentOrientation(originalComponentOrientation); this.preferredViewableArea = new Dimension(); this.originalComponentBounds = new Hashtable(); this.originalComponentFontSize = new Hashtable(); this.validate = false; } /** * Gets the original component orientation. * @return the original component orientation * @see java.awt.ComponentOrientation */ public ComponentOrientation getOriginalComponentOrientation() { return this.originalComponentOrientation; } /** * Sets the original component orientation. * @param orientation the original component orientation * @see java.awt.ComponentOrientation */ public void setOriginalComponentOrientation( ComponentOrientation orientation) { this.originalComponentOrientation = orientation; } /** * Gets the bounds for the specified component. A copy of * the actual <code>Rectangle</code> object is returned. * @param comp the component to be queried * @return the bounds for the specified component in this * layout; a copy of the actual bounds * object is returned */ public Rectangle getOriginalComponentBounds(Component comp) { checkContainer(comp.getParent()); Rectangle bounds = (Rectangle) this.originalComponentBounds.get(comp); return (Rectangle)bounds.clone(); } /** 66 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 * Sets the bounds for the specified component in this layout. * Zero width or zero height means that the preferred component size will * be applied. * @param comp the component to be modified * @param bounds the bounds to be applied * @exception java.lang.IllegalArgumentException if the bounds contains * negative values. * @see #addLayoutComponent(java.awt.Component, java.lang.Object) */ public void setOriginalComponentBounds(Component comp, Rectangle bounds) { checkContainer(comp.getParent()); if (bounds.width < 0 || bounds.height < 0) { throw new IllegalArgumentException( "Cannot set bounds: width and height must be positive"); } // Sets default bounds if (bounds.width == 0 || bounds.height == 0) { Dimension preferredComponentSize = comp.getPreferredSize(); bounds.width = preferredComponentSize.width; bounds.height = preferredComponentSize.height; } this.originalComponentBounds.put(comp, (Rectangle)bounds.clone()); // Sets the original component font size Font font = comp.getFont(); int fontSize = 0; if (font != null) { fontSize = font.getSize(); } if (fontSize <= 0) { // Sets a default value fontSize = 12; } this.originalComponentFontSize.put(comp, new Integer(fontSize)); // Sets the preferred viewable area (size - insets) int leftmost = bounds.x + bounds.width, bottommost = bounds.y + bounds.height; if (leftmost > this.preferredViewableArea.width) { this.preferredViewableArea.width = leftmost; } if (bottommost > this.preferredViewableArea.height) { this.preferredViewableArea.height = bottommost; } } /** * Removes the bounds and font size for the specified component * in this layout. * @param comp the component to be modified * @see #removeLayoutComponent(java.awt.Component) */ private void removeOriginalComponentData(Component comp) { this.originalComponentBounds.remove(comp); this.originalComponentFontSize.remove(comp); } /** * Gets the original viewable area (size - insets). * * @return the original viewable area. * @see #layoutContainer(java.awt.Container) * @see javax.swing.JRootPane */ private Dimension getOriginalViewableArea() { 67 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 Dimension parentSize = this.target.getSize(); Insets parentInsets = this.target.getInsets(); if (parentSize.width <= 0 || parentSize.height <= 0) { Container nextParent = this.target.getParent(), parent = null; // Gets top level container while (nextParent != null) { parent = nextParent; nextParent = parent.getParent(); } parentSize = parent.getSize(); parentInsets = parent.getInsets(); } // Viewable area = size - insets Dimension originalViewableArea = null; if (parentSize.width > 0 && parentSize.height > 0) { originalViewableArea = new Dimension( parentSize.width - (parentInsets.left + parentInsets.right), parentSize.height - (parentInsets.top + parentInsets.bottom)); } else { originalViewableArea = this.preferredViewableArea; } return originalViewableArea; } /** * Checks if the specified container is the right one. * * @see javax.swing.JRootPane */ private void checkContainer(Container target) { if (target == null) { return; } // This avoids extra parameters in class constructor if (this.target == null) { // Sets the target this.target = target; } else if (this.target != target) { throw new IllegalArgumentException("TransparentLayout can"t be shared"); } } /** * <p>Adds the specified component to the layout, using the specified * bounds object. The bounds is a java.awt.Rectangle object.</p> * <p>Called when a component is added to a container using the * <code>Container.add</code> method with the same argument types.</p> * <p>Zero width or zero height means that the preferred component size * will be applied.</p> * @param comp the component to be added. * @param bounds a java.awt.Rectangle object that specifies * the component bounds. * @exception java.lang.IllegalArgumentException if the constraint * object is not a Rectangle. * @see java.awt.Container#add(java.awt.Component, java.lang.Object) * @see #getOriginalComponentBounds(java.awt.Component) * @see #setOriginalComponentBounds(java.awt.Component, java.awt.Rectangle) */ public void addLayoutComponent(Component comp, Object bounds) { checkContainer(comp.getParent()); if (bounds == null) 68 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 { bounds = new Rectangle(); } else if(!(bounds instanceof Rectangle)) { throw new IllegalArgumentException( "Cannot add to layout: bounds must be a Rectangle"); } setOriginalComponentBounds(comp, (Rectangle)bounds); } /** * Has no effect, since this layout manager does not use * a per-component string. */ public void addLayoutComponent(String name, Component comp) { checkContainer(comp.getParent()); } /** * Removes the specified component from this layout. * <p> * Most applications do not call this method directly. * @param comp the component to be removed. * @see java.awt.Container#remove(java.awt.Component) * @see java.awt.Container#removeAll() */ public void removeLayoutComponent(Component comp) { checkContainer(comp.getParent()); removeOriginalComponentData(comp); } /** * Returns the alignment along the x axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. * <p> * @return the value <code>0.5f</code> to indicate centered */ public float getLayoutAlignmentX(Container target) { checkContainer(target); return 0.5f; } /** * Returns the alignment along the y axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. * <p> * @return the value <code>0.5f</code> to indicate centered */ public float getLayoutAlignmentY(Container target) { checkContainer(target); return 0.5f; } /** * Gets the maximum layout size for the specified container. * @return the maximum layout size for the specified container */ public Dimension maximumLayoutSize(Container target) { checkContainer(target); return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } /** * Gets the preferred layout size for the specified container. 69 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 * @return the preferred layout size for the specified container */ public Dimension preferredLayoutSize(Container target) { checkContainer(target); // Container size = viewable area + insets Dimension preferredLayoutSize = new Dimension(this.preferredViewableArea); Insets targetInsets = this.target.getInsets(); preferredLayoutSize.width += (targetInsets.left + targetInsets.right); preferredLayoutSize.height += (targetInsets.top + targetInsets.bottom); return preferredLayoutSize; } /** * Gets the minimum layout size for the specified container. * @return the minimum layout size for the specified container */ public Dimension minimumLayoutSize(Container target) { checkContainer(target); return preferredLayoutSize(target); } /** * Invalidates the layout, indicating that if the layout manager * has cached information it should be discarded. */ public void invalidateLayout(Container target) { checkContainer(target); this.validate = false; } /** * Lays out the specified container using this layout. * This method reshapes components in the specified container in * order to satisfy the bounds of this <code>Rectangle</code> * object. * <p> * Most applications do not call this method directly. * @param target the container in which to do the layout * @see java.awt.Container * @see java.awt.Container#doLayout() */ public void layoutContainer(Container target) { checkContainer(target); if (this.originalViewableArea == null) { this.originalViewableArea = getOriginalViewableArea(); } synchronized(target.getTreeLock()) { if (!this.validate) { // Viewable area = size - insets Dimension currentViewableArea = target.getSize(); Insets targetInsets = target.getInsets(); currentViewableArea.width -= (targetInsets.left + targetInsets.right); currentViewableArea.height -= (targetInsets.top + targetInsets.bottom); if (this.originalViewableArea.width > 0 && this.originalViewableArea.height > 0) { double hScale = ((double) currentViewableArea.width) / this.originalViewableArea.width, vScale = ((double) currentViewableArea.height) / this.originalViewableArea.height; // Sets children bounds from container ones Component currentChild; ComponentOrientation currentOrientation = target.getComponentOrientation(); 70 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 } 578 579 Rectangle originalChildBounds, newChildBounds = new Rectangle(); Font newChildFont = null; // AWT 1.1 backward compatibility Enumeration keys = this.originalComponentBounds.keys(); while (keys.hasMoreElements()) { currentChild = (Component) keys.nextElement(); originalChildBounds = (Rectangle) this.originalComponentBounds.get(currentChild); newChildBounds.x = targetInsets.left + ((int)(originalChildBounds.x * newChildBounds.width = ((int)(originalChildBounds.width * newChildBounds.y = targetInsets.top + ((int)(originalChildBounds.y * newChildBounds.height = ((int)(originalChildBounds.height * hScale)); hScale)); vScale)); vScale)); // i18n if (currentOrientation.isLeftToRight() != this.originalComponentOrientation.isLeftToRight()) { newChildBounds.x = currentViewableArea.width - targetInsets.right - newChildBounds.x - newChildBounds.width; } currentChild.setBounds(newChildBounds); // Scale text newChildFont = currentChild. getFont(). deriveFont((float) ( ((Integer) this.originalComponentFontSize.get(currentChild) ).intValue() *hScale)); currentChild.setFont(newChildFont); } } } } this.validate = true; } /** * Returns a string representation of this layout values. * @return a string representation of this layout. */ public String toString() { return TransparentLayout.class.getName() + "[orientation=" + (this.originalComponentOrientation.isHorizontal()? "Horizontal": "Vertical") + "," + (this.originalComponentOrientation.isLeftToRight()? "LeftToRight": "RightToLeft") + "]"; } Listagem 8 – Implementação do TransparentLayout 71 Parte 5 – Conclusão Nessa parte serão exibidos os testes e resultados alcançados. 5.1 – Testes O TransparentLayout pode ser usado a partir de qualquer ambiente de desenvolvimento, seja ele textual (com o Notepad) ou gráfico (como o Netbeans). Não existe a necessidade de nenhuma adaptação no TransparentLayout e nem mesmo no Ambiente de Desenvolvimento (plug-in ou add-on) onde ele será usado, pois ele pode ser visto como uma extensão da própria plataforma Java. Essa facilidade de extensão da plataforma Java aparece na forma de pacotes (packages), que são conjuntos de classes que oferecem recursos para que outros programas possam ser escritos a partir delas ou fazendo uso delas. A própria plataforma Java é formada por um conjunto de pacotes de classes, separados por categorias. Para o TransparentLayout foi gerado o pacote net.java.dev.transparentlayout. Sendo que para um programa fazer uso dos recursos do TransparentLayout basta que este programa importe a classe TransparentLayout do pacote net.java.dev.transparentlayout. 5.2 – Teste de unidade A Listagem 9 mostra um stress test para o TransparentLayout. Esse teste mostra o TransparentLayout atuando sobre componentes AWT e SWING, em situações com painéis dispostos de forma simples ou aninhados, levando em consideração se um componente está configurado para usar seu tamanho preferido. 72 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 // File: TransparentLayoutStressTest.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import net.java.dev.transparentlayout.TransparentLayout; /** * TransparentLayout stress test app */ public class TransparentLayoutStressTest { // TransparentLayout under AWT public static void awtTest() { Frame f = new Frame("TransparentLayout AWT Stress Test"); // Emulates content pane Panel p = new Panel(); f.add(p); if (nesting) { Panel tmp = p; p = new Panel(); tmp.setLayout(new GridLayout(1,2)); Label label = new Label("Blank area here"); label.setAlignment(Label.CENTER); tmp.add(label); tmp.add(p); } p.setLayout(new TransparentLayout()); // Create components Label locationLabel = new Label("location: "), userLabel = new Label("user: "), passwordLabel = new Label("password: "); TextField locationField = new TextField(16), userField = new TextField(8), passwordField = new TextField(8); Button searchButton = new Button("..."), openButton = new Button("Open"); if (preferredSize) { p.add(locationLabel, p.add(locationField, p.add(searchButton, p.add(userLabel, p.add(userField, p.add(passwordLabel, p.add(passwordField, p.add(openButton, } else { p.add(locationLabel, p.add(locationField, p.add(searchButton, p.add(userLabel, p.add(userField, p.add(passwordLabel, p.add(passwordField, p.add(openButton, } new new new new new new new new Rectangle( 0, Rectangle( 68, Rectangle(248, Rectangle( 0, Rectangle( 68, Rectangle( 0, Rectangle( 68, Rectangle(248, 0, 0, 0, 25, 25, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0)); 0)); 0)); 0)); 0)); 0)); 0)); 0)); new new new new new new new new Rectangle( 0, Rectangle( 68, Rectangle(248, Rectangle( 0, Rectangle( 68, Rectangle( 0, Rectangle( 68, Rectangle(248, 0, 68, 25)); 0, 180, 25)); 0, 67, 25)); 25, 68, 19)); 25, 134, 19)); 44, 68, 25)); 44, 134, 25)); 44, 67, 25)); 73 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 // Border feature not available under AWT if (pack) { f.pack(); } else { f.setBounds(200, 150, 400, 300); } f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent ev) { System.exit(0); } }); f.setVisible(true); // DEBUG INFO if (debug) { try { Thread.sleep(2500); } catch(Exception e) { System.err.println(e.getMessage()); } String msg = ""; msg += ("\nlocationLabel = " + locationLabel.getBounds()); msg += ("\nlocationField = " + locationField.getBounds()); msg += ("\nsearchButton = " + searchButton.getBounds()); msg += ("\nuserLabel = " + userLabel.getBounds()); msg += ("\nuserField = " + userField.getBounds()); msg += ("\npasswordLabel = " + passwordLabel.getBounds()); msg += ("\npasswordField = " + passwordField.getBounds()); msg += ("\nopenButton = " + openButton.getBounds()); } System.out.println(msg); } // TransparentLayout under Swing public static void swingTest() { JFrame f = new JFrame("TransparentLayout Swing Stress Test"); JPanel p = (JPanel) f.getContentPane(); if (nesting) { JPanel tmp = p; p = new JPanel(); tmp.setLayout(new GridLayout(1,2)); JLabel label = new JLabel("Blank area here"); label.setHorizontalAlignment(JLabel.CENTER); tmp.add(label); tmp.add(p); } p.setLayout(new TransparentLayout()); // Create components JLabel locationLabel = new JLabel("location: "), userLabel = new JLabel("user: "), passwordLabel = new JLabel("password: "); JTextField locationField = new JTextField(16), userField = new JTextField(8); JPasswordField passwordField = new JPasswordField(8); 74 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 locationLabel.setLabelFor(locationField); userLabel.setLabelFor(userField); passwordLabel.setLabelFor(passwordField); JButton searchButton = new JButton("..."), openButton = new JButton("Open"); if (preferredSize) { p.add(locationLabel, p.add(locationField, p.add(searchButton, p.add(userLabel, p.add(userField, p.add(passwordLabel, p.add(passwordField, p.add(openButton, } else { p.add(locationLabel, p.add(locationField, p.add(searchButton, p.add(userLabel, p.add(userField, p.add(passwordLabel, p.add(passwordField, p.add(openButton, } new new new new new new new new Rectangle( 0, Rectangle( 68, Rectangle(248, Rectangle( 0, Rectangle( 68, Rectangle( 0, Rectangle( 68, Rectangle(248, 0, 0, 0, 25, 25, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0)); 0)); 0)); 0)); 0)); 0)); 0)); 0)); new new new new new new new new Rectangle( 0, Rectangle( 68, Rectangle(248, Rectangle( 0, Rectangle( 68, Rectangle( 0, Rectangle( 68, Rectangle(248, 0, 68, 25)); 0, 180, 25)); 0, 67, 25)); 25, 68, 19)); 25, 134, 19)); 44, 68, 25)); 44, 134, 25)); 44, 67, 25)); if (border) { p.setBorder( BorderFactory.createTitledBorder("Titled Border")); } if (pack) { f.pack(); } else { f.setBounds(200, 150, 400, 300); } f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); // DEBUG INFO if (debug) { try { Thread.sleep(2500); } catch(Exception e) { System.err.println(e.getMessage()); } String msg = ""; msg += ("\nlocationLabel = " + locationLabel.getBounds()); msg += ("\nlocationField = " + locationField.getBounds()); msg += ("\nsearchButton = " + searchButton.getBounds()); msg += ("\nuserLabel = " + userLabel.getBounds()); msg += ("\nuserField = " + userField.getBounds()); msg += ("\npasswordLabel = " + passwordLabel.getBounds()); msg += ("\npasswordField = " + passwordField.getBounds()); msg += ("\nopenButton = " + openButton.getBounds()); } System.out.println(msg); } 75 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 } 245 // General options static boolean awt, nesting, preferredSize, border, pack, debug; // Program entry point public static void main(String[] args) { // Settings awt = false; nesting = false; preferredSize = false; border = false; pack = false; debug = false; } // Start if (awt) { awtTest(); } else { swingTest(); } Listagem 9 – Exemplo usando a solução Figura 36 – Interface do exemplo em seu tamanho original 76 Figura 37 – Interface do exemplo aumentada 77 Pode-se ver que os componentes foram redimensionados de forma equivalente ao aumento da tela, mantendo proporção de tamanho e posição entre antes e depois. 5.3 – Teste de integração O novo gerenciador integra-se facilmente com as ferramentas atualmente existentes. Nenhuma adaptação (add-on, plug-in e etc.) é necessária para a adoção dele, pois este é como uma extensão dos recursos da plataforma Java. Para usá-lo em qualquer ferramenta basta importar a classe do TransparentLayout através do seu pacote. A figura 38 mostra a integração entre o TransparentLayout e o Ambiente Integrado de Desenvolvimento NetBeans. Figura 38 – Integração com o NetBeans1 78 Figura 39 – Integração com o NetBeans2 Para adicionar o TransparentLayout ao NetBeans da maneira que mostra a figura 39 deve-se seguir os seguintes passos: Tools > Pallete customizer > Form Editor. Uma sugestão para trabalhos futuros seria integrar o TransparentLayout de maneira que ele possa ser usa em conjunto com o Gui Builder do NetBeans. 5.4 – Métricas Para podermos comparar o TransparentLayout com os Gerenciadores de Leiaute prédefinidos de Java devemos converter em números os passos necessários para a construção de interfaces gráficas usando cada um. Associando um peso a cada passo necessário ao processo e calculando a soma de todos no final, é possível medir os processos e, então, compará-los uns aos outros. Uma vez capazes de mensurá-los e compará-los, podemos aperfeiçoá-los. Atribuindo peso 1 para as tarefas muito fáceis (ou seja, aquelas que não exigem nenhum raciocínio por parte do desenvolvedor) e peso 5 para as muito difíceis (ou seja, aquelas que chegam a exigir horas de reflexão), vamos medir a complexidade de cada abordagem de montagem de tela. Quanto menor for o total, menor será a complexidade associada e, portanto, menor será também o tempo necessário para a montagem das telas – adaptado de (PRESSMAN, 2002). 79 Gerenciadores de Leiaute pré-definidos Etapa Peso Definir (e apenas definir) a posição de cada componente 1 Definir o tamanho dos componentes 1 Descobrir qual o gerenciador de leiaute (ou combinação deles) que produz o posicionamento e dimensionamento que foram definidos anteriormente 5 Adicionar na tela o painel (ou combinação deles) correspondente ao(s) gerenciador (es) definido(s) anteriormente 4 (Difícil) Configurar gerenciador de formato de cada painel 3 (Médio) Adicionar os componentes na tela (na verdade, ao painel apropriado e na ordem apropriada, dependendo do gerenciador de leiaute usado) 3 Total 17 Tabela 2 – Métricas para Gerenciadores de Leiaute pré-definidos TransparentLayout Etapa Peso Adicionar os componentes na tela 1 Configurar (definir e imediatamente ajustar) a posição de cada componente 1 Configurar o tamanho (dimensão) dos componentes 1 Total 3 Tabela 3 – Métricas para o TransparentLayout Comparando a Tabela 3 com a Tabela 2 podemos verificar que o TransparentLayout pode ser até quase seis vezes melhor do que os Gerenciadores de Leiaute pré-definidos por Java. 5.5 – Resultados Os gerenciadores de leiaute predefinidos de Java são projetados para situações específicas. Cada gerenciador foca numa disposição de componentes específica, o que obriga o desenvolvedor a combiná-los entre si das mais variadas formas até obter o visual desejado. A complexidade de cada gerenciador, em si, é pequena, mas cresce exponencialmente quando eles são combinados. O grande problema surge, então, da 80 combinação dos gerenciadores, o que quase sempre acontece devido às limitações evidentes de cada um. Além de comprometer a produtividade do desenvolvedor, o excesso de complexidade do código resultante também dificulta a manutenção futura dos programas produzidos. Uma vantagem do TransparentLayout é dispensar a combinação de gerenciadores. Com isso, o desenvolvedor pode se concentrar no aspecto final da interface gráfica e deixar os detalhes do redimensionamento-reposicionamento totalmente a cargo do gerenciador de leiaute. Como comprovação de tudo o que foi apresentado até aqui, a listagem 10 mostra um último exemplo demonstrando a complexidade citada anteriormente comparando o Gerenciador de Leiaute de Grade Dinâmico e o TransparentLayout. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 // File: LayoutManagersBenchmark.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import net.java.dev.transparentlayout.TransparentLayout; /** * Benchmark: TransparentLayout X GridBagLayout */ public class LayoutManagersBenchmark { /* GridBagLayout needs 54 (many per component) too complex statements to layout this GUI */ private JPanel getLoginPane( JLabel locationLabel, JTextField locationField, JButton searchButton, JLabel userLabel, JTextField userField, JLabel passwordLabel, JPasswordField passwordField, JButton openButton) { GridBagLayout gbLayout = new GridBagLayout(); // 1st GridBagConstraints gbConstraints = new GridBagConstraints(); // 2nd JPanel panel = new JPanel(gbLayout); gbConstraints.gridx = 0; // 3rd gbConstraints.gridy = 0; // 4th gbConstraints.gridwidth = 1; // 5th gbConstraints.gridheight = 1; // 6th gbConstraints.weightx = 1; // 7th gbConstraints.weighty = 1; // 8th gbConstraints.anchor = GridBagConstraints.CENTER; // 9th gbConstraints.fill = GridBagConstraints.BOTH; // 10th gbLayout.setConstraints(locationLabel, gbConstraints); // 11th panel.add(locationLabel); // 12th gbConstraints.gridx = 1; // 13th gbConstraints.gridy = 0; // 14th gbConstraints.gridwidth = 2; // 15th gbLayout.setConstraints(locationField, gbConstraints); // 16th panel.add(locationField); // 17th 81 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 gbConstraints.gridx = 3; // 18th gbConstraints.gridy = 0; // 19th gbConstraints.gridwidth = 1; // 20th gbLayout.setConstraints(searchButton, gbConstraints); // 21th panel.add(searchButton); // 22th gbConstraints.gridx = 0; // 23th gbConstraints.gridy = 1; // 24th gbLayout.setConstraints(userLabel, gbConstraints); // 25th panel.add(userLabel); // 26th gbConstraints.gridx = 1; // 27th gbConstraints.gridy = 1; // 28th gbLayout.setConstraints(userField, gbConstraints); // 29th panel.add(userField); // 30th JLabel aux = new JLabel(" "); // 31th gbConstraints.gridx = 2; // 32th gbConstraints.gridy = 1; // 33th gbConstraints.gridwidth = 2; // 34th gbLayout.setConstraints(aux, gbConstraints); // 35th panel.add(aux); // 36th gbConstraints.gridx = 0; // 37th gbConstraints.gridy = 2; // 38th gbConstraints.gridwidth = 1; // 39th gbLayout.setConstraints(passwordLabel, gbConstraints); // 40th panel.add(passwordLabel); // 41th gbConstraints.gridx = 1; // 42th gbConstraints.gridy = 2; // 43th gbLayout.setConstraints(passwordField, gbConstraints); // 44th panel.add(passwordField); // 45th JLabel aux2 = new JLabel(" "); // 46th gbConstraints.gridx = 2; // 47th gbConstraints.gridy = 2; // 48th gbLayout.setConstraints(aux2, gbConstraints); // 49th panel.add(aux2); // 50th gbConstraints.gridx = 3; // 51th gbConstraints.gridy = 2; // 52th gbLayout.setConstraints(openButton, gbConstraints); // 53th panel.add(openButton); // 54th panel.setBorder( BorderFactory.createTitledBorder("GridBagLayout")); return panel; } /* TransparentLayout needs just 8 (one per component) very simple statements to reach the same effect */ private JPanel getLoginPane2( JLabel locationLabel, JTextField locationField, JButton searchButton, JLabel userLabel, JTextField userField, JLabel passwordLabel, JPasswordField passwordField, JButton openButton) { JPanel panel = new JPanel(new TransparentLayout()); // container.add(child, new Rectangle(x, y, panel.add(locationLabel, new Rectangle( 0, panel.add(locationField, new Rectangle( 68, panel.add(searchButton, new Rectangle(248, panel.add(userLabel, new Rectangle( 0, panel.add(userField, new Rectangle( 68, panel.add(passwordLabel, new Rectangle( 0, panel.add(passwordField, new Rectangle( 68, panel.add(openButton, new Rectangle(248, width, height)); 0, 68, 25)); // 0, 180, 25)); // 0, 67, 25)); // 25, 68, 19)); // 25, 134, 19)); // 44, 68, 25)); // 44, 134, 25)); // 44, 67, 25)); // 1st 2nd 3rd 4th 5th 6th 7th 8th panel.setBorder( BorderFactory.createTitledBorder("TransparentLayout")); 82 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 } return panel; /** * Code that doesn"t change across layout managers */ public void benchmarkThem() { JLabel locationLabel = new JLabel("location: "), locationLabel2 = new JLabel("location: "), userLabel = new JLabel("user: "), userLabel2 = new JLabel("user: "), passwordLabel = new JLabel("password: "), passwordLabel2 = new JLabel("password: "); JTextField locationField = new JTextField(16), locationField2 = new JTextField(16), userField = new JTextField(8), userField2 = new JTextField(8); JPasswordField passwordField = new JPasswordField(8), passwordField2 = new JPasswordField(8); locationLabel.setLabelFor(locationField); locationLabel2.setLabelFor(locationField2); userLabel.setLabelFor(userField); userLabel2.setLabelFor(userField2); passwordLabel.setLabelFor(passwordField); passwordLabel2.setLabelFor(passwordField2); JButton searchButton = new JButton("..."), searchButton2 = new JButton("..."), openButton = new JButton("Open"), openButton2 = new JButton("Open"); JPanel p1 = getLoginPane(locationLabel, locationField, searchButton, userLabel, userField, passwordLabel, passwordField, openButton); JPanel p2 = getLoginPane2(locationLabel2, locationField2, searchButton2, userLabel2, userField2, passwordLabel2, passwordField2, openButton2); JFrame f = new JFrame("Layout Managers Benchmark"); f.setLayout(new GridLayout(1,0)); f.add(p1); f.add(p2); f.pack(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent ev) { System.exit(0); } }); f.setVisible(true); /* DEBUG INFO try { Thread.sleep(2500); } catch(Exception e) { System.err.println(e.getMessage()); } String msg = ""; msg += ("\nlocationLabel = " + locationLabel.getBounds()); msg += ("\nlocationField = " + locationField.getBounds()); msg += ("\nsearchButton = " + searchButton.getBounds()); msg += ("\nuserLabel = " + userLabel.getBounds()); msg += ("\nuserField = " + userField.getBounds()); msg += ("\npasswordLabel = " + passwordLabel.getBounds()); 83 203 204 205 206 207 208 209 210 211 212 213 214 } 215 msg += ("\npasswordField = " + passwordField.getBounds()); msg += ("\nopenButton = " + openButton.getBounds()); } System.out.println(msg); */ // Program entry point public static void main(String[] args) { new LayoutManagersBenchmark().benchmarkThem(); } Listagem 10 – Comparativo final Figura 40 – Interface do exemplo em seu tamanho original Figura 41 – Interface do exemplo aumentada A figura 40 mostra o exemplo com sua interface em seu tamanho original e a figura 41 mostra o mesmo exemplo com a interface aumentada. Percebe-se na figura 41 que os componentes mantiveram a posição original (comparados com os da figura 40) relativamente ao aumento sofrido. O novo tamanho dos componentes, mostrado na figura 41, também é proporcional (tanto na horizontal quanto na vertical) ao aumento sofrido pela janela da interface. O exemplo é menor (em quantidade de linhas de código) que os equivalentes feitos com gerenciadores de leiaute pré-definidos. O código produzido pelo novo gerenciador é também mais fácil de manter, pois evita configurações de parâmetros. 84 5.5.1 – RFE & Java.net A Sun mantém um Banco de Dados das solicitações dos usuários da plataforma Java. Uma vez aprovada, a solicitação é disponibilizada para votação pelos membros da SDN (Sun Developer Network). As solicitações mais votadas são atendidas com maior rapidez que as demais. As solicitações enviadas podem ser de dois tipos: Bug ou RFE. Bugs são pedidos para correção de problemas que impedem o correto funcionamento de um software atual. RFEs (Requests for Enhancement), por sua vez, são solicitações de melhoria, ou seja, são propostas para mudança de softwares que, embora funcionem corretamente no momento, podem ser aperfeiçoados em versões futuras. Geralmente, uma RFE se limita apenas a propor uma melhoria. Dificilmente ela já vem acompanhada com a respectiva solução. Esse, porém, foi o caso do TransparentLayout. Em 28 de Junho de 2005, o TransparentLayout foi encaminhado à Sun na forma de RFE como uma proposta para a solução do atual problema da complexidade no gerenciamento de leiaute. No dia 29 do mesmo mês, a proposta foi aprovada. Estava confirmada, portanto, a sua viabilidade. A RFE do TransparentLayout encontra-se atualmente disponível para votação no endereço abaixo. Até a data de término desse trabalho, ela contava com sete votos. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6292168 Os primeiros comentários de avaliação foram os seguintes: The source is clear and looks reasonable. More testing and verification needed though Ou seja: O código é claro e parece razoável. Entretanto mais testes e verificações são necessários. 85 A versão do TransparentLayout mostrada na RFE é a original, de 28/06/2005. Desde então, o código foi bastante aperfeiçoado e hoje já se encontra num estágio bem mais avançado. Todas as atualizações foram enviadas à Sun e podem ser acompanhadas através do site do projeto criado na comunidade Java.Net especificamente para o aprimoramento do software. O endereço é: http://transparentlayout.dev.java.net/ 86 Parte 6 – Referências Bibliográficas ANSELMO. Site Oficial do Cafeteira. Disponível em: < http://www.mycgiserver.com/~fernans/cafeteira/cafeteira.html > Acesso em: 01/jul/2005 ANSELMO2. Diário do Programador. Disponível em: < http://www.mycgiserver.com/~fernans/cafeteira/diario.pdf > Acesso em: 06/ago/2005 DEITEL, Paul J.; DEITEL, Harvey M. Java, como programar. 4ª ed. Porto Alegre: Bookman, 2004. JGoodies Forms. JGoodies Forms framework. Disponível em: < http://www.jgoodies.com/freeware/forms/ > Acesso em: 06/11/2005 KUZNETSOV. Project Matisse - Java GUI easy & good looking "by default". Disponível em: < http://www.netbeans.org/kb/articles/matisse.html > Acesso em: 13/set/2005. PRESSMAN, Roger S. Engenharia de Software. 5ª ed. São Paulo: McGraw-Hill, 2002. SPORAR. Project Matisse. Disponível em: < http://weblogs.java.net/blog/gsporar/archive/2005/06/project_matisse.html > Acesso em: 10/jun/2005 SUN. Creating a Custom Layout Manager. Disponível em: < http://java.sun.com/docs/books/tutorial/uiswing/layout/custom.html > Acesso em: 05/mai/2005 SUN1. Java TM 2 Platform Standard Edition 5.0 API Specification. Disponível em: < http://java.sun.com/j2se/1.5.0/docs/api/ > Acesso em : 05/mai/2005 SUN2. Interface ComponentListener. Disponível em: < http://java.sun.com/j2se/1.5.0/docs/api/java/awt/event/ComponentListener.html > Acesso em: 01/set/2005 87 SUN3. < Class Container. Disponível http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Container.html em: > Acesso em: 01/set/2005 TableLayout. Tablelayout Project home. Disponível em: < https://tablelayout.dev.java.net/ > Acesso em: 01/10/2005 WIKIPEDIA the free encyclopedia. Henri Matisse. Disponível em: < http://en.wikipedia.org/wiki/Henri_Matisse > Acesso em: 06/jun/2005 Zooki Technologies. ExplicitLayout 3.0. Disponível em: < http://www.zookitec.com/explicitlayout.html > Acesso em: 01/10/2005 88 Parte 7 - Apêndice O Apêndice deste trabalho mostra a seguir a documentação Java (Javadoc) para o TransparentLayout. Sumário da classe TransparentLayout: Package net.java.dev.transparentlayout Class Summary A straightforward layout manager for Java AWT/Swing toolkit that infers the appropriate resizing behavior from the original component TransparentLayout bounds, freeing the developers from the complexities of layout managers. Detalhes da classe TransparentLayout: net.java.dev.transparentlayout Class TransparentLayout java.lang.Object net.java.dev.transparentlayout.TransparentLayout All Implemented Interfaces: LayoutManager, LayoutManager2, Serializable public class TransparentLayout extends Object implements LayoutManager2, Serializable A straightforward layout manager for Java AWT/Swing toolkit that infers the appropriate re sizing behavior from the original component bounds, freeing the developers from the com plexities of layout managers. It implements the LayoutManager2 interface to support a brand new "Free Design" paradigm. Set only the original component bounds (x, y, width, height) and TransparentLayout works for you. The solution can be used either in command-line tools or in graphical ones. Version: 1.0rc5, 11/13/05 Description: Rewrote to target release 1.1., 1.0rc4, 11/12/05 Description: Better nesting support., 1.0rc3, 11/02/05 Description: Improved insets support., 1.0rc2, 10/29/05 Description: Improved preferred container size support., 89 1.0rc1, 10/13/05 Description: Added preferred component size support., 1.0beta2, 10/11/05 Description: Added preferred container size support., 1.0beta, 10/09/05 Description: Added font resizing support., 0.1alpha, 06/28/05 Description: First draft submitted to Sun ( http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6292168), i18n already supported. Author: Dante (E.B.G.) See Also: Rectangle, ComponentOrientation, Serialized Form Field Summary protected Hashtable originalComponentBounds This map maintains the association between a component and its original bounds. protected originalComponentOrientation ComponentOrientation Constructor Summary TransparentLayout() Constructs a new TransparentLayout using a left-to-right orientation. TransparentLayout(ComponentOrientation originalComponentOrientation) Constructs a new TransparentLayout. Method Summary void addLayoutComponent(Component comp, Object bounds) Adds the specified component to the layout, using the specified bounds object. void addLayoutComponent(String name, Component comp) Has no effect, since this layout manager does not use a percomponent string. float getLayoutAlignmentX(Container target) Returns the alignment along the x axis. float getLayoutAlignmentY(Container target) Returns the alignment along the y axis. Rectangle getOriginalComponentBounds(Component comp) Gets the bounds for the specified component. ComponentOrientation getOriginalComponentOrientation() Gets the original component orientation. void invalidateLayout(Container target) 90 Invalidates the layout, indicating that if the layout manager has cached information it should be discarded. void layoutContainer(Container target) Lays out the specified container using this layout. Dimension maximumLayoutSize(Container target) Gets the maximum layout size for the specified container. Dimension minimumLayoutSize(Container target) Gets the minimum layout size for the specified container. Dimension preferredLayoutSize(Container target) Gets the preferred layout size for the specified container. void removeLayoutComponent(Component comp) Removes the specified component from this layout. void setOriginalComponentBounds(Component comp, Rectangle bounds) Sets the bounds for the specified component in this layout. void setOriginalComponentOrientation(ComponentOrientation orientation) Sets the original component orientation. String toString() Returns a string representation of this layout values Methods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait Field Detail originalComponentOrientation protected ComponentOrientation originalComponentOrientation See Also: getOriginalComponentOrientation(), setOriginalComponentOrientation(java.awt.ComponentOrientation) originalComponentBounds protected Hashtable originalComponentBounds This map maintains the association between a component and its original bounds. The keys in originalComponentBounds are the components and the values are the instances of Rectangle. See Also: 91 getOriginalComponentBounds(java.awt.Component), setOriginalComponentBounds(java.awt.Component, java.awt.Rectangle), Rectangle 92 Constructor Detail TransparentLayout public TransparentLayout() Constructs a new TransparentLayout using a left-to-right orientation. TransparentLayout public TransparentLayout(ComponentOrientation originalComponentOrientation) Constructs a new TransparentLayout. Parameters: originalComponentOrientation - the component orientation corresponding to children bounds. The argument must be one of the following values: • • ComponentOrientation.LEFT_TO_RIGHT; or ComponentOrientation.RIGHT_TO_LEFT. See Also: ComponentOrientation Method Detail getOriginalComponentOrientation public ComponentOrientation getOriginalComponentOrientation() Gets the original component orientation. Returns: the original component orientation See Also: ComponentOrientation 93 setOriginalComponentOrientation public void setOriginalComponentOrientation(ComponentOrientation orienta tion) Sets the original component orientation. Parameters: orientation - the original component orientation See Also: ComponentOrientation getOriginalComponentBounds public Rectangle getOriginalComponentBounds(Component comp) Gets the bounds for the specified component. A copy of the actual Rectangle object is returned. Parameters: comp - the component to be queried Returns: the bounds for the specified component in this layout; a copy of the actual bounds object is returned setOriginalComponentBounds public void setOriginalComponentBounds(Component comp, Rectangle bounds) Sets the bounds for the specified component in this layout. Zero width or zero height means that the preferred component size will be applied. Parameters: comp - the component to be modified bounds - the bounds to be applied Throws: IllegalArgumentException - if the bounds contains negative values. See Also: addLayoutComponent(java.awt.Component, java.lang.Object) 94 addLayoutComponent public void addLayoutComponent(Component comp, Object bounds) Adds the specified component to the layout, using the specified bounds object. The bounds is a java.awt.Rectangle object. Called when a component is added to a container using the Container.add method with the same argument types. Zero width or zero height means that the preferred component size will be applied. Specified by: addLayoutComponent in interface LayoutManager2 Parameters: comp - the component to be added. bounds - a java.awt.Rectangle object that specifies the component bounds. Throws: IllegalArgumentException - if the constraint object is not a Rectangle. See Also: Container.add(java.awt.Component, java.lang.Object), getOriginalComponentBounds(java.awt.Component), setOriginalComponentBounds(java.awt.Component, java.awt.Rectangle) addLayoutComponent public void addLayoutComponent(String name, Component comp) Has no effect, since this layout manager does not use a per-component string. Specified by: addLayoutComponent in interface LayoutManager removeLayoutComponent public void removeLayoutComponent(Component comp) Removes the specified component from this layout. Most applications do not call this method directly. Specified by: removeLayoutComponent in interface LayoutManager Parameters: comp - the component to be removed. 95 See Also: Container.remove(java.awt.Component), Container.removeAll() getLayoutAlignmentX public float getLayoutAlignmentX(Container target) Returns the alignment along the x axis. This specifies how the component would like to be aligned relative to other components. The value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is centered, etc. Specified by: getLayoutAlignmentX in interface LayoutManager2 Returns: the value 0.5f to indicate centered getLayoutAlignmentY public float getLayoutAlignmentY(Container target) Returns the alignment along the y axis. This specifies how the component would like to be aligned relative to other components. The value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is centered, etc. Specified by: getLayoutAlignmentY in interface LayoutManager2 Returns: the value 0.5f to indicate centered maximumLayoutSize public Dimension maximumLayoutSize(Container target) Gets the maximum layout size for the specified container. Specified by: maximumLayoutSize in interface LayoutManager2 Returns: the maximum layout size for the specified container preferredLayoutSize public Dimension preferredLayoutSize(Container target) 96 Gets the preferred layout size for the specified container. Specified by: preferredLayoutSize in interface LayoutManager Returns: the preferred layout size for the specified container minimumLayoutSize public Dimension minimumLayoutSize(Container target) Gets the minimum layout size for the specified container. Specified by: minimumLayoutSize in interface LayoutManager Returns: the minimum layout size for the specified container invalidateLayout public void invalidateLayout(Container target) Invalidates the layout, indicating that if the layout manager has cached information it should be discarded. Specified by: invalidateLayout in interface LayoutManager2 layoutContainer public void layoutContainer(Container target) Lays out the specified container using this layout. This method reshapes components in the specified container in order to satisfy the bounds of this Rectangle object. Most applications do not call this method directly. Specified by: layoutContainer in interface LayoutManager Parameters: target - the container in which to do the layout See Also: Container, Container.doLayout() 97 toString public String toString() Returns a string representation of this layout values. Overrides: toString in class Object Returns: a string representation of this layout. 98