Um Sistema Java Completo - Criando Aplicaes Grficas com o NetBeans

  • Published on
    02-Aug-2015

  • View
    4.424

  • Download
    19

Transcript

Um Sistema Java Completo - Criando Aplicaes Grficas com o NetBeansParte 1: Prototipao da interface com o usurio Aprenda a criar aplicaes com aparncia profissional, desenvolvendo um exemplo completo no NetBeans, comeando com menus, janelas e componentes principais O NetBeans hoje o melhor IDE livre para iniciantes em Java, sem no entanto dever nada em recursos voltados para o profissional mais experiente. A verso 4.0 foi apresentada na edio anterior, com foco no novo modelo de projetos, que oferece flexibilidade para os projetos mais complexos. Nesta srie de artigos, o enfoque ser demonstrar como construir aplicaes grficas com a biblioteca padro de componentes visuais do J2SE, o Swing, usando os recursos do NetBeans. Para desenvolvedores acostumados ao desenvolvimento com ferramentas RAD como Delphi ou Visual Basic, haver certo esforo de adaptao filosofia de trabalho diferente do Java visual. Isso inclui a forma de desenhar formulrios usando gerenciadores de layout; o tratamento de eventos baseado em listeners; e a forma de utilizao de componentes mais sofisticados (como tabelas e rvores), que exigem customizao baseada na extenso de classes ou implementao de interfaces. Nesta parte apresentamos o desenvolvimento da interface grfica de uma aplicao de "Lista de Tarefas", ilustrando boas prticas do desenvolvimento Swing e mostrando como o NetBeans pode auxiliar na implementao dessas prticas. Se voc est comeando com o desenvolvimento Swing, no deixe de consultar os quadros Conceitos essenciais do Swing e "Gerenciadores de Layout e o NetBeans". E leitores atentos ao lanamento recente do NetBeans 4.1 podem consultar o quadro NetBeans 3.6, 4.0 e 4.1 para informaes sobre as diferenas entre as verses. No contexto deste artigo, as verses 4.1 e 4.0 so praticamente idnticas, e pouco mudou desde a verso 3.6 no que se refere ao desenvolvimento visual. A aplicao de exemplo A Lista de Tarefas ou todo list um componente comum de aplicaes de produtividade pessoal, que permite cadastrar tarefas com prioridades e datas de concluso associadas. A interface grfica inclui uma janela principal, que lista as tarefas ordenadas por prioridade ou por data de concluso, e um dilogo para edio ou incluso de uma tarefa. A janela principal tpica de aplicaes desktop, contendo uma barras de menus e de ferramentas, e uma rea central para a visualizao das tarefas; essa janela deve tambm ser capaz de adaptar-se resoluo de vdeo do sistema ou ao tamanho determinado pelo usurio. J o dilogo um tpico formulrio de entrada de dados, com caixas de edio, checkboxes e outros controles posicionados em uma ordem natural de preenchimento, com os usuais botes Ok e Cancelar na parte inferior. O termo "formulrio" utilizado de forma genrica para referenciar janelas, dilogos e painis, ou seja, qualquer classe que possa ser editada visualmente pela adio de componentes visuais. Outras janelas da aplicao, como uma caixa Sobre, e um dilogo para exibio de alertas sobre tarefas prximas de suas datas de concluso sero construdas nas prximas partes desta srie. Antes de iniciar a construo de uma interface visual, sempre bom desenhar um esboo contendo os principais componentes e sua disposio nas janelas. Papel e caneta ou um programa de desenho so geralmente melhores para isso do que o seu IDE favorito, pois permitem que as idias fluam sem serem viciadas pela estrutura e componentes padres do IDE. A idia aqui fazer brainstorming sobre como deve ser a interface com o usurio, e no obter uma definio precisa da aparncia de cada formulrio. Tambm h o benefcio de se poder focar nos componentes realmente essenciais para o usurio, antes de

1

entrar em detalhes de implementao, como cones ou atalhos. Veja na Figura 1 um esboo das duas janelas aplicao de exemplo deste artigo. Design: por favor, ajustem as cores para deixar o fundo azulado o mais branco possvel: Arquitetura da aplicao um padro em desenvolvimento orientado a objetos utilizar a arquitetura MVC como base de uma aplicao interativa. Dessa forma, o cdigo da nossa aplicao ser organizado em classes de modelo, viso e controlador, utilizando para tal uma estrutura de pacotes. Neste artigo ser realizada apenas a primeira etapa do desenvolvimento da aplicao, que a prototipao da interface com o usurio, utilizando os recursos de desenho de interfaces Swing do NetBeans. Vamos limitar o cdigo ao mnimo que possibilite a navegao e exibio de informaes; assim poderemos validar a usabilidade e a adequao da interface s necessidades da aplicao. Nas prximas edies, alm de novos formulrios, vamos criar as classes de negcios, contendo a lgica de validao e persistncia. Criao do projeto Para a aplicao de exemplo, vamos usar o modelo Java Application do NetBeans (selecione File|New Project, escolha a categoria General e depois Java Application). Fornea Todo como nome do projeto e aceite os padres, criando assim a classe todo.Main. Deixaremos esta classe vazia; mas adiante ela ser modificada para instanciar a janela principal da aplicao. Crie tambm os pacotes todo.modelo, todo.visao e todo.controle. Em uma aplicao de produo, o prefixo para os nomes dos pacotes da aplicao deveria incluir o nome DNS da empresa, por exemplo, "br.com.javamagazine.todo.modelo", de modo a evitar conflitos com bibliotecas e componentes de terceiros. A janela principal Para criar a janela principal, usamos o modelo JFrame form: selecione File|New File, depois Java GUI Forms e JFrame Form (veja a Figura 2). Utilize como nome "ListaTarefas" e modifique o nome do pacote para "todo.visao". Ser aberto o editor visual de classes do NetBeans (veja a Figura 3). Nos lados esquerdo e direito so exibidas vrias vises (ou visualizaes) relacionadas com o editor visual do IDE. direita temos a paleta (Pallete), onde podem ser encontrados os componentes visuais do Swing e AWT. Abaixo da paleta, a rea de propriedades (Properties) apresenta as propriedades do objeto selecionado, permitindo sua customizao. esquerda, logo abaixo da rea que exibe as vises de projeto, arquivos e ambiente de execuo (Projects, File e Runtime) temos o inspetor (Inspector), que apresenta a estrutura hierrquica de objetos visuais. O inspetor muito til quando um componente est sobreposto por outro, ou quando no est visvel na rea de desenho por algum outro motivo. O componente selecionado na rea de desenho sempre selecionado no inspetor, e vice-versa; e as propriedades sempre refletem o componente selecionado. possvel ainda selecionar vrios componentes na rea de desenho (ou no inspetor) e modificar propriedades em todos eles ao mesmo tempo na janela de propriedades. H algumas diferenas no posicionamento e configuraes padres dessas partes do IDE entre as verses 4.1 e 4.0 do NetBeans, entretanto possvel arrastar qualquer viso para outra posio na janela principal do IDE, alm de customizar a aparncia da paleta. Pessoalmente prefiro uma mistura dos padres das duas verses, configurando a paleta para uma aparncia mais compacta (como na verso 4.0) e colocando o inspetor no lado esquerdo (como no NetBeans 4.1), de modo a deixar mais espao para a janela de propriedades. Para reposicionar o inspetor, basta arrast-lo pela sua barra de ttulo; para deixar a paleta mais compacta, clique nela com o boto direito e escolha Hide component names.

2

Outra dica de customizao do NetBeans colocar a viso de sada (output) no modo de "auto-esconder", para que ela no reduza o espao disponvel para o inspetor e a paleta; ela fica como apenas um boto na parte inferior da janela do IDE. Note que a Figura 3 j apresenta a viso de sada nesta configurao. Basta clicar no cone da janela de sada, quando ela for ativada pela prxima compilao ou execuo do projeto. O nosso esboo indica a presena de uma barra de menus e uma de ferramentas na parte de cima da janela, e com uma tabela ocupando toda a sua rea interna. Iniciamos pela adio da barra de menus: clique no cone do JMenuBar ( ) na paleta e clique em qualquer parte da rea de desenho. Por enquanto, deixe a barra de menus como est; mais adiante iremos inserir os demais menus. Agora selecione o componente JToolbar ( ) e clique logo abaixo da barra de menus. O resultado a colocao do JToolbar na posio "norte" do BorderLayout (veja mais sobre este e outros gerenciadores no quadro "Gerenciadores de layout e o NetBeans"). Observe que a barra aparece bem estreita, por no conter ainda nenhum componente. Selecione o JButton ( ) e clique em seguida no JToolbar (na rea de desenho). Ele ir automaticamente se ajustar ao tamanho do boto. Repita o procedimento algumas vezes, para inserir os botes de adicionar, editar, excluir e marcar tarefas. Utilize smbolos como + e "*" para o texto dos componentes (altere a propriedade text), enquanto no criamos os cones apropriados para cada um. Selecione o JToogleButton (prximo ao JButton na paleta, com cone igual) e acrescente dois botes desse tipo ao JToolbar. Eles correspondem s opes de ordenao das tarefas por prioridade ou por data de concluso, e para exibir ou no as tarefas j concludas. Por fim, acrescente mais um JButton para a operao de visualizao de alertas. Continue utilizando smbolos como ! no texto dos botes, como substitutos provisrios para os cones que ainda no foram acrescentados. Para obter o agrupamento e separao visual entre os grupos de botes de uma JToolbar no ir funcionar o uso de um JSeparator, como faremos mais adiante para os menus. O problema que o JSeparator sempre se expande para ocupar toda a largura do container. Utilize em seu lugar um JLabel contendo como texto apenas um espao em branco. Para criar uma barra de status, insira um JLabel ( ) na parte inferior da janela principal, de modo que ele seja colocado na posio "sul" do BorderLayout. Finalmente, insira um JScrollPane ( ) na parte central do JFrame, e dentro dele insira um JTable ( ). Sempre que o contedo de um componente puder ser maior do que a sua rea ocupada na janela, o componente deve ser colocado dentro de um JScrollPane; componentes Swing precisam do JScrollPane para exibir barras de rolagem. A janela principal da aplicao j comea a se parecer com o nosso esboo inicial. A Figura 4 ilustra como est a janela neste momento. Antes de prosseguir, recomendo escolher nomes (propriedade name) significativos para cada componente, ou pelo menos para aqueles cuja funo mais do que decorativa. Isso facilita a identificao dos componentes no inspetor e tambm ser til posteriormente, quando forem codificados os eventos. A Figura 5 apresenta o inspetor com os nomes dos componentes alterados. Formatando a tabela Durante a prototipao de uma interface grfica, seja ela desktop ou web, importante desde o incio inserir dados que sejam o mais prximo possvel da realidade. Caso contrrio, no ser possvel decidir, por exemplo, se o tamanho e a legibilidade dos componentes so adequados ou se a disposio na tela intuitiva. Dessa forma, no recomendvel utilizar textos falsos (como Nonono ou "Xxxxx"), pois eles no refletem a informao que ser vista pelo usurio final.

