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