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

Kafka Streams with Java 15

Rust and Java Interoperability

HMAC in Java