3

No caso da janela principal, isso significa no apenas configurar as colunas e os ttulos da tabela, mas tambm inserir algumas linhas de dados. Selecione o JTable (no inspetor ou na rea de desenho), depois selecione sua propriedade model e clique no boto de reticncias ( ) ao seu lado. Isso exibe o "customizador" da propriedade, que um mecanismo padro do Java para que um componente visual oferea suporte personalizado configurao de suas propriedades, independentemente do IDE utilizado. Alguns IDEs podem optar por oferecer seus prprios customizadores como alternativa (ou em adio) aos fornecidos pelos prprios componentes. O customizador padro do NetBeans para uma propriedade do tipo TableModel (mostrado na Figura 6) apresenta duas abas. Na primeira, so definidas as colunas da tabela, incluindo o nome e o tipo. Na segunda, possvel inserir um conjunto de dados iniciais para a tabela. Fornea estes dados conforme a figura. Se voc est habituado a IDEs como Delphi ou Visual Basic, poder achar a configurao de tabelas do NetBeans um tanto restrita. Mas veremos na prxima edio que a maioria dessas configuraes na verdade feita por cdigo Java, em classes criadas como parte da aplicao. Veremos ainda que as tabelas do Swing fornecem flexibilidade bastante superior oferecida pelos seus correspondentes em ambientes visuais no-Java. Editando menus A edio de menus e itens de menus no NetBeans no feita na rea de desenho, mas sim no inspetor. Apenas o primeiro nvel na barra de menus pode ser configurado e visualizado na prpria rea de desenho. Para adicionar novos itens ou submenus, deve ser utilizado o menu de contexto dos componentes, em vez da paleta. Clique com o boto direito no JMenuBar e selecione a opo Add JMenu; depois repita mais duas vezes a operao, de modo a terminar com quatro menus; Altere a propriedade text dos menus para "Arquivo", "Editar", "Opes" e "Ajuda". At aqui as alteraes podem ser observadas na rea de desenho do editor visual do NetBeans. Em seguida clique com o boto direito no JMenu "Arquivo" recm-criado e escolha Add>JMenuItem O item adicionado no exibido na rea de desenho, mas pode ser visto no inspetor; selecione esse item e mude seu text para Nova lista de tarefas. Repita a operao para criar o item Abrir lista de tarefas, depois adicione um JSeparator e mais um JMenuItem, para a opo Sair. Ao selecionar um item de menu ou boto na IDE para alterar suas propriedades, comum dar-se um duplo clique acidentalmente. Isso faz o NetBeans sair do editor visual e mudar para o editor de cdigo, permitindo editar o cdigo associado ao evento de ao do boto ou item. Se isso acontecer, observe no topo do editor de cdigo dois botes: Source e Design. Um clique em Design retorna ao editor visual; e a qualquer momento pode-se clicar em Source para ver o cdigo Java correspondente ao formulrio. Para visualizar a aparncia dos itens recm-adicionados ao nosso menu Arquivo, clique no cone com um pequeno olho ( ) na barra de ferramentas da rea de desenho. Isso ir executar imediatamente um "clone" do JFrame, contendo os mesmos componentes, mas sem o cdigo de tratamento de eventos (que ainda no acrescentamos de qualquer modo). Assim possvel interagir com os menus e visualizar seus itens e submenus. A Figura 7 mostra um dos menus nessa pr-visualizao. Repita o processo para inserir os demais itens, de acordo com a estrutura apresentada na Figura 8. Observe na figura o uso de componentes JMenuItem, JSeparator, JCheckboxMenuItem e JRadioButtonMenuItem. Voc pode mudar a ordem com que os elementos aparecem em cada menu, arrastando os componentes para outra posio dentro do inspetor. cones e barras de ferramentas

4

Um item de menu ou boto de barra de ferramentas contendo apenas texto considerado pobre para os padres atuais de interfaces grficas: espera-se que ao menos os itens mais importantes tenham cones associados, alm de teclas de atalho. Todas essas opes podem ser configuradas pelas propriedades do componente, mas os iniciantes em Swing costumam ter dificuldades especiais com os cones. A primeira dificuldade vem de que a maioria dos IDEs Java (entre eles o NetBeans) no incluem um conjunto padro de cones prontos para uso. A Sun fornece um conjunto de cones especialmente adaptados ao look-and-feel Metal padro do Swing (at o J2SE 1.4) em java.sun.com/developer/techDocs/hi/repository. Eles podem ser baixados todos em um pacote jar ou um a um diretamente da pgina, e podem ser redistribudos livremente com sua aplicao. Preferi, no entanto, copiar os cones do Workbench do Eclipse, que so mais modernos em vrios aspectos e tambm podem ser redistribudos livremente. Os cones esto todos na pasta src/icones nos fontes para download deste artigo (embora apenas uma pequena deles sejam utilizados pela aplicao que estamos construindo). A segunda dificuldade na forma de referenciar os cones, de forma independente do diretrio de instalao no computador do usurio final. Caso contrrio voc vai precisar fornecer tambm um programa de instalao, assim como lidar com questes como letras de drives (que s existem no Windows) e separadores de diretrios. A soluo recomendada colocar os cones junto s classes da aplicao, de modo que possam ser localizados por uma busca pelo classpath, da mesma forma que so localizados os arquivos .class. pela JVM. Arquivos de dados encontrados desta maneira so chamados de recursos da aplicao. Voc pode ento copiar a pasta src/icones do pacote de download para o mesmo local em seu projeto no NetBeans. Por estarem na mesma pasta do cdigo Java da aplicao, os recursos (no caso os cones) sero automaticamente copiados para a pasta build/classes durante a compilao do projeto. Assim estaro junto aos bytecodes das classes da aplicao, como desejamos. O prximo passo configurar os cones nos itens de menu. Para cada item, selecione sua propriedade icon e clique no boto do seu customizador ( ). No dilogo exibido (Figura 9) selecione a opo Classpath e clique em Select File. Escolha o cone adequado e observe como a caixa de texto correspondente, em vez de registrar o caminho completo para o arquivo do cone no sistema de arquivos, registra apenas o caminho relativo ao classpath da aplicao, por exemplo /icones/delete_obj.gif. Caso o NetBeans no exiba os cones recm-copiados no customizador da propriedade icon, entre nas propriedades do projeto (clique com o boto direito sobre o cone do projeto, na viso de projeto) e adicione uma pasta qualquer ao seu classpath de compilao (item Libraries, aba Build nas propriedades do projeto). Ao se confirmar a alternao nas propriedades, o IDE ir re-escanear o classpath e assim notar a presena dos cones. Depois no deixe de voltar s propriedades do projeto e remover esta pasta adicional. Quando o projeto for empacotado para distribuio (com Build|Build Main Project) os arquivos de cones sero copiados para o pacote jar executvel, juntamente com os bytecodes da aplicao. A aplicao poder assim ser instalada em qualquer pasta no computador do usurio final. Da mesma forma que foi feito para os menus, podemos agora configurar os cones para os botes da barra de ferramentas. A Figura 10 apresenta a barra customizada com os cones. Tome o cuidado de escolher para os botes os mesmos cones dos itens de menu equivalentes. Aceleradores e atalhos Aplicaes visuais bem-escritas definem mnemnicos para todos os seus itens de menus, e tambm aceleradores para os itens utilizados com mais freqncia pelo usurio.

5

Um mnemnico permite navegar pelos menus utilizando apenas o teclado, o que torna a operao da aplicao mais gil para usurios freqentes e mais confortvel em dispositivos como quiosques1[1]. Mnemnicos tambm so um dos principais itens de acessibilidade2[2] de uma aplicao. Um mnemnico em geral a primeira letra do item do menu, conjugada com a tecla Alt. Alm de itens de menus, outros componentes como botes e labels podem ter mnemnicos, permitindo a navegao pelo teclado em um formulrio de entrada de dados. Mais adiante veremos como fazer isso, quando detalharmos a construo do dilogo de edio de tarefas. J um acelerador permite a execuo direta de alguma operao importante, sem a necessidade de navegar at ela nos menus. Um exemplo o popular Ctrl+X para o comando Editar|Recortar. Mnemnicos e aceleradores so definidos em propriedades dos itens de menus e demais controles; ento fcil configur-los no NetBeans. A Figura 11 apresenta essa configurao para o item Editar|Adicionar tarefa da aplicao de exemplo. E a Figura 12 mostra os menus da aplicao completos, j com cones, mnemnicos e aceleradores definidos. Observe que as letras correspondentes aos mnemnicos so exibidas sublinhadas em cada item de menu, enquanto que os aceleradores definidos so exibidos ao lado do texto do item correspondente. J que falamos de facilidade de uso, aproveitamos para um comentrio sobre as barras de ferramentas. Conceitualmente, elas seriam atalhos de mouse, ento se uma operao importante o suficiente para estar na barra de ferramentas, ela tambm deve ter um atalho de teclado associado. Alm disso, todo elemento numa barra de ferramentas deve corresponder a algum item de menu, ou ento a alguma opo num dilogo. Em outras palavras, atalhos e barras de ferramentas nunca devem ser a nica forma de se realizar uma tarefa. Voltando aplicao: para que as barras e menus fiquem completos, eles necessitam apenas da configurao de tooltips, que podem ser configurados alterando a propriedade toolTipText de cada componente. A janela de edio de tarefas Para criar a segunda janela da aplicao, clique com o boto direito no pacote "todo.visao" no inspetor e selecione New>File/Folder no menu de contexto; depois escolha o modelo JDialog Form na categoria Java GUI Forms. Chame a classe de "EditaTarefa". Altere o gerenciador de layout para o valor nulo ("Null Layout"). Assim ser possvel posicionar os componentes de forma livre dentro do dilogo. Depois mude para um GridBagLayout, deixando que o NetBeans gere um conjunto inicial de GridBagConstraints3[3] para cada componente, que ser depois ajustado manualmente. O quadro Entenda os GridBagConstraints descreve o significado de cada uma das propriedades de layout que teremos que ajustar. A Figura 13 apresenta o JDialog com componentes posicionados no gerenciador de layout nulo. Depois da mudana para o GridBagLayout vai parecer que a janela no mudou, mas ao abrir o customizador do gerenciador de layout (clicando com o boto direito no JDialog e selecionando Customize Layout), veremos que o conjunto de constraints gerados pela converso menos que timo (Figura 14). H vrias colunas e linhas adicionais e os espaamentos desiguais em cada clula prejudicam o alinhamento dos componentes. Apesar disso, ainda no encontrei um desenvolvedor que, depois de algum tempo com o NetBeans, prefira utilizar o GridBagLayout desde o incio, porque ser mais trabalhoso configurar manualmente todas as propriedades a cada componente adicionado. 1[1] Como os quiosques que informam sobre localizaes de lojas em shopping centers ou caixas eletrnicos de bancos 2[2] Uma aplicao considerada acessvel se foi construda levando em considerao a facilidade de uso por pessoas com deficincias visuais ou motoras 3[3] As propriedades que vemos agrupadas na categoria Layout em um componente so na verdade as propriedades do objeto de constraints do gerenciador de layout, cuja classe especfica para cada gerenciador.

