Swing Fácil com Groovy: Como criar seus próprios componentes

Não tenho dúvidas que o desenvolvimento de aplicações desktop com Java tem seu problemas. Não digo apenas pela estrutura de composite do Swing, ou de classes gigantes com muitas responsabilidades como o JFrame. Mas mesmo com todos esses problemas vejo o desenvolvimento de aplicações Swing para Java ainda com viabilidade.

Hoje é dia é comodismo desenvolver aplicações para Web. O que acontece é que nem todos os sistemas ou nem todas as funcionalidades dos sistemas podem ser feitas na web, por que?
  • Complexidade do desenvolvimento com JavaScript
  • Consumo de memória do cliente(Browser)
  • Complexidade de tecnologias Ajax VS problemas de uso de Arquiteturas Commet.
  • Falta de bons IDEs e Debuggers para JavaScript
  • Pouca performance na execução de JS devido a sua arvore DOM.
  • Tempo de desenvolvimento e custo de manutenção
Quando desenvolvemos com Swing puro por mais nojento que possa ser ainda assim nos livramos de muitos problemas. Vejam que eu não sou contra o desenvolvimento para web, mas sem sempre é viável, e temos que avaliar a possibilidade de sistemas RichClient.

Como deixar o Swing melhor?

A melhor coisa seria um refatoração e re-design da API mas como isso não é simples e mesmo que feito iria dar muito custo e problemas de manutenção/migração. Então qual seria uma possibilidade intermediária? Groovy!

O Groovy tem um recurso muito bom que é o suporte a Builders que são classes que seguem o pattern Builder. Com esse objetos podem criar objetos de maneira muito mais fácil e produtiva, sem falar que o código fica muito mais simples por se parecer com uma DSL.



Por que usar um Builder?

A questão não é só clareza, simplicidade e produtividade, com um Builder vamos alem disso. Um Builder é como um factory só que parametrizavel, logo se você constrói suas interfaces com Builders do Groovy ao invés de Swing direto você ganha a possibilidade mudar o comportamento da interface sem ter que mudar todas as telas!

Como isso é possível?

Isso é possível devido a duas coisas que se usadas em conjunto vão dar a você a flexibilidade e robustez necessárias a suas aplicações desktop. A primeira delas é fazer hold da variável de builder no seu código para uma classe mais superior. Aqui estou me referindo a boa e velha programação para interfaces, isso é bem possível de se fazer com groovy por que existe o BuilderSupport.

A única coisa que para mim deixou a desejar foi no design do SwingBuilder por que esse cara não segue a mesma hierarquia de classes do BuilderSupport. Bom até a versão 1.5.7 é assim vamos ver se agora nas próximas versões os caras da SS resolvem isso :)

Criando os seus próprios Builders

Criar um builder é uma tarefa relativamente fácil a questão é a complexidade que você irá colocar no seu componente. Vou mostrar como criar um builder de gui que extende o SwingBuilder e adiciona um novo widget que gera uma caixa de texto que só permite digitação de números!

Dependências
  • JDK 1.6
  • Groovy 1.5.7 (groovy-all-1.5.7.jar)
Passos necessários
  • Criar o Builder
  • Criar uma factory
  • Registrar essa factory no builder
Como você pode perceber com poucos passos podemos fazer e já colocar o builder em uso. Vamos ao código do builder então.

CustomSwingBuilder.java

package com.blogspot.diegopacheco.groovy.builder;

import groovy.swing.SwingBuilder;

import com.blogspot.diegopacheco.groovy.builder.factories.NumericTextFactory;

/**
* Builder groovy que adiciona funcionalidades ao builder do Swing.
*
* @author Diego Pacheco
* @since 20/01/2009
* @version 1.0
*
*/
public class CustomSwingBuilder extends SwingBuilder{

public CustomSwingBuilder() {
super();
}

/**
* Método que registra as factories que vao processar os widgets adicionados por você.
* Você deve informar a tag do widgets e a factory que processa o mesmo.
*
*/
@Override
protected void registerWidgets() {   
super.registerWidgets();
registerFactory(NumericTextFactory.WIDGET_TAG, new NumericTextFactory());
}

}