6

O posicionamento dos JLabels e caixas de texto (incluindo os dois JSpinner), no oferece dificuldades. Lembre-se tambm de colocar o JTextArea dentro de um JScrollPane. Os botes de Salvar, Cancelar e Remover devero ser inseridos todos dentro de um painel; este painel que ser posicionado dentro do dilogo (mais detalhes adiante). Observe ainda os dois JSeparator, colocados antes e depois da rea de texto de observaes, e o JLabel a parte superior do dilogo, que ser utilizado como uma rea ara exibio de mensagens de erros. Daqui em diante entramos em mais detalhes sobre como configurar o dilogo para chegar aparncia final, conforme a Figura 15. Todos os ajustes sero feitos dentro do customizador do GridBagLayout, o qual ao fim do processo estar como na Figura 16. Inicie os ajustes zerando a margem interna (Internal Padding) e colocando o valor 1 na altura (Grid Height ) de todos os componentes. Posicionamento e espaamento no formulrio Foi inserido um espaamento de cinco pixels entre cada componente e entre os componentes e as bordas do dilogo, para que no paream grudados. Observe as reas em amarelo na Figura 16; elas indicam onde foram adicionados espaamentos. Aproveite o fato de que possvel selecionar mltiplos componentes utilizando a tecla Ctrl + mouse, para configurar espaamentos uniformes. Os labels de Descrio, Prioridade e Data de concluso, assim como o checkbox Gerar alerta foram ancorados (modificando Anchor) direita (posio "leste"); os controles correspondentes (um JTextField, dois JSpinner e um JFormattedTextField) foram alinhados esquerda (posio "oeste"). Ambos os grupos receberam espaamento esquerda e abaixo, exceto pela primeira linha (Descrio), que ganhou tambm espaamento acima (caso contrrio, ela ficaria colada ao label de mensagem). Para JScrollPane e os dois separadores, foi acrescentado espaamento esquerda, direita e abaixo, e eles foram configurados para ocuparem trs clulas de largura (alterando Grid Width). A caixa de texto de descrio ocupa duas clulas, assim como a de data de concluso. As caixas de prioridade e de dias de antecedncia para o alerta ocupam apenas uma clula de largura. O campo de observaes Queremos que o dilogo de edio de atividades seja redimensionvel, e que o campo de observaes ocupe todo o espao remanescente. Assim, o campo deve ser configurado para se expandir tanto na horizontal quanto na vertical (mudando a propriedade Fill para Both) e receber peso 1 em ambos os sentidos (modifique Weight X e Weight Y). Observe que estas constraints se aplicam ao JScrollPane que contm o JTextArea. J os dois separadores devem ser configurados para se expandirem apenas na horizontal (alterando o valor de Fill para Horizontal), mas sem nenhum peso. Configurando os botes Um JButton normalmente assume a dimenso mnima que permita exibir seu texto, gerando telas deselegantes, onde o boto de "Ok" muito menor do que o de "Cancelar", por exemplo. A aparncia fica melhor quando botes relacionados tm as mesmas dimenses. A maneira mais fcil de fazer isso inserindo os botes dentro do seu prprio painel, e configurando o layout deste painel para um GridLayout. O painel ento posicionado na parte inferior do dilogo, posicionado na parte de baixo do GridBagLayout, com duas clulas de largura. esquerda do painel de botes est o checkbox que registra se a tarefa foi ou no completada. A ncora do painel colocada na posio "leste", de modo que o conjunto de botes fique alinhado direita. Label de mensagens

7

Para o label de mensagens, posicionado no topo do dilogo, queremos um visual diferente do padro. Ele deve ficar claramente diferenciado no formulrio de edio, dada sua funo de exibir mensagens informativas. Obtemos o efeito de faixa mudando a cor de fundo do label, e deixado seus espaamentos (Insets) zerados, de modo que ele fique colado aos cantos do dilogo; entretanto, no queremos que o texto fique colado. A soluo definir uma borda: alteramos a propriedade border do label para EmptyBorder e configuramos esta borda com espaamentos de 5 pixels em cada direo. Quanto s cores de frente e de fundo, foram escolhidos um tom suave de amarelo e um tom mais forte de azul-claro, para se obter um bom contraste. A mudana na cor de fundo s ser visvel se for modificada a propriedade opaque do componente, pois o padro que um JLabel tenha o fundo transparente, incorporando a cor de fundo do seu container. J em relao fonte, foi mantido o padro do Swing (Dialog); apenas retiramos o negrito da fonte padro. Na maioria das vezes deve-se evitar a customizao de fontes e cores em formulrios de entrada de dados, pois isso pode tornar a aplicao deselegante ou ilegvel caso o usurio opte por um look-and-feel customizado, ou por um tema de cores diferente para o lookand-feel padro. Caso seja necessrio mudar as cores, mesmo que para um tom fixo, tenha sempre o cuidado de fixar ambas as cores de frente e de fundo do componente. Mnemnicos no formulrio Para garantir a agilidade na digitao e a acessibilidade do formulrio, devem ser definidos mnemnicos de teclado para os campos de texto e outros componentes, de forma similar ao que foi feito para os menus. O procedimento envolve, primeiro, associar cada JLabel ao seu componente de entrada de dados, por meio da propriedade labelFor. Em seguida, configurado o campo displayedMnemonic para a tecla desejada, que ser sublinhada no texto do label. Os "botes" (JButton, JToogleButton, JCheckBox e JRadioButton) so configurados pelas suas propriedades nmemonic especficas. Use a Figura 15 como referncia para definir as teclas de mnemnico para cada componente. Testando o prottipo At este ponto, as janelas do prottipo foram testadas apenas pela pr-visualizao do editor visual do NetBeans, que nem sempre fiel ao comportamento das classes Java. Vamos ento inserir o mnimo de cdigo para que as duas telas possam ser iniciadas como parte de uma aplicao, e verificar se o resultado funciona corretamente. Localize a classe todo.Main na viso de projeto e d um clique duplo para abri-la no editor de cdigo. Edite o cdigo conforme a Listagem 1: dessa forma, a aplicao iniciar instanciando uma janela ListaTarefas e tornando-a visvel. Em seguida, use o mesmo procedimento para abrir a classe ListaTarefas (caso ela tenha sido fechada). Ela ser aberta no editor visual, em vez de no editor de cdigo. D um clique duplo no primeiro boto da barra de ferramentas. Ser ento mostrado o editor de cdigo, com o cursor posicionado no mtodo que trata o evento actionPerformed do boto. (Os trechos em azul-claro so gerados pelo prprio editor visual e no podero ser modificados no editor de cdigo.) Complete o cdigo para o evento conforme a Listagem 2. O objetivo apenas instanciar o dilogo de edio de tarefas e exibi-lo de forma modal4[4]. Voc j poder executar a aplicao com Run|Run Main Project e verificar o comportamento do exemplo; ou ento selecionar Build|Build Main Project para gerar o pacote jar executvel para a aplicao, e iniciar a aplicao na linha de comando da maneira usual (onde estamos supondo que o diretrio Todo/dist contem o jar da aplicao): $ java -jar Todo/dist/Todo.jar 4[4] Um dilogo exibido de forma modal impede que se interaja com sua janela "me", at que seja fechado pelo usurio.

8

importante que uma aplicao Swing seja testada desde o incio com look-andfeels alternativos, para garantir que ela realmente uma aplicao multiplataforma. Por exemplo, para utilizar o look-and-feel GTK do Linux, a linha de comando seria: $ java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel Todo/dist/Todo.jar feel. Concluses Este artigo demonstrou como usar as facilidades oferecidas pelo NetBeans para desenvolver aplicaes Java com aparncia profissional, baseadas nos componentes visuais do Swing. Como se viu, importante atentar para detalhes, naturalmente, seguir as boas prticas da plataforma Java. Artigos futuros iro demonstrar como utilizar as janelas que foram prototipadas nesta aplicao em uma aplicao orientada a objetos, considerando acesso a bancos de dados e uso eficiente de threads. Veremos tambm como integrar e usar componentes de terceiros no NetBeans.Links netbeans.org Site oficial do NetBeans netbeans.org/kb/articles/form_getstart40.html GUI Building in NetBeans IDE 4.0 java.sun.com/docs/books/tutorial/uiswing Trilha sobre Swing no Java Tutorial da Sun cld.blog-city.com/read/1149708.htm Swing Pointer, uma coleo de recursos para o desenvolvedor Swing

-jar

A Figura 17 apresenta o aspecto das duas janelas da aplicao com este look-and-

Alguns conceitos de Swing Para os que esto comeando com a programao visual em Java, so apresentados aqui alguns conceitos do Swing, que so usados ou citados ao longo do texto. Componentes, em um sentido amplo, so objetos visuais (ex.: JCheckBox, JButton, JSeparator), ou objeto no-visuais (como GridBagLayout) que podem interagir com objetos visuais por meio dos padres JavaBeans. Um container qualquer objeto que possa conter outros objetos visuais. Todo container tem um gerenciador de layout que organiza o posicionamento e dimensionamento dos componentes dentro do container. Exemplos: JPanel e JDialog. Todo componente possui um tamanho mnimo, que a menor dimenso (altura, largura) capaz de exibir todo o seu contedo (texto, cone ou ambos). Em alguns (poucos) casos, este tamanho derivado de outras propriedades do componente; por exemplo, em um JTextArea podem ser especificadas colunas e linhas da sua rea de texto visvel. NetBeans 3.6, 4.0 e 4.1 O NetBeans um dos projetos mais antigos de IDEs livre com recursos visuais, mas no era inicialmente com uma interface com o usurio bem-projetada. Era sim um exemplo de como a plataforma Java e a tecnologia de componentes JavaBeans poderia viabilizar a construo de aplicaes desktop complexas. Como mostrados em outros artigos desta coluna, na verso 3.6 iniciou-se um ciclo de mudanas profundas no NetBeans, de modo a moderniz-lo e deix-lo mais coerente com modernas prticas de desenvolvimento de software em Java. A primeira mudana, no 3.6, foi a criao de uma nova interface com o usurio, baseada em visualizaes que podem ser ancoradas em qualquer parte da tela, organizadas em abas, e abandonando o antigo modelo MDI (como o usado no Gerenciador de Programas do antigo Windows 3.0 e em partes do Microsoft Office).

9

A verso 4.0 inaugurou um novo modelo de projetos, baseado no Ant, que permite customizar com facilidade o processo de construo e empacotamento de aplicaes. Basicamente, o desenvolvedor pode acrescentar novas etapas ao processo, por exemplo, gerao de cdigo via XDoclet ou pr-compilao de pginas JSP com o Jasper do Tomcat tudo sem necessitar de instalar um plug-in especialmente construdo para o NetBeans. Na recm-lanada verso 4.1 a novidade foram recursos voltados para o desenvolvimento J2EE, em especial suporte a EJBs e a web services, no havendo grandes mudanas na interface com o usurio ou no suporte ao desenvolvimento Swing, exceto pela presena de novos templates e assistentes. Da verso 3.6 at a verso 4.1 h poucas mudanas no editor visual, a maioria delas apenas estticas. A nica mudana realmente importante foi o acrscimo, na verso 4.0, de um customizador para o GridBagLayout, utilizado neste artigo para configurar o dilogo de edio de propriedades. Gerenciadores de layout e o NetBeans A maior dificuldade do iniciante em Swing lidar com os gerenciadores de layout predefinidos. Isso sentido especialmente por desenvolvedores habituados a ambientes RAD para Windows. O motivo que nestes ambientes se costuma posicionar os componentes de modo fixo (em pixels) nos formulrios, enquanto que no Swing o posicionamento determinado por um gerenciador de layout. Por isso foi preparado este quadro, que relaciona os usos mais comuns dos principais gerenciadores de layout do J2SE (e um especfico do NetBeans), alm das facilidades oferecidas pelo IDE para a customizao visual de componentes com esses gerenciadores. FlowLayout O gerenciador de layout de fluxo apenas posiciona os componentes em fila, um aps o outro, cada qual com suas dimenses mnimas. O FlowLayout imita o fluxo de texto em uma folha de papel e, como um pargrafo em um processador de textos, tambm pode alinhar os componentes direita, esquerda, ou centralizados dentro do container. O uso mais comum deste layout para preencher uma linha com a maior quantidade possvel de componentes, por exemplo em barras de ferramentas ou de status. No NetBeans: Novos componentes so sempre adicionados ao final do fluxo, mas eles podem ser reposicionados pelo mouse. Um quadrado pontilhado indica a nova posio do componente durante esta operao. BorderLayout O BorderLayout posiciona os compomentes nas bordas do container, deixando a maior parte da sua rea disponvel para o componente inserido no centro. Cada borda identificada por um ponto cardeal (NORTH, SOUTH, EAST, WEST). Apenas um componente ser visvel em cada borda, expandido na altura ou largura para ocupar toda a borda do container, porm assumindo o valor mnimo na outra dimenso. Note que esta disposio reflete o padro na maioria das aplicaes desktop, como processadores de texto ou programas de desenho: uma barra de ferramentas ao norte, uma barra de status ao sul, opcionalmente outras barras de ferramentas ao leste e oeste, e uma rea de edio ao centro. No NetBeans: O componente posicionado na borda da rea de desenho que for clicada quando feita sua adio ao container, e permite que um componente seja arrastado para outra posio (outra borda ou para o centro) desde que esta posio esteja vazia. Caso um componente seja arrastado para uma posio j ocupada, o BorderLayout ir se perder (e consequentemente tambm o NetBeans), e a correo ter que ser feita na viso de propriedades e/ou no inspetor. GridLayout

10

O GridLayout organiza os componentes em uma "grade" ou tabela com tamanho (linhas e colunas) pr-fixadas no momento da sua criao. Todas as clulas possuem o mesmo tamanho, e so expandidas para ocupar a rea total disponvel no container. Caso haja menos componentes do que clulas, o espao das clulas vazias distribudo igualmente entre os componentes; mas podem ficar clulas vazias nas ltimas colunas da ltima linha. O GridLayout adequado quando se deseja que um grupo de componentes (como um grupo de botes) tenha dimenses uniformes, como na caixa de ferramentas de um programa de desenho ou o par de botes Ok e Cancela de um dilogo. No NetBeans: Novos componentes so sempre acrescentados na prxima clula vazia da grade, mas podem ser arrastados com o mouse para uma posio (clula) diferente. GridBagLayout Com nome estranho ("saco de grades"), o GridBagLayout o mais poderoso e mais flexvel dos gerenciadores fornecidos com o J2SE. Ele imita em linhas gerais o funcionamento de uma tabela HTML, em que um componente pode ocupar vrias clulas, ou seja, se estender por vrias colunas e linhas. Os componentes podem ser expandidos para ocupar toda a rea das suas clulas, ou serem alinhados em qualquer posio do conjunto de clulas. Linhas e colunas assumem as dimenses do maior componente, mas necessrio que tenham todas o mesmo tamanho. E algumas clulas podem ser configuradas para ocuparem toda a rea disponvel no container. Podemos afirmar com segurana que qualquer disposio de componentes pode ser configurada em um GridBagLayout. Por outro lado, a quantidade de constraints (propriedades e restries de layout) possvel para cada componente tambm deu a este gerenciador a fama de ser difcil de programar. No NetBeans: O editor visual do NetBeans no tinha suporte ao GridBagLayout antes da verso 4.0, o que obrigava o desenvolvedor a configurar cada uma das dezenas de constraints, manualmente para cada componente. Mas a nova verso fornece um customizador para o GridBagLayout, numa janela externa ao editor visual. Nela representada a grade definida para o layout, assim como a rea ocupada por cada componente. Botes de setas permitem ajustar facilmente cada propriedade, e os componentes podem ser arrastados entre as clulas da grade. Observe o cdigo de cores no customizador: azul significa que a clula ocupada por um componente; cinza indica uma clula vazia; vermelho indica uma linha ou coluna sem componentes; e amarelo mostra espaamento (insets) interno clula. O customizador do GridBagLayout realmente fcil de usar, e em pouco tempo voc estar acostumado com ele. Pena que, pelo customizador, no seja possvel modificar propriedades alm dos constraints de cada componente, nem adicionar novos componentes. Ento ser necessrio entrar e sair do customizador vrias vezes durante o desenho de um formulrio. Null Layout Na verdade o Null Layout no um gerenciador de layout, mas sim a ausncia de qualquer gerenciador (equivale a definir a propriedade layout do container com o valor null). O resultado que no IDE componentes podem ser posicionados vontade na rea de desenho; eles permanecero na posio onde foram colocados e com as dimenses indicadas pelo desenvolvedor. Criar telas com o "layout nulo" s vezes chamado de usar o "posicionamento absoluto". No NetBeans: O NetBeans pode parecer pobre no seu suporte ao layout nulo, pois no fornece as ferramentas de alinhar e centralizar componentes, ou para ajustar as dimenses de grupos de componentes. Por outro lado, o uso desse layout no recomendado, por ser incompatvel com o uso de look-and-feels customizados e ir contra

11

filosofia de portabilidade do Java. Ento faz sentido que o NetBeans desestimule o uso desta opo ao no fornecer facilidades especficas. Absolute Layout O AbsoluteLayout no um gerenciador padro do Java, mas uma adio do NetBeans; seu uso requer que o pacote modules/ext/AbsoluteLayout.jar seja copiado para a estao do usurio e configurado no classpath. Ele funciona como um Null Layout, com a diferena de que as dimenses do container so calculadas corretamente, permitindo o uso do mtodo pack() (com o Null Layout, o resultado so dimenses [0, 0]). Ele apresenta todas as desvantagens do Null Layout, portanto tambm no recomendado para uso geral. GridBagConstraints As propriedades que determinam a posio e dimenses de um componente dentro de um GridBagLayout so reunidas em um objeto chamado GridBagConstraints. Cada componente adicionado a um container cujo gerenciador de layout seja um GridBagLayout possui seu prprio objeto GridBagConstraints. Neste quadro fornecemos uma breve explicao do significado de cada uma dessas propriedades. Note que identificamos as propriedades da classe GridBagConstraints do modo como aparecem no customizador do GridBagLayout. Estes nomes no so os mesmos que sero encontrados na documentao javadoc da classe, onde seguido um estilo mais telegrfico, na sintaxe de Java. Por exemplo, a propriedade "Grid Width" do customizador na verdade gridWidth; e "Internal Padding X" ipadx. Grid X e Grid Y indicam a posio do componente dentro da tabela ou grade utilizada pelo GridBagLayout para posicionar os componentes. Grid Width e Grid Height determinam a quantidade de clulas da tabela que sero ocupadas pelo componente, respectivamente na largura e altura. Fill indica se o componente ir ocupar seu tamanho mnimo, deixando vazio o restante das clulas ocupadas; ou se ele ser expandido para ocupar todo o espao alocado para a clula. A expanso pode ser apenas na vertical (valor Vertical), apenas na horizontal (Horizontal), ou em ambos os sentidos (Both). Internal Padding X e Internal Padding Y indicam espao acrescentado ao prprio componente, aumentando o seu tamanho mnimo, em vez de acrescentado clula que o contm. Anchor indica o alinhamento do componente em relao suas clulas, caso ele no preencha toda a rea alocada a elas. Seus valores possveis so baseados nos pontos cardeais, como North ou SouthEast. Weight X e Weight Y Valores maiores do que zero indicam que a clula ser expandida para alm do seu tamanho mnimo, ocupando o espao na largura ou altura que sobrar no container. Estas propriedades costumam ser utilizadas apenas quando o container pode ser redimensionado pelo usurio. Insets indicam espaamentos a serem inseridos nas quatro bordas da clula, afastando o componente destas bordas. Dois componentes em clulas adjacentes e com espaamentos zerados sero exibidos "grudados" um no outro. Dicas do editor visual Aqui esto reunidas algumas dicas que podem tornar mais produtivo o uso do editor visual do NetBeans para a construo de interfaces Swing. A maioria explora o uso do boto direito do mouse na rea de desenho ou no inspetor como alternativa viso de propriedades. Quais propriedades foram alteradas?