Esse é o Builder fato. Ele extende o SwingBuilder e tem a sobre-escrita do método registerWidgets esse método registra as factories que tem os widgets personalizados que você venha a construir!

Neste caso por uma questão de boas práticas estou passando uma constante com a tag do widget que no caso tem o valor "caixaNumeros", que sera a tag que você utilizara no groovy.

Agora vamos ao código da factory NumericTextFactory.java
package com.blogspot.diegopacheco.groovy.builder.factories;

import groovy.util.AbstractFactory;
import groovy.util.FactoryBuilderSupport;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JTextField;

/**
* Factory que cria um JLabel com controle de digitação
* que soh deixa digitar numeros.
*
* @author Diego Pacheco
* @since 20/01/2009
* @version 1.0
*
*/
public class NumericTextFactory extends AbstractFactory{

public static String WIDGET_TAG = "caixaNumeros";

@Override
@SuppressWarnings("unchecked")
public Object newInstance(FactoryBuilderSupport builder, Object name,Object value, Map attributes) throws InstantiationException, IllegalAccessException {

JTextField textField = new JTextField((String)attributes.get("text"));
textField.setBackground(Color.YELLOW);       
textField.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
textField.setToolTipText("Digite algum número entre 0 e 9!");

attachEvents(textField);       
return textField;
}

/**
* Metodo que adiciona eventos ao botao
* @param textField
*/
private void attachEvents(JTextField textField){

textField.addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent e){}               
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){
System.out.println(e.getKeyChar());                   
if ( (e.getKeyChar() >=48 && e.getKeyChar()<=57)){                         // numeros validos                     }else{                         e.consume();                     }                                }         });             }     } 
Aqui que as coisas acontecem! Essa classe extende AbstractFactory que é a factory padrão dos builders do Groovy ela já contem os métodos do ciclo de vida do parser do Groovy, assim você tem um conjunto de métodos estilo callback a sua disposição. Nesse caso só foi necessário o uso do método newInstance o qual cria um objeto JTextField e chamo um metodo privado que eu criaei para colocar o tratamento de eventos. O tratamento de evento só deixa que se digite números de 0 a 9. Agora podemos testar o builder em um código Groovy chamei de GroovyUsage.groovy
package com.blogspot.diegopacheco.groovy.builder.usage

import java.awt.*
import javax.swing.*
import groovy.swing.*

import com.blogspot.diegopacheco.groovy.builder.*

/**
* Classe groovy que mostra como usar o builder.
*
* @autor Diego Pacheco
* @since 20/01/2009
* @version 1.0
*
*/
public class GroovyUsage {

def swing = new CustomSwingBuilder()

public void renderMe(){       

def frame = swing.frame(title:'Tela de Teste', size:[300,300]) {
borderLayout()
caixaNumeros(text:"",constraints: BorderLayout.NORTH)
}
frame.show()       
}

public static void main(String []args){
new GroovyUsage().renderMe()       
}

}
Aqui podemos ver que esta sendo usado a tag caixaNumeros(text:"",constraints: BorderLayout.NORTH) e mais nada! Se você rodar esse código ira aparecer uma tela com uma caixa de texto que só permite a digitação de números! Ese exemplo é muito simples! O importante aqui é as possíbilidades que esse recurso do Groovy nos permite dentre as muitas possíbilidades podemos:
  • Criar componentes customizados e usa-los de forma produtiva
  • Colocar controles arquiteturais do tipo segurnça, i18m, etc...
  • Requisitos de usabilidade como cores, posicionamento, fonte, etc...
Dentre outras tantas utilidades, se quizerem os fontes estão disponíveis aqui!

Popular posts from this blog

C Unit Testing with Check

Having fun with Zig Language

HMAC in Java