12

A viso de propriedades coloca em negrito os nomes das propriedades que esto com valores diferentes do padro, de modo que fica fcil verificar o que foi customizado em um componente, por exemplo, quando se deseja deixar um outro componente com a mesma aparncia. Para retornar propriedades modificadas aos seus valores padro, abra o customizador da propriedade e clique no boto Reset to Defaults.

Alterando o texto de um componente Componentes que exibem textos (como JLabel, JButton e JMenuItem) oferecem em seu menu de contexto a opo Edit Text para edio rpida do texto do componente diretamente na rea de desenho.

Alterando o layout de um container O gerenciador de layout de um container tambm pode ser modificado diretamente pelo menu de contexto.

Renomeando um componente importante dar a todos os componentes nomes intuitivos, porque esses nomes so utilizados nas propriedades do container (por exemplo, JFrame, JDialog ou JPanel) que os contm. O menu de contexto do componente fornece a opo de renomear o componente, mas por algum bug ela nem sempre funciona se for utilizada na rea de desenho do editor. Por outro lado, ela sempre funciona se utilizada na viso do inspetor.

Novas linhas ou colunas em um GridBagLayout No customizador do GridBagLayout, pode-se criar novas linhas e colunas simplesmente arrastando-se o componente para alm da parte inferior da grade, ou para

13

alm da fronteira direita da grade. No processo pode-se criar tambm vrias linhas e colunas vazias, que podero depois ser ocupadas por novos componentes. Caso voc queira inserir novos componentes no incio (ou no meio) da grade, inicie arrastando os componentes mais direita (ou mais embaixo) para criar novas linhas; e depois arraste os demais componentes para as clulas criadas, at que fiquem clulas vazias nas posies desejadas.

Figura 1. Esboo da aplicao Todo

Figura 2. Criao da janela ListaTarefas

14

Figura 3. Editor visual do NetBeans 4.0 (esquerda) e do 4.1 (direira). Notem a posio diferente do inspetor e a configurao do palete de componentes.

Figura 4. Prottipo parcial da janela principal (ListaTarefas); observe o agrupamento dos botes (4, 2, 1) na barra de ferramentas

Figura 5. Hierarquia de objetos da janela principal

15

Figura 6. Abas do customizador para o TableModel do JTable na janela principal

Figura 7. Menu Arquivo na pr-visualizao do editor visual

Figura 8. Estrutura completa de menus da janela principal, visualizada no inspetor

16

Figura 9. Escolhendo um cone para um item de menu ou toolbar

Figura 10. Barra de ferramentas do prottipo depois de configurada com os cones

Figura 11. Configurando mnemnicos e aceleradores no NetBeans (propriedades correspondentes destacadas em amarelo)

Figura 12. Os menus da aplicao completamente configurados

Figura 13. Dilogo de edio de tarefas, rascunhado com o Null Layout

17

Figura 14. Customizador de layout do dilogo de edio de tarefas, aps a converso para um GridBagLayout

Figura 15. Forma final do dilogo de edio de tarefas

Figura 16. Customizador do GridBagLayout do dilogo de edio de tarefas

18

Figura 17. Aplicao Todo com o look-and-feel GTK do Linux Listagem 1. Modificaes na classe principal da aplicao para iniciar a janela da listagem de tarefas package todo; import javax.swing.*; import todo.visao.*; public class Main { public Main() {} public static void main(String[] args) { JFrame w = new ListaTarefas(); w.pack(); w.setVisible(true); } }

Listagem 2. Cdigo vinculado ao evento actionPerformed no primeiro boto da barra de ferramentas, para exibir o formulrio de edio de tarefas import javax.swing.*; // ... private void botaoAdicionarActionPerformed(java.awt.event.ActionEvent evt) { JDialog d = new EditaTarefa(this, true); d.pack(); d.setVisible(true); }

19

Parte 2: JTable, MVC Aplicado e Tratamento de Eventos Saiba como customizar componentes JTable, organizar o tratamento de eventos, estruturar uma aplicao visual para facilitar extenses e manutenes. Nesta edio, damos continuidade construo da aplicao iniciada na edio anterior, apresentando conceitos fundamentais de desenvolvimento Java e recursos da srie 4.x do IDE livre NetBeans. A primeira parte foi focada na programao visual e em como o NetBeans pode ser utilizado para prototipar uma interface com usurio baseada no Swing, alm de mostrar caractersticas dos principais gerenciadores de layout. Nesta segunda parte, passamos ao editor de cdigo. Vamos customizar o visual da tabela que exibe as tarefas, para indicar com cores diferentes tarefas completadas, atrasadas ou em estado de alerta. Tambm iremos tratar dos eventos gerados pelos componentes da interface, evoluir a arquitetura e saber pelos componentes da interface, evoluir a arquitetura e saber como evitar que o tratamento de eventos transforme seu cdigo orientado e objetos em cdigo espaguete. Arquitetura MVC em aplicaes Grficas Durante a prototipao da interface grfica, buscamos ficar o mximo possvel dentro do editor visual do NetBeans. O objetivo era apenas criar uma casca visual para a aplicao que pudesse ser avaliada e discutida com os usurios. Agora vamos comear a colocar lgica por trs dessa casca, permitindo avaliar e testar a real funcionalidade da aplicao. comum, no desenvolvimento de aplicaes visuais, acabar gerando cdigo desorganizado, onde uma modificao em qualquer parte gera efeitos colaterais nos locais mais inesperados; ou onde a simples adio de uma informao extra exige uma cascata de mudanas em vrias partes da aplicao. Para evitar isso, vamos adotar uma arquitetura muito popular em aplicaes interativas, a arquitetura MVC (Movel-View-Controller, Modelo-Viso-Controlador). A MVC foi usada ou descrita em vrios artigos na Java Magazine (em maior parte no contexto de aplicaes web). Nela, cada classe tem um papel bem definido: tratar da exibio das informaes (Viso); responder a aes do usurio (Controlador); ou cuidar da consistncia e persistncia dos dados (Modelo). Classes com papis diferentes so praticamente independentes entre si, e assim possvel modific-las sem medo de gerar efeitos colaterais. O uso da arquitetura MVC tambm torna fcil identificar onde fazer cada mudana. Para tornar o uso da arquitetura bem explcito, iremos organizar as classes Java em trs pacotes: todo.visao, todo.controle e todo.modelo. No pacote visao esto classes grficas (como janelas ou componentes personalizados), ou classes necessrias para o seu funcionamento. Essas classes no tomam decises a respeito de como uma operao deve ser realizada este o papel das classes do pacote controle, as quais efetivamente respondem aos eventos do usurio (como cliques num item de menu) e decidem qual operao realizar. J as classes do pacote modelo representam os dados da aplicao, e contm a inteligncia necessria para realizar aes sobre esses dados.

Figura 1. Dependncias entre componentes no modelo MVC

20

A Figura 1 ilustra o relacionamento entre os pacotes, usando um diagrama UML (o desenho de pasta representa um pacote e agrupa vrias classes)1. Observe que o Controlador fica no meio do caminho entre a Viso e o Modelo2. Essa separao traz um benefcio adicional: ela permite que uma mesma Viso seja reutilizada com vrios Modelos contendo as mesmas informaes mas obtendo essas informaes de fontes diferentes (ex.: um Modelo baseado em banco de dados e outro acessando arquivos XML). Pelo seu lado, o Modelo fica independente da interface com o usurio (que faz parte da Viso): as classes do Modelo podem, por exemplo, ser utilizadas depois, numa aplicao web ou num MIDlet J2ME. Inteligncia em objetos No incio da Orientao a Objetos, era comum defender-se a idia de que um objeto deveria conter toda a intelignciarelacionada a ele. Mas com o passar do tempo verificouse que essa estratgia poderia levar a objetos gordos, concentrando mutas funcionalidades, e com manuteno difcil e baixo desempenho. Hoje, no entanto, se considera uma alternativa vlida criar tambm objetos burros, que apenas trafegam informaes de um objeto inteligente para outro, deixando-os mais independentes entre si. No nosso caso, os objetos burros sero Value Objects (VOs)( que so JavaBeans, com atributos e seus mtodos get/set, e possivelmente alguma funcionalidade localizada). E os objetos inteligentes so os objetos de Viso, Modelo e Controle. A nica classe VO de que necessitamos agrupa todas as informaes de uma tarefa, ento este ser o seu nome. Na nossa aplicao, teremos classes de Viso que sabem representar graficamente uma tarefa, e classes de Modelo que sabem como recuperar e salvar tarefas do bando de dados (ou de um collection etc.). Para simplificar, a classe Tarefa ( e outros VOs que surgirem) podem ser deixados no mesmo pacote das classes de Modelo. Afinal, so as operaes implementadas no Modelo que determinam quais informaes devero estar nos VOs.

Arquitetura da aplicao Nossas classes de Viso ListaTarefas (um JFrame) e EditaTarefa (um JDialog) foram prototipadas no artigo anterior. Agora estamos preocupados em definir a interface externa destas classes, isto , o que iro expor para o Controlador. Precisamos definir os eventos, que representam aes realizadas pelo usurio, e os mtodos para manipular informaes encapsuladas em VOs. Teremos apenas uma classe no Controlador, chamada ConsultaEditaTarefas. Em aplicaes mais complexas, poder haver vrias classes controladoras. Uma estratgia para comear criar um controlador para cada conjunto de operaes consultar-editar-apagar da aplicao. Nosso exemplo tambm ter apenas uma classe no Modelo, chamada GerenciadorTarefas. Esta classe um DAO (Data Access Object) e ser responsvel por ler e atualizar registros no banco de dados. Aplicaes mais complexas tero classes de Modelo que encapsulam processos de negcios em vez de apenas entidades de informao. E iro para o Controlador apenas estas classes de mais alto nvel, reservando os DAOs para uso interno. Na Figura 2 temos um modelo UML contendo as classes que iremos desenvolver. Note como todas as classes no diagrama tm dependncias em relao ao VO Tarefa. (Mas como este no tem inteligncia significativa, ele com freqncia omitido em diagramas de classes, e na avaliao de dependncias entre classes da aplicao).

Comeando a construo

21

Nossa idia prosseguir construindo a aplicao de cima para baixo. Iniciamos pela interface com o usurio (Viso) e vamos descendo at chegar logica de banco de dados (Modelo). Em cada etapa ser feito o mnimo de trabalho necessrio para que seja possvel testar uma nova funcionalidade. Assim, nossos objetos de modelo sero por algum tempo verses temporrias, mantendo os dados em memria sem acessar o bando de dados. A classe Main (no representada na Figura 2) permanece como sendo a classe principal da aplicao, e do projeto no NetBeans. Seu papel instanciar e conectar as classes de Viso, Modelo e Controle. A Listagem 1 apresenta a classe Tarefa e a Listagem 2, a classe Main. Note que Tarefa fornece alguns mtodos utilitrios relacionados com a manipulao das datas de concluso e prazo de alerta. Parece ir contra a recomendao de que um VO no deve ter inteligncia, mas estes mtodos no dependem de nada externo ao prprio objeto, ento este o seu lugar. A Listagem 3 apresenta a classe GerenciadorTarefas, que implementa um nico mtodo: listaTarefas(). Neste ponto, o mtodo constri um java.util.List contendo objetos Tarefas pr-fabricados para que seja possvel testar o cdigo da Viso e do Controlador. Voc pode gerar os mtodos get/set automaticamente no NetBeans. Depois de definir os atributos da classe Tarefa, clique com o boto direito no editor de cdigo (ou na viso de projeto do NetBeans) e escolha Refactor|Encapsulate Fields. A Listagem 4 mostra a primeira verso da classe controladora ConsultaEditaTarefas. Tudo o que ela faz no momento passar para a Viso (ListaTarefas) a lista de objetos Tarefa retornada pelo Modelo (GerenciadorTarefas). Note que as classes de Viso devem ter mtodos para receber as tarefas, e responsabilidade da Viso repassar os dados das tarefas para componentes visuais internos, como caixas de texto e componente JTable.

Figura 2. Principais classes da aplicao Lista de Tarefas Modelo da aplicao e models do Swing Na maioria dos toolkits grficos, os objetos visuais de tabela e de lista manipulam apenas arrays de strings; para preench-los, os dados devem ser convertidos em strings e inseridos linha a linha (ou clula a clula). Esta abordagem tem dois problemas: aumento do consumo de memria, pois os dados so duplicados na tabela; e maior tempo gasto para inserir um conjunto extenso de dados. No Swing, entretanto, os dados para exibio num componente de tabela (JTable) devem se passados num classe que implementa a interface TableModel. Esta classe fica responsvel por fornecer para a tabela os dados das clulas visveis, e em informar quando os dados forem modificados. Com isso, no so acrescentadas ou alteradas linhas na tabela em si; essas operaes so realizadas no TableModel associado tabela. O Swing fornece a classe DefaultTableModel, que armazena dados em vetores de vetores (java.util.Vector), emulando a abordagem dos outros toolkits. Isso permite comear rapidamente, mas o recomendado mesmo criar o seu prprio TableModel, que acessa diretamente os VOs. Dessa forma no h duplicao de dados e se obtm ganhos de

22

performance, pois a tabela pede ao seu modelo apenas os dados que ir efetivamente utilizar. Todos os componentes do Swing seguem a abordagem descrita: em vez de o prprio componente armazenar as informaes que exibe, essa responsabilidade e delegada para um objeto model do Swing. (O uso do nome model nas classes e interfaces utilizadas pelos componentes do Swing no coincidncia. Para uma discusso mais aprofundada sobre o assunto, consulte o quadro Arquitetura MVC e o Swing.) Listagem 1. VO Tarefa package todo.modelo; import java.util.Date; import Java.util.Calendar; public class Tarefa { private int id; private String descricao; private int prioridade; private Date dataConclusao; private boolean gerarAlerta; private int diasAlerta; private String observacoes; private boolean concluida; private Calendar getDataHojeNormalizada() Calendar hoje - Calendar.getlnstanceC); hoje.set(Calendar.HOUR_OF_DAY. 0); hoje.set(Calendar.MINUTE. 0); hoje.set(Calendar.SECOND. 0); hoje.set(Calendar.MILLISECOND, 0); return hoje; } public boolean isAtrasada() { Date conclusao = getDataConclusao(); if (conclusao == null) return false; else { return conclusao.compareTo( getDataHojeNormalizada().getTime()) < 0; } } public boolean isAlertaAtivo() { Date conclusao = getDataConclusao(); if (!isGerarAletra() || conclusao == null) return false; else { Calendar diaConclusao = Calendar.getlnstance(); diaConclusao.setTime(getDataConclusao()); int dias = getDataHojeNormalizada().get(Calendar.DAY_OF_YEAR) - diaConclusao.get(Calendar.DAY_OF_YEAR); return dias = 1); habilitaRemocao(tarefas.getSelectedRowCount() >= 1); } }; public void setListaTarefas(List tarefas) { this.tarefas.setModel(new TarefasTableModel(tarefas)); } public ListaTarefas() { initComponents(); tarefas.setAutoCreateColumnsFromModel(false); FontMetrics fm = tarefas.getFontMetrics(tarefas.getFont()); tarefas.setColumnModel(new TarefasColumnModel(fm)); tarefas.getSelectionModel().addListSelectionListener( selectionListener); habilitaEdicao(false); habilitaRemocao(false); }

// ... cdigo gerado pelo editor visual do NetBeans }

Eventos externos: adicionando e editando tarefas Para no poluir as classes de Viso com dezenas de mtodos no estilo addEditarTarefaListener(), addAdicionarTarefaListener etc. decidimos expor em cada classe de Viso apenas o evento ActionEvent sua classe controladora. A classe ActionEvent inclui a propriedade actionCommand, que espelha a propriedade de mesmo nome do componentes que gerou o evento. Dessa forma, o controlador pode saber exatamente quando a operao foi requisitada pelo usurio, sem, ter que definir listeners adicionais. A Listagem 11 apresenta a classe ConsultaEditaTarefas modificada para tratar apenas dos eventos de adicionar e editar tarefa. A Listagem 12 mostra as modificaes nas classes ListaTarefa para gerar o evento (lembre-se de configurar os actionCommands no editor visual). A Listagem 13 apresenta as modificaes no dilogo EditaTerefas, de modo que os botes de Salvar e de Remover tambm gerem eventos ActionEvent para o controlador. Como o cdigo de gerenciamento dos listeners e de gerao de evento o mesmo para ambas as classes, ele foi movido para uma classe utilitria ActionSupport, apresentada na Listagem 14. Observe que o Controlador que sabe se o dilogo foi instanciado para adio de uma nova tarefa, ou para a edio de uma nova tarefa existente. Mas o dilogo necessita receber esta informao para desabilitar o boto de remover em caso de uma tarefa nova. Foram omitidas as listas das classes ModeloException e ValidacaoException, ambas no pacote todo.modelo. Estas classes simplesmente sinalizam erros ocorridos internamente nas classes de modelo; representam erros de alto nvel da aplicao, em vez de erros de baixo nvel como IOException ou NumberFormatException. Note que

33

as reas de mensagens das duas classes de Viso so utilizadas para exibir a mensagem de erro fornecida pelas excees vindas do Modelo.

Listagem 11. Classe controladora modificada para tratar da adio e edio de tarefas package todo.controle; //... imports public class ConsultaEditaTarefas implements ActionListener { // ...atributos omitidos public ConsultaEditaTarefas(ListaTarefas visao. GerenciadorTarefas modelo) { this.visao = visao; this.modelo = modelo; visao.addActionListener(this); listaTarefas(); } public void listaTarefas() { visao.setListaTarefas(modelo.listaTarefas()); public void actionPerformed(java.awt.event.ActionEvent e) { try { if (e.getActionCommand().equals(novaTarefa)) { editaTarefa(true); } else if (e.getActionCommand().equals(editarTarefa)) { editaTarefa(false); } else if (e.getActionCommand().equals(salvarTarefa)) { salvaTarefa(); } else visao.setMensagem(No implementado: [" + e.getActionCommand() + J, true); } catch (Exception ex) { visao.setMensagem(ex.getMessage(), true); } } private void editaTarefa(boolean novaTarefa) { editaTarefaDialog = new EditaTarefa(visao.true); editaTarefaDialog.setNovaTarefa(novaTarefa); if (novaTarefa) editaTarefaDialog.setTarefa(new Tarefa( )); else editaTarefaDialog.setTarefa(visao. getTarefaSelecionada()); editaTarefaDialog.addActionListener(this); editaTarefaDialog.setVisible(true); }

34

private void salvaTarefa() { Tarefa tarefa = editaTarefaDialog.getTarefa(); try { if (editaTarefaDialog.isNovaTarefa()) modelo.adicionaTarefa(tarefa); else modelo.editaTarefa(tarefa); editaTarefaDialog.dispose(); editaTarefaDialog = null; listaTarefas(); } catch (ModeloException e) { editaTarefaDialog.setMensagem(e.getMessage(), true); } } } Listagem 12. Modificaes em ListaTarefa para gerar o evento Action para o Controlador package todo.visao; // ... imports public class ListaTarefas extends javax.swing.JFrame { private ActionSupport actionSupport = new ActionSupport(this); public void addActionListener(ActionListener listener) { actionSupport.addActionListener(listener); } public void removeActionListener(ActionListener listener) { actionSupport.removeActionListener(listener); } public void setMensagem(String msg, boolean isErro) { status.setText(msg); if (isErro) status.setForeground(Color.RED); else status.setForeground(Color.DARK_GRAY); } public void setListaTarefas(List tarefas) { this.tarefas.setModel(new TarefasTableModel(tarefas)); } public ListaTarefas() { initComponents() ; tarefas.setAutoCreateColumnsFromModel(false); FontMetrics fm = tarefas.getFontMetrics( tarefas. getFont()); tarefas.setColumnModel(new TarefasColumnModel(fm)); menuAdicionar.addActionListener(actionSupport); menuEditar.addActionListener(actionSupport); botaoAdicionar.addActionListener( actionSupport) ; botaoEditar.addActionListener( actionSupport) ;

35

} // ... Cdigo gerado pelo NetBeans } O mesmo controlador responde aos eventos, tanto do JFrame ListaTarefas quanto do JDialog EditaTarefa. Isto faz sentido porque o JDialog apenas parte de um processo iniciado pelo JFrame, e no uma classe de Viso independente. Assim tambm podemos manter o dilogo aberto em caso de erros de validao dos dados digitados pelo usurio. No final das contas, temos no cdigo do controlador um grande switch, onde feita a deciso de qual mtodo da classe de Modelo chamar baseado no valor do actionCommand do evento. Numa aplicao maior, esse cdigo poderia ser parametrizado, como sugere o quadro Frameworks MVC para aplicaes grficas. Mais uma vez estamos em condies de rodar a aplicao e testar a funcionalidade recm-acrescentada. A forma final do projeto est na Figura 8. Estamos quase com a aplicao pronta, exceto pelo fato de que as edies so perdidas quando ela encerrada. A soluo para essa e outras questes ser o assunto da prxima parte.

Figura 8. Classes da aplicao aps o tratamento dos eventos de adicionar e editar tarefas.

Listagem 13. Modificaes em EditaTarefa para gerar o evento Action para o controlador package todo.visao; // ... imports public class EditaTarefa extends javax.swing.JDialog{ private Tarefa tarefa; private boolean novaTarefa; public void setNovaTarefa(boolean novaTarefa) { this.novaTarefa - novaTarefa; remover.setEnabled(!novaTarefa); if (isNovaTarefa()) setMensagem(Fornea os dados para a nova tarefa. false); else setMensagem(Alterando os dados da tarefa. false); } public boolean isNovaTarefa() { return novaTarefa;

36

public void setMensagem(String msg. boolean isErro) { // ... igual ao correspondente em ListaTarefa } public void setTarefa(Tarefa tarefa) { this.tarefa = tarefa; descricao.setText(tarefa.getDescricao()); prioridade.setValue(tarefa.getPrioridade()); // ... demais atributos omitidos } public Tarefa getTarefa() { tarefa.setDescricao(descricao.getText()); tarefa.setPrioridade(((Number)prioridade.getValue()), intValue()); // ... demais atributos omitidos return tarefa; } // actionSupport(), addActionListener e // removeActionListener() iguais aos de ListaTarefas ... public EditaTarefa(java.awn.Frame parent, boolean modal) { super(parent, modal); initComponents(); salvar.addActionListener(actionSupport); remover.addActionListener(actionSupport); } // cdigo gerado pelo editor visual do NetBeans } Listagem 14. Classe utilitria ActionSupport package todo.visao; // .. imports public class ActionSupport implements ActionListener { private Window window; public ActionSupport(Window window) { this.window = window; } private List listeners = new ArrayList< ActionListener>(); public void addActionListener(ActionListener listener) { listeners.add(listener); } public void removeActionListener(ActionListener listener) { listeners.remove (listeners) ; } public void fireActionEvent(ActionEvent e) { Iterator it = listeners.iterator(); while (it.hasNext()) {

37

ActionListener listener = it.next(); listener.actionPerformed(new ActionEvent(window, ActionEvent.ACTION_PERFORMED, e.getActionCommand())); } } public void actionPerformed(ActionEvent e) { fireActionEvent(e); } }

Concluses Neste artigo vimos como configurar um componente JTable do Swing, que possui flexibilidade de customizao sem igual em outros toolkits grficos. Vimos tambm que a plena explorao das capacidades desse componente exige a criao de novas classes em vez de simplesmente definir propriedades no editor visual. E mostramos como tratar eventos gerados pelos componentes grficos, sem cair no cdigo espaguete - mantendo a separao de responsabilidades proposta pela arquitetura MVC. O prximo artigo da srie ir demostrar como filtrar o contedo da lista de tarefas e como armazenar as tarefas num banco de dados, alm de apresentar um componente para a seleo visual de datas. ________________________________________________________ [1] Os diagramas UML neste artigo foram criados com a aplicao Java. [2] Nesta artigo estamos usando Viso, Modelo e Controle praticamente como sinnimos para os pacotes de mesmo nome; em aplicaes mais complexas, esses pacotes seriam quebrados em vrios.livre ArgoUML (argouml.org). [3] Neste caso, que no ilustrado pela aplicao de exemplo, o vnculo configurado por meio de um atributo do prprio JTable, um Map, onde as chaves so objetos Class (como String.class, Data.class) e os valores so os objetos TableCellRenderer criados pelo desenvolvedor.

Arquitetura MVC e Swing O Swing foi arquitetado de acordo com o modelo MVC. Cada classe ou componente visual que manipulamos (por exemplo um JButton) na verdade a agregao de um Controlador, que obtm dados de um Modelo, com uma Viso que fornecida pelo lookand-feel atual. Esta viso chamada de UI Delegate, indicando que ela que realmente desenha o componente no vdeo. A Figura Q1 ilustra o uso da arquitetura MVC no Swing. (Note que neste diagrama no esto representados nomes de classes ou interfaces reais, mas apenas uma descrio da arquitetura que aplicada individualmente a cada tipo de componente.) Nos casos mais simples, o programador no precisa fornecer a classe model para um componente Swing, pois o prprio componente instancia sua classe model padro (ex.: DefaultTableModel) e oferece mtodos utilitrios para armazenar valores nessa instncia. Assim o programador fica com a impresso de estar lidando com uma nica classe virtual, e essa impresso reforada num editor visual como o do NetBeans. Alguns tipos de models do Swing so compartilhados entre vrios tipos diferentes componentes. Por exemplo, uma barra de rolagem e um spinner podem utilizar o mesmo modelo (que indica os limites superior e inferior, e os incrementos para o valor armazenado). possvel tambm que um componente esteja associado ao mesmo tempo a vrios models diferentes, por exemplo um que representa os dados propriamente ditos e outro que indica os elementos selecionados pelo usurio. o que acontece com o JTable, que tem um TableModel um ListSelectionModel e um ColumnModel.

38

Um erro comum, entretanto, acreditar que as classes model do Swing devem ser usadas como classes de Modelo de aplicao MVC. No o caso, pois estamos lidando com nveis de abstrao diferentes (a aplicao como um todo e o toolkit grfico especfico). Caso as classes de Modelo da aplicao sejam construdas segundo os models do Swing elas ficaro dependentes da Viso, ou seja, haver uma independncia grande e indesejada do Modelo com a Viso.

Figura Q1. Viso geral da arquitetura MVC, conforme utilizada pelos componentes do Swing

Frameworks MVC para aplicaes grficas O leitor com experiencia em frameworks MVC para aplicaes web, como o Struts, ir logo imaginar que o grande switch no Controlador do nosso exemplo poderia ser substitudo por um arquivo de configurao. Esta uma das idias bsicas em frameworks par aplicaes grficas, como o NetBeans Platform (netbeans.org/products/platform). (O NetBeans Platform uma separao do cdigo do Controlador MVC do NetBeans do restante do IDE, de modo que ele possa ser utilizado em outros tipos de aplicaes.) Um exemplo popular de aplicao construda desta forma o MC4J (mc4j.sf.net), um console para gerenciamento de aplicaes que suportam o padro JMX. Vale a pena conhecer e estudar o cdigo dessa ferramenta open source. Infelizmente, frameworks MVC para aplicaes grficas ainda no atingiram o mesmo nvel de popularidade que tm em aplicaes web. Talvez isso seja por conta da facilidade em construir aplicaes simples num editor visual, sem se preocupar com a estruturao do cdigo, o que pode fazer com que considerem pequeno o ganho em produtividade se fosse adotado um framework. Mas isso parece estar finalmente mudando, com o crescimento de projetos relacionados, do Eclipse.org e da comunidade JavaDesktop no portal java.net.

Links http://java.sun.com/products/jfc/tsc/articles/architecture Documento que descreve a arwquitetura do Swing e sua aplicao do padroMVC. http://netbeans.org Site oficial do Netbeans

39

Parte 3: Banco de Dados e Preferncias dos Usurios Nesta parte conclumos a aplicao, implementando suporte a preferncias e acesso a banco de dados, e fazendo ajustes finais Neste artigo completamos aplicao de Lista de Tarefas (Todo), que iniciamos nesta coluna na Edio 25 um exemplo completo do desenvolvimento de uma aplicao grfica baseada no Swing, utilizando os recursos do IDE livre NetBeans. O primeiro artigo desta srie demonstrou como usar os recursos do editor visual do NetBeans para prototipar a interface como o usurio. O segundo mostrou como customizar a exibio de dados em JTable do Swing e como organizar o tratamento de eventos na aplicao, de acordo com a arquitetura Model-View-Controller. Este ltimo artigo mostra como filtrar as informaes exibidas na tabela e como ler e gravar as informaes em um banco de dados relacional. Para manter a aplicao simples de instalar e distribuir, ser utilizado o banco de dados HSQLDB (apresentado na Edio 7). Dessa forma, a aplicao final ser formada por apenas dois pacotes jar: o Todo.jar gerado pelo NetBeans, contendo as classes da aplicao; e o hsqldb.jar do HSQLDB. O quadro Configurando o projeto no NetBeans descreve como configurar o IDE para uso do HSQLDB durante o desenvolvimento da aplicao. E o leitor que preferir utilizar um banco de dados diferente pode consultar o quadro Experimentando com outros bancos. Arquitetura da aplicao No artigo anterior, chegamos a uma aplicao bastante funcional, que permitia edio e consulta de tarefas armazenadas em memoria, mas sem ainda persistir os dados em disco. Utilizamos a arquitetura MVC, pela qual as classes da aplicao devem atuar apenas num dos seguintes papis: gerenciamento dos dados (Modelo), visualizao dos dados (Viso), ou resposta s aes do usurio (Controle). Criamos um pacote para cada parte: o diagrama de classes UML da Figura 1 representa as principais classes desses pacotes.

Figura 1. Principais classes da aplicao de exemplo, desenvolvidas nas duas partes desta srie. As classes em azul-claro so neste artigo, e a classe GerenciadorTarefas praticamente reescrita.

No pacote todo.modelo, temos a classe Tarefa, construda com um VO (Value Object, um repositrio de dados com pouca ou nenhuma inteligncia prpria). H tambm a classe GerenciadorTarefas, cuja verso inicial tinha o objetivo de fazer uma simulao da persistncia mantendo os dados em memria, pois o foco estava nas classes de viso e controle. Nesta edio vamos expandir a classe GerenciadorTarefas para conter o cdigo de persistncia num banco de dados. Tambm ser criada uma nova classe de modelo,

40

chamada Parametros, contendo os dados de configurao da aplicao por exemplo, o diretrio onde so salvos os arquivos do bando de dados. O pacote todo.visao contm duas janelas que foram prototipadas na primeira parte, ListaTarefas (um JFrame) e EditaTarefas (um JDialog), alm de vrias classes auxiliares. A Figura 2 reapresenta as duas janelas, para que o leitor que no tenha idia da aparncia e funcionalidade da aplicao. O pacote todo.controle contm uma nica classe, ConsultaEditaTarefas, que responde s aes do usurio para criar, editar ou listar tarefas. Essas classe delega as aes em si para a classe de modelo GerenciadorTarefas e comanda a atualizao das classes de viso, quando necessrio. Neste artigo ser criada outra classe controladora, chamada CriaAbreListaTarefas, responsvel por criar novos bancos de dados existentes em outras localizaes. Ela tambm receber as funcionalidades de miscelnea da aplicao, por exemplo a exibio da caixa Sobre.

Figura 2. Janelas da aplicao Lista de Tarefas Os trs pacotes contm ainda uma srie de classes auxiliares no descritas aqui, por exemplo, excees customizadas ou modelos para o JTable do Swing. Elas no afetam a arquitetura da aplicao e na maioria dos casos so utilizadas por classes fora dos respectivos pacotes. A Figura 3 apresenta as classes da aplicao, na viso de projetos do NetBeans. O quadro Todas as classes do exemplo apresenta uma breve descrio do papel de cada uma.

Figura 3. Todas as classes da aplicao final, na viso de projeto do NetBeans.

41

Acesso ao banco de dados A nova verso da classe GerenciadorTarefas foi construda como um DAO. A idia que as demais classes da aplicao no tenham conhecimento do uso de banco de dados relacionais ou de outra tecnologia de armazenamento e recuperao de informaes elas apenas chamam os mtodos da classe DAO para ler e gravar objetos. Nosso DAO fornece mtodos como listaTarefas() e editaTarefa(), que sero chamados pelo controlador apropriado (no caso, ConsultaEditaTarefas) de acordo com a operao solicitada pelo usurio. A Listagem 1 fornece o cdigo completo dessa classe, que ser detalhado a seguir. A nova classe de modelo ir interagir com a classe Parametros para obter as configuraes de acesso ao banco de dados, que sero utilizadas em conecta() para criar uma conexo ao HSQLDB. A conexo mantida como varivel de instncia (atributo) da classe DAO. fornecido tambm o mtodo desconecta(), para que a aplicao possa fechar a conexo quando for encerrada. O prprio HSQLDB cria automaticamente uma base de dados vazio no momento da conexo, caso o arquivo referenciado na URL JDBC no exista. Como padro, estamos utilizando a base dB/todo (que corresponde ao arquivo dB/todo.script) no diretrio pessoal do usurio, que ser o $HOME em sistemas Linux ou a pasta correspondente em sistemas Windows. Para simplificar a utilizao, o prprio DAO ir criar as tabelas na base de dados, caso elas no existam. Isso feito pelos mtodos privativos existemTabelas() e criaTabelas(). Visando simplificar a escrita dos mtodos de consulta e alterao de dados propriamente ditos, so fornecidos os mtodos auxiliares finaliza(), executa(), prepara(), consulta() e altera(), que encapsulam seqncias comuns chamadas JDBC. Todos eles, exceto os dois ltimos, poderiam ser movidos para uma superclasse abstrata numa aplicao com vrios DAOs. Os mtodos consulta() e altera() seriam praticamente iguais, variando apenas quanto aos nomes dos campos, em outras classes DAO de uma aplicao maior. O mtodo finaliza() tem importncia especial, pois temos que garantir que os recursos do banco de dados sejam liberados o quanto antes, mesmo que ocorram excees durante o acesso. Todos os mtodos de acesso ou alterao devem conter uma clusula finally que chama finaliza() (veja por exemplo o mtodo executa()). Os mtodos especficos de acesso e alterao de dados adicionaTarefa(), editatarefa(), marcaComoConcluida(), removeTarefa(), listaTarefas() e listaTarefasComAlarme() so todos escritos chamando a finaliza() garantia em caso de erros. Por fim, o DAO fornece o mtodo validaTarefa(), que chamado pelo controlador antes de se inserir ou modificar uma tarefa. Isso permite que a operao seja abortada, e o usurio informado de que houve erros na digitao dos atributos da tarefa. Observe que os mtodos da classe de todo.modelo, nunca retornam excees de baixo nvel ao controlador, por exemplo SQLException ou IOException. So retornadas subclasses de ModeloException, como a BancoDeDadosException. Estas classes, por sua vez, encapsulam a exceo de baixo nvel como causa (acessvel pelo mtodo getCause() de Exception), de modo que a informao esteja disponvel durante a depurao da aplicao. Isso foi feito para que o controlador fique completamente isolado de qualquer conhecimento relativo ao banco de dados ou outro mecanismo de persistncia. O mesmo estilo de programao poderia ser utilizado caso fosse empregada outra forma de persistncia, por exemplo arquivos XML.

42

Listagem 1. Classe de modelo GerenciadorTarefas package todo.modelo; import import import import import java.io.*; java.sql .*; java.text.*; java.util.List; java.util.ArrayList;

public class GerenciadorTarefas { private Parametros params; private Connection con; private Statement stmt; private ResultSet rs; public GerenciadorTarefas(Parametros params) throws BancoDeDadosException { this.params = params; conecta(); } public void reconecta(String database) throws BancoDeDadosException { desconecta(); params.setDatabase(database); conecta(); } private void conecta() throws BancoDeDadosException { try { Class.forName(params.getJdbcDriver()); con = DriverManager.getConnection(params.getJdbcUrl(). "sa", ""); if (!existemTabelasC) criaTabelas() ; } catch (BancoDeDadosException e) { throw new BancoDeDadosException( "No foi possvel criar as tabelas no banco de dados", e.getCause()); } catch (ClassNotFoundException e) { throw new BancoDeDadosException( "No foi possvel carregar o driver do banco de da dos" , e); } catch (SQLException e) { throw new BancoDeDadosException( No foi possvel conectar ao banco de dados" , e); } } private boolean existemTabelas() { try { String sql = "SELECT COUNT(*) FROM todo"; stmt = con.createStatement(); rs = stmt.executeQuery(sql);

43

return true; } catch (SQLException e) { return false; } finally { finaliza(); } } private void criaTabelas() throws BancoDeDadosException { executa ("CREATE TABLE todo (" + "id IDENTITY. " + "descricao VARCHAR(100), " + "prioridade INTEGER, " + "concluida BOOLEAN, " + "dataConclusao DATE, " + "alerta BOOLEAN, " + "diasAlerta INTEGER, " + "observacoes VARCHAR(250) " + ")"); } public void desconecta() try { if (con != null) con.close(); con = null ; } catch (SOLException e) {/* ignora a exceo */} } private void finaliza() { try { if (rs != null) rs.close() ; rs = null; if (stmt != null) stmt.close(); stmt = null; } catch (SOLException e) {/* ignora a exceo*/} } private void executa(String sql) throws BancoDeDadosException{ try { stmt = con.createStatement(); stmt.executeUpdate(sql ); } catch (SQLException e) { throw new BancoDeDadosException( "No foi possvel alterar o banco de dados", e); } finally (finaliza();} } private PreparedStatement prepara(String sql) throws SQLException } try {

44

PreparedStatement pst = con.prepareStatement(sql); stmt = pst; return pst; } finally {finaliza();} } private List consulta(String where, String orderBy) throws BancoDeDadosException { List resultado = new ArrayList(); try { String sql = "SELECT id, descricao, prioridade, concluida, " + "dataConclusao, alerta, diasAlerta, observacoes FROM todo ; if (where != null) sql += "WHERE" + where + " "; if (orderBy != null) sql += "ORDER BY " + orderBy; stmt = con.createStatement(); rs = stmt. executeOuery(sql); while (rs.next()) { Tarefa tarefa = new Tarefa(); tarefa.setId(rs.getInt(1)); tarefa.setDescricao(rs.getString(2)); tarefa.setPrioridade(rs.getInt(3)); tarefa.setConcluida(rs.getBoolean(4)); tarefa.setDataConclusao(rs.getDate(5)); tarefa.setGerarAletraCrs.getBoolean(6)); tarefa.setDiasAlerta(rs.getInt(7)); tarefa.setObservacoes(rs.getString(8)); resultado.add(tarefa); } } catch (SOLException e) { throw new BancoDeDadosException{ "No foi possvel consultar o banco de dados", e); } finally {finaliza(); } return resultado; } private void altera(String sql, Tarefa tarefa) throws BancoDeDadosException { try { PreparedStatement pst = con.prepareStatement(sql); stmt = pst; pst.setString(1, tarefa.getDescricao()); pst.setlnt(2, tarefa.getPrioridade()); pst.setBoolean(3, tarefa.isConcluida()); if (tarefa.getDataConclusao() == null) { pst. setDate(4, null); } else { pst.setDate(4, new Date(tarefa.getDataConclusao().getTime())); }

45

pst.setBoolean(5, tarefa.isGerarAletra()); pst.setlnt(6, tarefa.getDiasAlerta()); pst.setString(7, tarefa.getObservacoes()); pst.executeUpdate(); } catch (SQLException e) { throw new BancoDeDadosException( "No foi possvel alterar o banco de dados", e); } finally { finaliza(); } } public List listaTarefas(boolean prioridadeOuData) throws BancoDeDadosException { return consultaCnull, prioridadeOuData ? "prioridade, dataConclusao, descricao" "dataConclusao, prioridade, descricao"); } public List listaTarefasComAlarme() throws ModeloException { return consulta("alerta = true AND" + "datediff( 'dd' ,curtime().dataConclusao)